[fusion-commits] r1353 - in sandbox/aboudreault: . MapGuide MapGuide/php MapServer MapServer/php containerinfo docs jx jx/css jx/images jx/lib lib lib/OpenLayers lib/OpenLayers/Strings lib/OpenLayers/img lib/OpenLayers/theme/default lib/OpenLayers/theme/default/img templates templates/mapguide templates/mapguide/standard templates/mapguide/standard/images templates/mapguide/standard/images/icons templates/mapserver templates/mapserver/standard templates/mapserver/standard/images templates/mapserver/standard/images/icons text text/en text/fr widgets widgets/BufferPanel widgets/EditableScale widgets/Help widgets/LayerManager widgets/Maptip widgets/Measure widgets/Navigator widgets/Print widgets/ScalebarDual widgets/Search widgets/SelectWithin widgets/SelectionPanel widgets/TaskPane widgets/scalebar widgets/widgetinfo

svn_fusion at osgeo.org svn_fusion at osgeo.org
Mon Mar 31 10:35:42 EDT 2008


Author: aboudreault
Date: 2008-03-31 10:35:37 -0400 (Mon, 31 Mar 2008)
New Revision: 1353

Added:
   sandbox/aboudreault/MapGuide/MapGuideViewerApi.js
   sandbox/aboudreault/MapServer/php/Search.php
   sandbox/aboudreault/containerinfo/menu.png
   sandbox/aboudreault/containerinfo/splitterbar.png
   sandbox/aboudreault/containerinfo/splitterbar.xml
   sandbox/aboudreault/containerinfo/toolbar.png
   sandbox/aboudreault/jx/
   sandbox/aboudreault/jx/JX_VERSION.txt
   sandbox/aboudreault/jx/css/
   sandbox/aboudreault/jx/css/jxskin-border.css
   sandbox/aboudreault/jx/css/jxskin-graphic.css
   sandbox/aboudreault/jx/css/reset.css
   sandbox/aboudreault/jx/css/tests.css
   sandbox/aboudreault/jx/images/
   sandbox/aboudreault/jx/images/a_pixel.png
   sandbox/aboudreault/jx/images/button_bg.png
   sandbox/aboudreault/jx/images/button_bg_arrow_d2.png
   sandbox/aboudreault/jx/images/button_bg_arrow_r2.png
   sandbox/aboudreault/jx/images/close.png
   sandbox/aboudreault/jx/images/container_bg.png
   sandbox/aboudreault/jx/images/dialog_bg.png
   sandbox/aboudreault/jx/images/dialog_glow_b.png
   sandbox/aboudreault/jx/images/dialog_glow_bl.png
   sandbox/aboudreault/jx/images/dialog_glow_br.png
   sandbox/aboudreault/jx/images/dialog_glow_l.png
   sandbox/aboudreault/jx/images/dialog_glow_r.png
   sandbox/aboudreault/jx/images/dialog_glow_t.png
   sandbox/aboudreault/jx/images/dialog_glow_tl.png
   sandbox/aboudreault/jx/images/dialog_glow_tr.png
   sandbox/aboudreault/jx/images/dialog_resize.png
   sandbox/aboudreault/jx/images/disclose.png
   sandbox/aboudreault/jx/images/disclose2.png
   sandbox/aboudreault/jx/images/disclose3.png
   sandbox/aboudreault/jx/images/grid.png
   sandbox/aboudreault/jx/images/help.png
   sandbox/aboudreault/jx/images/help_close.png
   sandbox/aboudreault/jx/images/icon_close.png
   sandbox/aboudreault/jx/images/icon_quickhelp.png
   sandbox/aboudreault/jx/images/maximize.png
   sandbox/aboudreault/jx/images/menu_item_arrow_d.png
   sandbox/aboudreault/jx/images/menu_item_arrow_d2.png
   sandbox/aboudreault/jx/images/menu_item_arrow_r.png
   sandbox/aboudreault/jx/images/menu_item_arrow_r2.png
   sandbox/aboudreault/jx/images/menu_item_check.png
   sandbox/aboudreault/jx/images/menu_item_radio.png
   sandbox/aboudreault/jx/images/minimize.png
   sandbox/aboudreault/jx/images/page_grid.png
   sandbox/aboudreault/jx/images/panel_grey_bg.png
   sandbox/aboudreault/jx/images/panel_white_bg.png
   sandbox/aboudreault/jx/images/separator.png
   sandbox/aboudreault/jx/images/snap_bg.png
   sandbox/aboudreault/jx/images/tab_bottom_bg.png
   sandbox/aboudreault/jx/images/tab_left_bg.png
   sandbox/aboudreault/jx/images/tab_right_bg.png
   sandbox/aboudreault/jx/images/tab_top_bg.png
   sandbox/aboudreault/jx/images/test-text.png
   sandbox/aboudreault/jx/images/toolbar_separator_h.png
   sandbox/aboudreault/jx/images/toolbar_separator_v.png
   sandbox/aboudreault/jx/images/tree_folder.png
   sandbox/aboudreault/jx/images/tree_folder_open.png
   sandbox/aboudreault/jx/images/tree_last_node.png
   sandbox/aboudreault/jx/images/tree_minus.png
   sandbox/aboudreault/jx/images/tree_node.png
   sandbox/aboudreault/jx/images/tree_none.png
   sandbox/aboudreault/jx/images/tree_page.png
   sandbox/aboudreault/jx/images/tree_plus.png
   sandbox/aboudreault/jx/images/tree_vert_line.png
   sandbox/aboudreault/jx/lib/
   sandbox/aboudreault/jx/lib/jx_combined.css
   sandbox/aboudreault/jx/lib/jx_combined.js
   sandbox/aboudreault/jx/lib/jx_compressed.js
   sandbox/aboudreault/lib/OpenLayers/Strings/
   sandbox/aboudreault/lib/OpenLayers/Strings/en.js
   sandbox/aboudreault/lib/OpenLayers/Strings/fr.js
   sandbox/aboudreault/templates/
   sandbox/aboudreault/templates/mapguide/
   sandbox/aboudreault/templates/mapguide/standard/
   sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml
   sandbox/aboudreault/templates/mapguide/standard/images/
   sandbox/aboudreault/templates/mapguide/standard/images/a_pixel.png
   sandbox/aboudreault/templates/mapguide/standard/images/grab.cur
   sandbox/aboudreault/templates/mapguide/standard/images/grabbing.cur
   sandbox/aboudreault/templates/mapguide/standard/images/icons/
   sandbox/aboudreault/templates/mapguide/standard/images/icons/buffer.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-copy.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-cut.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-duplicate.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-paste.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-redo.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-undo.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-open.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-print.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-save.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/help.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-layer.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-map.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-raster.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-theme.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/measure.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/move-down.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/move-up.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/navigator.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-east.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-north.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-south.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/search.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-attribute.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-centre.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-clear.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-features.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-polygon.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-query.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-radius.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-rectangle.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-zoom.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-back.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-forward.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-refresh.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/warning.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/west.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-full.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in-fixed.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out-fixed.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out.png
   sandbox/aboudreault/templates/mapguide/standard/index.html
   sandbox/aboudreault/templates/mapserver/
   sandbox/aboudreault/templates/mapserver/standard/
   sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml
   sandbox/aboudreault/templates/mapserver/standard/images/
   sandbox/aboudreault/templates/mapserver/standard/images/PoweredBy_en.gif
   sandbox/aboudreault/templates/mapserver/standard/images/Thumbs.db
   sandbox/aboudreault/templates/mapserver/standard/images/a_pixel.png
   sandbox/aboudreault/templates/mapserver/standard/images/grab.cur
   sandbox/aboudreault/templates/mapserver/standard/images/grabbing.cur
   sandbox/aboudreault/templates/mapserver/standard/images/icon_back.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_forward.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_home.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl_disabled.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_loading.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_tasks.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icons/
   sandbox/aboudreault/templates/mapserver/standard/images/icons/Thumbs.db
   sandbox/aboudreault/templates/mapserver/standard/images/icons/buffer.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-copy.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-cut.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-duplicate.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-paste.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-redo.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-undo.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-open.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-print.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-save.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/help.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-layer.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-map.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-raster.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-theme.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/measure.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/move-down.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/move-up.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/navigator.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-east.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-north.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-south.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/search.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-attribute.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-centre.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-clear.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-features.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-polygon.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-query.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-radius.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-rectangle.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-zoom.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-back.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-forward.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-refresh.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/warning.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/west.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-full.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in-fixed.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out-fixed.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out.png
   sandbox/aboudreault/templates/mapserver/standard/images/zoomin.cur
   sandbox/aboudreault/templates/mapserver/standard/images/zoomout.cur
   sandbox/aboudreault/templates/mapserver/standard/index.html
   sandbox/aboudreault/text/
   sandbox/aboudreault/text/en/
   sandbox/aboudreault/text/en/strings.json
   sandbox/aboudreault/text/en/strings.php
   sandbox/aboudreault/text/fr/
   sandbox/aboudreault/text/fr/strings.json
   sandbox/aboudreault/text/fr/strings.php
   sandbox/aboudreault/widgets/MSSearch.js
   sandbox/aboudreault/widgets/Maptip/
   sandbox/aboudreault/widgets/Maptip/Maptip.css
   sandbox/aboudreault/widgets/ScalebarDual.js
   sandbox/aboudreault/widgets/ScalebarDual/
   sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css
Removed:
   sandbox/aboudreault/MapServer/php/Search.php
   sandbox/aboudreault/containerinfo/menu.gif
   sandbox/aboudreault/containerinfo/toolbar.gif
   sandbox/aboudreault/jx/JX_VERSION.txt
   sandbox/aboudreault/jx/css/
   sandbox/aboudreault/jx/css/jxskin-border.css
   sandbox/aboudreault/jx/css/jxskin-graphic.css
   sandbox/aboudreault/jx/css/reset.css
   sandbox/aboudreault/jx/css/tests.css
   sandbox/aboudreault/jx/images/
   sandbox/aboudreault/jx/images/a_pixel.png
   sandbox/aboudreault/jx/images/button_bg.png
   sandbox/aboudreault/jx/images/button_bg_arrow_d2.png
   sandbox/aboudreault/jx/images/button_bg_arrow_r2.png
   sandbox/aboudreault/jx/images/close.png
   sandbox/aboudreault/jx/images/container_bg.png
   sandbox/aboudreault/jx/images/dialog_bg.png
   sandbox/aboudreault/jx/images/dialog_glow_b.png
   sandbox/aboudreault/jx/images/dialog_glow_bl.png
   sandbox/aboudreault/jx/images/dialog_glow_br.png
   sandbox/aboudreault/jx/images/dialog_glow_l.png
   sandbox/aboudreault/jx/images/dialog_glow_r.png
   sandbox/aboudreault/jx/images/dialog_glow_t.png
   sandbox/aboudreault/jx/images/dialog_glow_tl.png
   sandbox/aboudreault/jx/images/dialog_glow_tr.png
   sandbox/aboudreault/jx/images/dialog_resize.png
   sandbox/aboudreault/jx/images/disclose.png
   sandbox/aboudreault/jx/images/disclose2.png
   sandbox/aboudreault/jx/images/disclose3.png
   sandbox/aboudreault/jx/images/grid.png
   sandbox/aboudreault/jx/images/help.png
   sandbox/aboudreault/jx/images/help_close.png
   sandbox/aboudreault/jx/images/icon_close.png
   sandbox/aboudreault/jx/images/icon_quickhelp.png
   sandbox/aboudreault/jx/images/maximize.png
   sandbox/aboudreault/jx/images/menu_item_arrow_d.png
   sandbox/aboudreault/jx/images/menu_item_arrow_d2.png
   sandbox/aboudreault/jx/images/menu_item_arrow_r.png
   sandbox/aboudreault/jx/images/menu_item_arrow_r2.png
   sandbox/aboudreault/jx/images/menu_item_check.png
   sandbox/aboudreault/jx/images/menu_item_radio.png
   sandbox/aboudreault/jx/images/minimize.png
   sandbox/aboudreault/jx/images/page_grid.png
   sandbox/aboudreault/jx/images/panel_grey_bg.png
   sandbox/aboudreault/jx/images/panel_white_bg.png
   sandbox/aboudreault/jx/images/separator.png
   sandbox/aboudreault/jx/images/snap_bg.png
   sandbox/aboudreault/jx/images/tab_bottom_bg.png
   sandbox/aboudreault/jx/images/tab_left_bg.png
   sandbox/aboudreault/jx/images/tab_right_bg.png
   sandbox/aboudreault/jx/images/tab_top_bg.png
   sandbox/aboudreault/jx/images/test-text.png
   sandbox/aboudreault/jx/images/toolbar_separator_h.png
   sandbox/aboudreault/jx/images/toolbar_separator_v.png
   sandbox/aboudreault/jx/images/tree_folder.png
   sandbox/aboudreault/jx/images/tree_folder_open.png
   sandbox/aboudreault/jx/images/tree_last_node.png
   sandbox/aboudreault/jx/images/tree_minus.png
   sandbox/aboudreault/jx/images/tree_node.png
   sandbox/aboudreault/jx/images/tree_none.png
   sandbox/aboudreault/jx/images/tree_page.png
   sandbox/aboudreault/jx/images/tree_plus.png
   sandbox/aboudreault/jx/images/tree_vert_line.png
   sandbox/aboudreault/jx/lib/
   sandbox/aboudreault/jx/lib/jx_combined.css
   sandbox/aboudreault/jx/lib/jx_combined.js
   sandbox/aboudreault/jx/lib/jx_compressed.js
   sandbox/aboudreault/lib/OpenLayers/Strings/en.js
   sandbox/aboudreault/lib/OpenLayers/Strings/fr.js
   sandbox/aboudreault/templates/mapguide/
   sandbox/aboudreault/templates/mapguide/standard/
   sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml
   sandbox/aboudreault/templates/mapguide/standard/images/
   sandbox/aboudreault/templates/mapguide/standard/images/a_pixel.png
   sandbox/aboudreault/templates/mapguide/standard/images/grab.cur
   sandbox/aboudreault/templates/mapguide/standard/images/grabbing.cur
   sandbox/aboudreault/templates/mapguide/standard/images/icons/
   sandbox/aboudreault/templates/mapguide/standard/images/icons/buffer.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-copy.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-cut.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-duplicate.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-paste.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-redo.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-undo.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-open.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-print.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/file-save.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/help.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-layer.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-map.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-raster.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-theme.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/measure.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/move-down.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/move-up.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/navigator.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-east.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-north.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-south.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/pan.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/search.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-attribute.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-centre.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-clear.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-features.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-polygon.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-query.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-radius.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-rectangle.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select-zoom.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/select.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-back.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-forward.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/view-refresh.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/warning.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/west.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-full.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in-fixed.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out-fixed.png
   sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out.png
   sandbox/aboudreault/templates/mapguide/standard/index.html
   sandbox/aboudreault/templates/mapserver/
   sandbox/aboudreault/templates/mapserver/standard/
   sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml
   sandbox/aboudreault/templates/mapserver/standard/images/
   sandbox/aboudreault/templates/mapserver/standard/images/PoweredBy_en.gif
   sandbox/aboudreault/templates/mapserver/standard/images/Thumbs.db
   sandbox/aboudreault/templates/mapserver/standard/images/a_pixel.png
   sandbox/aboudreault/templates/mapserver/standard/images/grab.cur
   sandbox/aboudreault/templates/mapserver/standard/images/grabbing.cur
   sandbox/aboudreault/templates/mapserver/standard/images/icon_back.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_forward.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_home.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl_disabled.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_loading.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icon_tasks.gif
   sandbox/aboudreault/templates/mapserver/standard/images/icons/
   sandbox/aboudreault/templates/mapserver/standard/images/icons/Thumbs.db
   sandbox/aboudreault/templates/mapserver/standard/images/icons/buffer.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-copy.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-cut.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-duplicate.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-paste.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-redo.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-undo.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-open.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-print.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/file-save.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/help.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-layer.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-map.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-raster.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-theme.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/measure.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/move-down.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/move-up.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/navigator.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-east.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-north.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-south.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/pan.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/search.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-attribute.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-centre.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-clear.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-features.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-polygon.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-query.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-radius.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-rectangle.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select-zoom.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/select.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-back.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-forward.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/view-refresh.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/warning.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/west.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-full.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in-fixed.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out-fixed.png
   sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out.png
   sandbox/aboudreault/templates/mapserver/standard/images/zoomin.cur
   sandbox/aboudreault/templates/mapserver/standard/images/zoomout.cur
   sandbox/aboudreault/templates/mapserver/standard/index.html
   sandbox/aboudreault/text/en/
   sandbox/aboudreault/text/en/strings.json
   sandbox/aboudreault/text/en/strings.php
   sandbox/aboudreault/text/fr/
   sandbox/aboudreault/text/fr/strings.json
   sandbox/aboudreault/text/fr/strings.php
   sandbox/aboudreault/widgets/MSSearch.js
   sandbox/aboudreault/widgets/Maptip/Maptip.css
   sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css
Modified:
   sandbox/aboudreault/BUILDING.TXT
   sandbox/aboudreault/LICENSE.TXT
   sandbox/aboudreault/MapGuide/MapGuide.js
   sandbox/aboudreault/MapGuide/php/Buffer.php
   sandbox/aboudreault/MapGuide/php/Common.php
   sandbox/aboudreault/MapGuide/php/Constants.php
   sandbox/aboudreault/MapGuide/php/LoadMap.php
   sandbox/aboudreault/MapGuide/php/Measure.php
   sandbox/aboudreault/MapGuide/php/Query.php
   sandbox/aboudreault/MapGuide/php/SaveMapFrame.php
   sandbox/aboudreault/MapGuide/php/SetLayers.php
   sandbox/aboudreault/MapGuide/php/SetSelection.php
   sandbox/aboudreault/MapGuide/php/UserManager.php
   sandbox/aboudreault/MapGuide/php/Utilities.php
   sandbox/aboudreault/MapServer/MapServer.js
   sandbox/aboudreault/MapServer/php/LegendIcon.php
   sandbox/aboudreault/MapServer/php/LoadMap.php
   sandbox/aboudreault/MapServer/php/Measure.php
   sandbox/aboudreault/MapServer/php/Query.php
   sandbox/aboudreault/MapServer/php/SetLayers.php
   sandbox/aboudreault/build.xml
   sandbox/aboudreault/config.json
   sandbox/aboudreault/containerinfo/contextmenu.xml
   sandbox/aboudreault/containerinfo/toolbar.xml
   sandbox/aboudreault/docs/ApplicationDefinition-1.0.0.xsd
   sandbox/aboudreault/docs/ApplicationDefinition.xml
   sandbox/aboudreault/fusion.cfg
   sandbox/aboudreault/lib/ApplicationDefinition.js
   sandbox/aboudreault/lib/ButtonBase.js
   sandbox/aboudreault/lib/CanvasTool.js
   sandbox/aboudreault/lib/Error.js
   sandbox/aboudreault/lib/Map.js
   sandbox/aboudreault/lib/MenuBase.js
   sandbox/aboudreault/lib/OpenLayers/OpenLayers.js
   sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js
   sandbox/aboudreault/lib/OpenLayers/img/blank.gif
   sandbox/aboudreault/lib/OpenLayers/img/close.gif
   sandbox/aboudreault/lib/OpenLayers/img/drag-rectangle-off.png
   sandbox/aboudreault/lib/OpenLayers/img/drag-rectangle-on.png
   sandbox/aboudreault/lib/OpenLayers/img/east-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/layer-switcher-maximize.png
   sandbox/aboudreault/lib/OpenLayers/img/layer-switcher-minimize.png
   sandbox/aboudreault/lib/OpenLayers/img/marker-blue.png
   sandbox/aboudreault/lib/OpenLayers/img/marker-gold.png
   sandbox/aboudreault/lib/OpenLayers/img/marker-green.png
   sandbox/aboudreault/lib/OpenLayers/img/marker.png
   sandbox/aboudreault/lib/OpenLayers/img/measuring-stick-off.png
   sandbox/aboudreault/lib/OpenLayers/img/measuring-stick-on.png
   sandbox/aboudreault/lib/OpenLayers/img/north-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/panning-hand-off.png
   sandbox/aboudreault/lib/OpenLayers/img/panning-hand-on.png
   sandbox/aboudreault/lib/OpenLayers/img/slider.png
   sandbox/aboudreault/lib/OpenLayers/img/south-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/west-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/zoom-minus-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/zoom-plus-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/zoom-world-mini.png
   sandbox/aboudreault/lib/OpenLayers/img/zoombar.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/add_point_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/add_point_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/drag-rectangle-off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/drag-rectangle-on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_line_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_line_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_point_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_point_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_polygon_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_polygon_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/move_feature_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/move_feature_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/pan_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/pan_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/panning-hand-off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/panning-hand-on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/remove_point_off.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/img/remove_point_on.png
   sandbox/aboudreault/lib/OpenLayers/theme/default/style.css
   sandbox/aboudreault/lib/fusion.js
   sandbox/aboudreault/widgets/About.js
   sandbox/aboudreault/widgets/ActivityIndicator.js
   sandbox/aboudreault/widgets/Buffer.js
   sandbox/aboudreault/widgets/BufferPanel.js
   sandbox/aboudreault/widgets/BufferPanel/AreaLayerDef.templ
   sandbox/aboudreault/widgets/BufferPanel/Buffer.php
   sandbox/aboudreault/widgets/BufferPanel/BufferPanel.php
   sandbox/aboudreault/widgets/BufferPanel/BufferPanel.templ
   sandbox/aboudreault/widgets/BufferPanel/BufferReport.templ
   sandbox/aboudreault/widgets/BufferPanel/ColorPicker.php
   sandbox/aboudreault/widgets/BufferPanel/ColorPicker.templ
   sandbox/aboudreault/widgets/BufferPanel/ErrorPage.templ
   sandbox/aboudreault/widgets/BufferPanel/Viewer.css
   sandbox/aboudreault/widgets/CTRLClick.js
   sandbox/aboudreault/widgets/CursorPosition.js
   sandbox/aboudreault/widgets/EditableScale.js
   sandbox/aboudreault/widgets/EditableScale/EditableScale.css
   sandbox/aboudreault/widgets/ExtentHistory.js
   sandbox/aboudreault/widgets/Help.js
   sandbox/aboudreault/widgets/Help/Help.html
   sandbox/aboudreault/widgets/InitialMapView.js
   sandbox/aboudreault/widgets/InvokeURL.js
   sandbox/aboudreault/widgets/LayerManager.js
   sandbox/aboudreault/widgets/LayerManager/LayerManager.css
   sandbox/aboudreault/widgets/Legend.js
   sandbox/aboudreault/widgets/LinkToView.js
   sandbox/aboudreault/widgets/MapMenu.js
   sandbox/aboudreault/widgets/Maptip.js
   sandbox/aboudreault/widgets/Measure.js
   sandbox/aboudreault/widgets/Measure/Measure.css
   sandbox/aboudreault/widgets/Measure/Measure.php
   sandbox/aboudreault/widgets/Measure/MeasurePending.gif
   sandbox/aboudreault/widgets/Navigator.js
   sandbox/aboudreault/widgets/Navigator/slider.png
   sandbox/aboudreault/widgets/Navigator/sliderscale.png
   sandbox/aboudreault/widgets/Navigator/spinner.gif
   sandbox/aboudreault/widgets/Pan.js
   sandbox/aboudreault/widgets/Print.js
   sandbox/aboudreault/widgets/Print/Print.css
   sandbox/aboudreault/widgets/Print/pr_north.gif
   sandbox/aboudreault/widgets/Print/printablepage.php
   sandbox/aboudreault/widgets/Print/printablepage.templ
   sandbox/aboudreault/widgets/RefreshMap.js
   sandbox/aboudreault/widgets/SaveMap.js
   sandbox/aboudreault/widgets/Search.js
   sandbox/aboudreault/widgets/Search/ErrorPage.templ
   sandbox/aboudreault/widgets/Search/Search.php
   sandbox/aboudreault/widgets/Search/Search.templ
   sandbox/aboudreault/widgets/Search/SearchPrompt.php
   sandbox/aboudreault/widgets/Search/SearchPrompt.templ
   sandbox/aboudreault/widgets/Search/Viewer.css
   sandbox/aboudreault/widgets/Select.js
   sandbox/aboudreault/widgets/SelectRadius.js
   sandbox/aboudreault/widgets/SelectWithin.js
   sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php
   sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.php
   sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ
   sandbox/aboudreault/widgets/SelectWithin/Viewer.css
   sandbox/aboudreault/widgets/SelectionInfo.js
   sandbox/aboudreault/widgets/SelectionPanel.js
   sandbox/aboudreault/widgets/SelectionPanel/SelectionPanel.css
   sandbox/aboudreault/widgets/TaskPane.js
   sandbox/aboudreault/widgets/TaskPane/TaskPane.css
   sandbox/aboudreault/widgets/TaskPane/TaskPane.html
   sandbox/aboudreault/widgets/ViewOptions.js
   sandbox/aboudreault/widgets/ViewSize.js
   sandbox/aboudreault/widgets/Zoom.js
   sandbox/aboudreault/widgets/scalebar/fancy-bar-alt.gif
   sandbox/aboudreault/widgets/scalebar/fancy-bar.gif
   sandbox/aboudreault/widgets/widgetinfo/WidgetInfoTemplate.xml
   sandbox/aboudreault/widgets/widgetinfo/about.xml
   sandbox/aboudreault/widgets/widgetinfo/activityindicator.xml
   sandbox/aboudreault/widgets/widgetinfo/buffer.xml
   sandbox/aboudreault/widgets/widgetinfo/bufferpanel.xml
   sandbox/aboudreault/widgets/widgetinfo/centerselection.xml
   sandbox/aboudreault/widgets/widgetinfo/clearselection.xml
   sandbox/aboudreault/widgets/widgetinfo/colorpicker.xml
   sandbox/aboudreault/widgets/widgetinfo/ctrlclick.xml
   sandbox/aboudreault/widgets/widgetinfo/cursorposition.xml
   sandbox/aboudreault/widgets/widgetinfo/editablescale.xml
   sandbox/aboudreault/widgets/widgetinfo/extenthistory.xml
   sandbox/aboudreault/widgets/widgetinfo/help.xml
   sandbox/aboudreault/widgets/widgetinfo/initialmapview.xml
   sandbox/aboudreault/widgets/widgetinfo/invokescript.xml
   sandbox/aboudreault/widgets/widgetinfo/invokeurl.xml
   sandbox/aboudreault/widgets/widgetinfo/legend.xml
   sandbox/aboudreault/widgets/widgetinfo/linktoview.xml
   sandbox/aboudreault/widgets/widgetinfo/mapmenu.xml
   sandbox/aboudreault/widgets/widgetinfo/maptip.xml
   sandbox/aboudreault/widgets/widgetinfo/measure.xml
   sandbox/aboudreault/widgets/widgetinfo/navigator.xml
   sandbox/aboudreault/widgets/widgetinfo/overviewmap.xml
   sandbox/aboudreault/widgets/widgetinfo/pan.xml
   sandbox/aboudreault/widgets/widgetinfo/panonclick.xml
   sandbox/aboudreault/widgets/widgetinfo/panquery.xml
   sandbox/aboudreault/widgets/widgetinfo/print.xml
   sandbox/aboudreault/widgets/widgetinfo/refreshmap.xml
   sandbox/aboudreault/widgets/widgetinfo/savemap.xml
   sandbox/aboudreault/widgets/widgetinfo/scalebar.xml
   sandbox/aboudreault/widgets/widgetinfo/search.xml
   sandbox/aboudreault/widgets/widgetinfo/select.xml
   sandbox/aboudreault/widgets/widgetinfo/selectioninfo.xml
   sandbox/aboudreault/widgets/widgetinfo/selectionpanel.xml
   sandbox/aboudreault/widgets/widgetinfo/selectpolygon.xml
   sandbox/aboudreault/widgets/widgetinfo/selectradius.xml
   sandbox/aboudreault/widgets/widgetinfo/selectradiusvalue.xml
   sandbox/aboudreault/widgets/widgetinfo/selectwithin.xml
   sandbox/aboudreault/widgets/widgetinfo/taskpane.xml
   sandbox/aboudreault/widgets/widgetinfo/viewoptions.xml
   sandbox/aboudreault/widgets/widgetinfo/viewsize.xml
   sandbox/aboudreault/widgets/widgetinfo/zoom.xml
   sandbox/aboudreault/widgets/widgetinfo/zoomonclick.xml
   sandbox/aboudreault/widgets/widgetinfo/zoomtoselection.xml
Log:
Merged trunk changes into aboudreault sandbox


Property changes on: sandbox/aboudreault/BUILDING.TXT
___________________________________________________________________
Name: svn:keywords
   - Date Revision Author HeadURL Id
   + Author Date Id Revision

Modified: sandbox/aboudreault/LICENSE.TXT
===================================================================
--- sandbox/aboudreault/LICENSE.TXT	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/LICENSE.TXT	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * FUSION
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/LICENSE.TXT
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapGuide/MapGuide.js
===================================================================
--- sandbox/aboudreault/MapGuide/MapGuide.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/MapGuide.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -67,11 +67,27 @@
         if (isMapWidgetLayer != null) {
             this.bIsMapWidgetLayer = isMapWidgetLayer;
         }
-        
+        this.mapInfo = mapTag.mapInfo;
         var extension = mapTag.extension; //TBD: this belongs in layer tag?
         this.selectionType = extension.SelectionType ? extension.SelectionType[0] : 'INTERSECTS';
         this.ratio = extension.MapRatio ? extension.MapRatio[0] : 1.0;
         
+        //add in the handler for CTRL-click actions for the map, not an overviewmap
+        if (this.bIsMapWidgetLayer) {
+          var ctrlClickEnabled = true;
+          if (extension.DisableCtrlClick && extension.DisableCtrlClick[0] == 'true') {
+              ctrlClickEnabled = false;
+          }
+          if (ctrlClickEnabled) {
+            this.map = this.mapWidget.oMapOL;
+            this.handler = new OpenLayers.Handler.Click(this,
+                                  {click: this.mouseUpCRTLClick.bind(this)},
+                                  {keyMask: OpenLayers.Handler.MOD_CTRL});
+            this.handler.activate();
+            this.nTolerance = 2; //pixels, default pixel tolernace for a point click; TBD make this configurable
+          }
+        }
+       
         this.sMapResourceId = mapTag.resourceId ? mapTag.resourceId : '';
         
         rootOpts = {
@@ -87,7 +103,7 @@
 
         this.keepAliveInterval = parseInt(extension.KeepAliveInterval ? extension.KeepAliveInterval[0] : 300);
         
-        var sid = Fusion.getQueryParam("session");
+        var sid = Fusion.sessionId;
         if (sid) {
             this.session[0] = sid;
             this.mapSessionCreated();
@@ -142,6 +158,10 @@
         return this._sMapname;
     },
     
+    getMapTitle: function() {
+        return this._sMapTitle;
+    },
+    
     loadMap: function(resourceId, options) {
         this.bMapLoaded = false;
 
@@ -261,9 +281,6 @@
               }
             }
 
-            //TODO: get this from the layerTag.extension
-            //this.oMapInfo = Fusion.oConfigMgr.getMapInfo(this._sResourceId);
-
             //set projection units and code if supplied
             //TODO: consider passing the metersPerUnit value into the framework
             //to allow for scaling that doesn't match any of the pre-canned units
@@ -300,7 +317,7 @@
             this.bMapLoaded = true;
         } else {
             Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL, 
-                        'Failed to load requested map:\n'+r.responseText));
+                OpenLayers.String.translate('mapLoadError', r.responseText)));
         }
         this.mapWidget._removeWorker();
     },
@@ -332,6 +349,7 @@
         this.aHideGroups = [];
         this.aRefreshLayers = [];
         this.layerRoot.clear();
+        this.oldLayers = this.aLayers.clone();
         this.aLayers = [];
         
         var sl = Fusion.getScriptLanguage();
@@ -344,11 +362,13 @@
                       onException: this.reloadFailed.bind(this),
                       parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
+        
+        
     },
 
     reloadFailed: function(r) {
       Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL, 
-                      'Failed to reload requested map:\n'+r.transport.responseText));
+        OpenLayers.String.translate('mapLoadError', r.transport.responseText)));
       this.mapWidget._removeWorker();
     },
 
@@ -358,11 +378,21 @@
             var o;
             eval('o='+r.responseText);
             this.parseMapLayersAndGroups(o);
+            for (var i=0; i<this.aLayers.length; ++i) {
+              var newLayer = this.aLayers[i];
+              for (var j=0; j<this.oldLayers.length; ++j){
+                if (this.oldLayers[j].uniqueId == newLayer.uniqueId) {
+                  newLayer.selectedFeatureCount = this.oldLayers[j].selectedFeatureCount;
+                  break;
+                }
+              }
+            }
+            this.oldLayers = null;
             this.mapWidget.triggerEvent(Fusion.Event.MAP_RELOADED);
             this.drawMap();
         } else {
             Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL, 
-                            'Failed to load requested map:\n'+r.responseText));
+                OpenLayers.String.translate('mapLoadError', r.responseText)));
         }
         this.mapWidget._removeWorker();
     },
@@ -399,7 +429,7 @@
                 this.drawMap();
                 this.triggerEvent(Fusion.Event.MAP_LAYER_ORDER_CHANGED);
             } else {
-                alert("setLayers failure:"+o.layerindex);
+                alert(OpenLayers.String.translate('setLayersError', o.layerindex));
             }
         }
     },
@@ -502,6 +532,25 @@
     },
             
     /**
+     * Function: getLayerByName
+     * 
+     * Returns the MapGuide layer object as identified by the layer name
+     */
+    getLayerByName : function(name)
+    {
+        var oLayer = null;
+        for (var i=0; i<this.aLayers.length; i++)
+        {
+            if (this.aLayers[i].layerName == name)
+            {
+                oLayer = this.aLayers[i];
+                break;
+            }
+        }
+        return oLayer;
+    },
+
+    /**
      * Function: isMapLoaded
      * 
      * Returns true if the Map has been laoded succesfully form the server
@@ -578,12 +627,7 @@
       *
       * sets a Selection XML back to the server
       */
-    zoomToSelection: function(r) {
-      var xmlDoc = r.responseXML.documentElement;
-      var x = xmlDoc.getElementsByTagName('X');
-      var y = xmlDoc.getElementsByTagName('Y');
-      //double the veiwport
-      var extent = new OpenLayers.Bounds(x[0].firstChild.nodeValue,y[0].firstChild.nodeValue,x[1].firstChild.nodeValue,y[1].firstChild.nodeValue);
+    zoomToSelection: function(extent) {
       var center = extent.getCenterPixel();
       var size = extent.getSize();
       extent.left = center.x - 2*size.w;
@@ -593,28 +637,14 @@
       this.mapWidget.setExtents(extent);
     },  
 
-    processSelection: function(sel, requery, zoomTo, json) {
-      if (requery) {
-        //xmlDoc = (new DOMParser()).parseFromString(r.responseXML, "text/xml");
-        //this.processFeatureInfo(xmlDoc.documentElement, false, 1);
-        //this.processFeatureInfo(xmlOut, false, 2);
-      }
-      if (zoomTo) {
-        var mgRequest = new Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope(this.getSessionID(), this.getMapName(), sel );
-        Fusion.oBroker.dispatchRequest(mgRequest, this.zoomToSelection.bind(this));
-      } else {
-        this.mapWidget.redraw();
-      }
-    },
-
-    setSelection: function (selText, requery, zoomTo) {
+    setSelection: function (selText, zoomTo) {
+      this.mapWidget._addWorker();
       var sl = Fusion.getScriptLanguage();
       var setSelectionScript = this.arch + '/' + sl  + '/SetSelection.' + sl;
       var params = 'mapname='+this.getMapName()+"&session="+this.getSessionID();
       params += '&selection=' + encodeURIComponent(selText);
-      params += '&queryinfo=' + (requery? "1": "0");
       params += '&seq=' + Math.random();
-      var options = {onSuccess: this.processSelection.bind(this, selText, requery, zoomTo), parameters:params, asynchronous:false};
+      var options = {onSuccess: this.processQueryResults.bind(this, zoomTo), parameters:params, asynchronous:false};
       Fusion.ajaxRequest(setSelectionScript, options);
     },
 
@@ -701,7 +731,7 @@
     /**
        Call back function when slect functions are called (eg queryRect)
     */
-    processQueryResults : function(r) {
+    processQueryResults : function(zoomTo, r) {
         this.mapWidget._removeWorker();
         if (r.responseText) {   //TODO: make the equivalent change to MapServer.js
             var oNode;
@@ -727,9 +757,15 @@
                   }
                 }
               }
+              
+              if (zoomTo) {
+                var ext = oNode.extents
+                var extents = new OpenLayers.Bounds(ext.minx, ext.miny, ext.maxx, ext.maxy);
+                this.zoomToSelection(extents);
+              }
               this.newSelection();
             } else {
-              //this.drawMap();
+              this.clearSelection();
               return;
             }
         }
@@ -754,67 +790,115 @@
         var layers = options.layers || '';
         var extend = options.extendSelection ? '&extendselection=true' : '';
         var computed = options.computedProperties ? '&computed=true' : '';
+        var zoomTo = options.zoomTo ?  true : false;
         var sl = Fusion.getScriptLanguage();
         var loadmapScript = this.arch + '/' + sl  + '/Query.' + sl;
 
         var sessionid = this.getSessionID();
 
         var params = 'mapname='+this._sMapname+"&session="+sessionid+'&spatialfilter='+geometry+'&maxfeatures='+maxFeatures+filter+'&layers='+layers+'&variant='+selectionType+extend+computed;
-        var options = {onSuccess: this.processQueryResults.bind(this), 
+        var options = {onSuccess: this.processQueryResults.bind(this, zoomTo), 
                                      parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
     },
     
-    showLayer: function( layer ) {
-        if (this.oMapInfo && this.oMapInfo.layerEvents[layer.layerName]) {
-            var layerEvent = this.oMapInfo.layerEvents[layer.layerName];
-            for (var i=0; i<layerEvent.onEnable.length; i++) {
-                var l = this.layerRoot.findLayer(layerEvent.onEnable[i].name);
-                if (l) {
-                    if (layerEvent.onEnable[i].enable) {
-                        l.show();
-                    } else {
-                        l.hide();
+    processLayerEvents: function(layer, isEnabling) {
+        if (this.mapInfo && this.mapInfo.mapEvents.layerEvents[layer.layerName]) {
+            var layerEvent = this.mapInfo.mapEvents.layerEvents[layer.layerName];
+            var events = isEnabling ? layerEvent.onEnable : layerEvent.onDisable;
+            for (var i=0; i<events.length; i++) {
+                var o = events[i];
+                if (o.type == 'layer') {
+                    var l = this.layerRoot.findLayer(o.name);
+                    if (l) {
+                        if (o.enable) {
+                            l.show(true);
+                        } else {
+                            l.hide(true);
+                        }
                     }
+                    
+                } else if (o.type == 'group') {
+                    var g = this.layerRoot.findGroupByAttribute('groupName', o.name);
+                    if (g) {
+                        if (o.enable) {
+                            g.show(true);
+                        } else {
+                            g.hide(true);
+                        }
+                    }
                 }
             }
         }
-        this.aShowLayers.push(layer.uniqueId);
-        this.drawMap();
     },
     
-    hideLayer: function( layer ) {
-        if (this.oMapInfo && this.oMapInfo.layerEvents[layer.layerName]) {
-            var layerEvent = this.oMapInfo.layerEvents[layer.layerName];
-            for (var i=0; i<layerEvent.onDisable.length; i++) {
-                var l = this.layerRoot.findLayer(layerEvent.onDisable[i].name);
-                if (l) {
-                    if (layerEvent.onDisable[i].enable) {
-                        l.show();
-                    } else {
-                        l.hide();
+    processGroupEvents: function(group, isEnabling) {
+        if (this.mapInfo && this.mapInfo.mapEvents.groupEvents[group.groupName]) {
+            var groupEvent = this.mapInfo.mapEvents.groupEvents[group.groupName];
+            var events = isEnabling ? groupEvent.onEnable : groupEvent.onDisable;
+            for (var i=0; i<events.length; i++) {
+                var o = events[i];
+                if (o.type == 'layer') {
+                    var l = this.layerRoot.findLayer(o.name);
+                    if (l) {
+                        if (o.enable) {
+                            l.show(true);
+                        } else {
+                            l.hide(true);
+                        }
                     }
+                    
+                } else if (o.type == 'group') {
+                    var g = this.layerRoot.findGroupByAttribute('groupName', o.name);
+                    if (g) {
+                        if (o.enable) {
+                            g.show(true);
+                        } else {
+                            g.hide(true);
+                        }
+                    }
                 }
             }
-        }        
+        }
+    },
+        
+    showLayer: function( layer, noDraw ) {
+        this.processLayerEvents(layer, true);
+        this.aShowLayers.push(layer.uniqueId);
+        if (!noDraw) {
+            this.drawMap();
+        }
+    },
+    
+    hideLayer: function( layer, noDraw ) {
+        this.processLayerEvents(layer, false);
         this.aHideLayers.push(layer.uniqueId);
-        this.drawMap();
+        if (!noDraw) {
+            this.drawMap();
+        }
     },
-    showGroup: function( group ) {
-      if (group.groupName == 'layerRoot') {
-        this.oLayerOL.setVisibility(true);
-      } else {
-        this.aShowGroups.push(group.uniqueId);
-        this.drawMap();
-      }
+    
+    showGroup: function( group, noDraw ) {
+        this.processGroupEvents(group, true);
+        if (group.groupName == 'layerRoot') {
+            this.oLayerOL.setVisibility(true);
+        } else {
+            this.aShowGroups.push(group.uniqueId);
+            if (!noDraw) {
+                this.drawMap();
+            }
+        }
     },
-    hideGroup: function( group ) {
-      if (group.groupName == 'layerRoot') {
-        this.oLayerOL.setVisibility(false);
-      } else {
-        this.aHideGroups.push(group.uniqueId);
-        this.drawMap();
-      }
+    hideGroup: function( group, noDraw ) {
+        this.processGroupEvents(group, false);
+        if (group.groupName == 'layerRoot') {
+            this.oLayerOL.setVisibility(false);
+        } else {
+            this.aHideGroups.push(group.uniqueId);
+            if (!noDraw) {
+                this.drawMap();
+            }
+        }
     },
     refreshLayer: function( layer ) {
         this.aRefreshLayers.push(layer.uniqueId);        
@@ -834,11 +918,77 @@
         this.mapWidget._removeWorker();
     },
     
+  /**
+     * called when there is a click on the map holding the CTRL key: query features at that postion.
+     **/
+    mouseUpCRTLClick: function(evt) {
+      if (evt.ctrlKey) {
+        var min = this.mapWidget.pixToGeo(evt.xy.x-this.nTolerance, evt.xy.y-this.nTolerance);
+        var max = this.mapWidget.pixToGeo(evt.xy.x+this.nTolerance, evt.xy.y+this.nTolerance);
+        if (!min) {
+          return;
+        }   
+        var sGeometry = 'POLYGON(('+ min.x + ' ' +  min.y + ', ' +  min.x + ' ' +  max.y + ', ' + max.x + ' ' +  max.y + ', ' + max.x + ' ' +  min.y + ', ' + min.x + ' ' +  min.y + '))';
+        //var sGeometry = 'POINT('+ min.x + ' ' +  min.y + ')';
+
+        var maxFeatures = 1;
+        var persist = 0;
+        var selection = 'INTERSECTS';
+        var layerNames = '';
+        var sep = '';
+        for (var i=0; i<this.aLayers.length; ++i) {
+          layerNames += sep + this.aLayers[i].layerName;
+          sep = ',';
+        }
+        var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(this.mapWidget.getSessionID(),
+                                                            this._sMapname,
+                                                            sGeometry,
+                                                            maxFeatures, persist, selection, layerNames);
+        Fusion.oBroker.dispatchRequest(r, this.crtlClickDisplay.bind(this));
+      }
+    },
+
+    /**
+     * open a window if a URL is defined for the feature.
+     **/
+    crtlClickDisplay: function(r) {
+        //console.log('ctrlclcik  _display');
+        if (r.responseXML) {
+            var d = new DomNode(r.responseXML);
+            var h = d.getNodeText('Hyperlink');
+            if (h != '') {
+                window.open(h, "");
+            }
+        }
+    },
+    
     pingServer: function() {
         var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Common." + Fusion.getScriptLanguage() ;
         var params = {};
         params.parameters = 'session='+this.getSessionID();
         Fusion.ajaxRequest(s, params);
+    },
+    getGroupInfoUrl: function(groupName) {
+        if (this.mapInfo) {
+            var groups = this.mapInfo.links.groups;
+            for (var i=0; i<groups.length; i++) {
+                if (groups[i].name == groupName) {
+                    return groups[i].url;
+                }
+            }
+        }
+        return null;
+    },
+    getLayerInfoUrl: function(layerName) {
+        if (this.mapInfo) {
+            var layers = this.mapInfo.links.layers;
+            for (var i=0; i<layers.length; i++) {
+                if (layers[i].name == layerName) {
+                    return layers[i].url;
+                }
+            }
+        }
+        return null;
     }
 };
     
@@ -865,22 +1015,22 @@
         this.actuallyVisible = o.actuallyVisible;
     },
     
-    show: function() {
+    show: function(noDraw) {
         if (this.visible) {
             return;
         }
-        this.oMap.showGroup(this);
+        this.oMap.showGroup(this, noDraw ? true : false);
         this.visible = true;
         if (this.legend && this.legend.checkBox) {
             this.legend.checkBox.checked = true;
         }
     },
     
-    hide: function() {
+    hide: function(noDraw) {
         if (!this.visible) {
             return;
         }
-        this.oMap.hideGroup(this);
+        this.oMap.hideGroup(this, noDraw ? true : false);
         this.visible = false;
         if (this.legend && this.legend.checkBox) {
             this.legend.checkBox.checked = false;
@@ -960,22 +1110,22 @@
         return null;
     },
 
-    show: function() {
+    show: function(noDraw) {
         if (this.visible) {
             return;
         }
-        this.oMap.showLayer(this);
+        this.oMap.showLayer(this, noDraw ? true : false);
         this.set('visible', true);
         if (this.legend && this.legend.checkBox) {
             this.legend.checkBox.checked = true;
         }
     },
 
-    hide: function() {
+    hide: function(noDraw) {
         if (!this.visible) {
             return;
         }
-        this.oMap.hideLayer(this);
+        this.oMap.hideLayer(this, noDraw ? true : false);
         this.set('visible',false);
         if (this.legend && this.legend.checkBox) {
             this.legend.checkBox.checked = false;

Copied: sandbox/aboudreault/MapGuide/MapGuideViewerApi.js (from rev 1352, trunk/MapGuide/MapGuideViewerApi.js)
===================================================================
--- sandbox/aboudreault/MapGuide/MapGuideViewerApi.js	                        (rev 0)
+++ sandbox/aboudreault/MapGuide/MapGuideViewerApi.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,441 @@
+/**
+ * Fusion API AjaxViewer API layer
+ *
+ * $Id$
+ *
+ * Copyright (c) 2007, DM Solutions Group Inc.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/***************************************************************************
+* This is a simple API layer to mimick the MapGuide ajaxviewer API
+*/
+var mapWidgetId = 'Map';
+
+function Refresh() {
+    var Fusion = window.top.Fusion;
+    var mapWidget = Fusion.getWidgetById(mapWidgetId);
+    if (mapWidget && mapWidget.isMapLoaded()) {
+        mapWidget.redraw();
+    }
+}
+
+function SetSelectionXML(selectionXml) {
+    var Fusion = window.top.Fusion;
+    var mapWidget = Fusion.getWidgetById(mapWidgetId);
+    if (mapWidget && mapWidget.isMapLoaded()) {
+        mapWidget.setSelection(selectionXml, true, true);
+    }
+}
+
+function ZoomToView(x, y, scale, refresh) {
+    var Fusion = window.top.Fusion;
+    var mapWidget = Fusion.getWidgetById(mapWidgetId);
+    if (mapWidget && mapWidget.isMapLoaded()) {
+        var extent = mapWidget.getExtentFromPoint(x, y, scale);
+        mapWidget.setExtents(extent);
+    }
+}
+
+function DigitizePoint(handler) {
+    if (handler) {
+      var Fusion = window.top.Fusion;
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      var digitizer = new Fusion.Tool.Canvas.Point(mapWidget);
+      digitizer.mouseUp = PointHandlers.prototype.mouseUp;
+      Object.inheritFrom(digitizer, Fusion.Tool.Canvas.prototype, []);
+      digitizer.handler = handler;
+      digitizer.activateCanvas();
+      
+      //add a listener to update the position of the features
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, 
+        function(){
+          digitizer.updatePx();
+          digitizer.clearContext();
+          digitizer.draw(digitizer.context);
+        }
+      );
+    }
+}
+
+function DigitizeLine(handler) {
+    if (handler) {
+      var Fusion = window.top.Fusion;
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      var digitizer = new Fusion.Tool.Canvas.Line(mapWidget);
+      digitizer.mouseDown = LineHandlers.prototype.mouseDown;
+      digitizer.mouseMove = LineHandlers.prototype.mouseMove;
+      Object.inheritFrom(digitizer, Fusion.Tool.Canvas.prototype, []);
+      digitizer.handler = handler;
+      digitizer.activateCanvas();
+      
+      //add a listener to update the position of the features
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, 
+        function(){
+          digitizer.updatePx();
+          digitizer.clearContext();
+          digitizer.draw(digitizer.context);
+        }
+      );
+    }
+}
+
+function DigitizeLineString(handler) {
+    if (handler) {
+      var Fusion = window.top.Fusion;
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      var digitizer = new Fusion.Tool.Canvas.Line(mapWidget);
+      digitizer.mouseDown = MultiPointHandlers.prototype.mouseDown;
+      digitizer.mouseMove = MultiPointHandlers.prototype.mouseMove;
+      digitizer.dblClick = MultiPointHandlers.prototype.dblClick;
+      Object.inheritFrom(digitizer, Fusion.Tool.Canvas.prototype, []);
+      digitizer.handler = handler;
+      digitizer.activateCanvas();
+      
+      //add a listener to update the position of the features
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, 
+        function(){
+          digitizer.updatePx();
+          digitizer.clearContext();
+          digitizer.draw(digitizer.context);
+        }
+      );
+    }
+}
+
+function DigitizeRectangle(handler) {
+    if (handler) {
+      var Fusion = window.top.Fusion;
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      var digitizer = new Fusion.Tool.Canvas.Polygon(mapWidget);
+      digitizer.mouseDown = RectangleHandlers.prototype.mouseDown;
+      digitizer.mouseMove = RectangleHandlers.prototype.mouseMove;
+      Object.inheritFrom(digitizer, Fusion.Tool.Canvas.prototype, []);
+      digitizer.handler = handler;
+      digitizer.activateCanvas();
+      
+      //add a listener to update the position of the features
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, 
+        function(){
+          digitizer.updatePx();
+          digitizer.clearContext();
+          digitizer.draw(digitizer.context);
+        }
+      );
+    }
+}
+
+function DigitizePolygon(handler) {
+    if (handler) {
+      var Fusion = window.top.Fusion;
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      var digitizer = new Fusion.Tool.Canvas.Polygon(mapWidget);
+      digitizer.mouseDown = MultiPointHandlers.prototype.mouseDown;
+      digitizer.mouseMove = MultiPointHandlers.prototype.mouseMove;
+      digitizer.dblClick = MultiPointHandlers.prototype.dblClick;
+      Object.inheritFrom(digitizer, Fusion.Tool.Canvas.prototype, []);
+      digitizer.handler = handler;
+      digitizer.activateCanvas();
+      
+      //add a listener to update the position of the features
+      var mapWidget = Fusion.getWidgetById(mapWidgetId);
+      mapWidget.registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, 
+        function(){
+          digitizer.updatePx();
+          digitizer.clearContext();
+          digitizer.draw(digitizer.context);
+        }
+      );
+    }
+}
+
+Fusion.Tool.Canvas.prototype.getMap = function() {
+  return Fusion.getWidgetById(mapWidgetId);
+}
+
+Fusion.Tool.Canvas.prototype.deactivateCanvas = function() {
+    var map = this.getMap();
+    map.deregisterForEvent(Fusion.Event.MAP_RESIZED, this.resizeCanvasFn);
+    map.stopObserveEvent('mousemove', this.mouseMoveCB);
+    map.stopObserveEvent('mouseup', this.mouseUpCB);
+    map.stopObserveEvent('mousedown', this.mouseDownCB);
+    map.stopObserveEvent('dblclick', this.dblClickCB);
+}
+
+
+PointHandlers = Class.create();
+PointHandlers.prototype = {
+    mouseUp: function(e) {
+        var p = this.getMap().getEventPosition(e);
+        var point = this.getMap().pixToGeo(p.x, p.y);
+        this.setPoint(point.x, point.y);
+        this.clearContext();
+        this.draw(this.context);
+        this.isDigitizing = false;
+        this.deactivateCanvas();
+        this.handler(new Point(point.x, point.y));
+    }
+}
+    
+LineHandlers = Class.create();
+LineHandlers.prototype = {
+    mouseDown: function(e) {
+        if (Event.isLeftClick(e)) {
+            var p = this.getMap().getEventPosition(e);
+
+            if (!this.isDigitizing) {
+                this.segments = [];
+                var point = this.getMap().pixToGeo(p.x, p.y);
+                var from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                var to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                var seg = new Fusion.Tool.Canvas.Segment(from,to);
+                seg.setEditing(true);
+                this.addSegment(seg);
+                this.clearContext();
+                this.draw(this.context);     
+
+                this.isDigitizing = true;
+            } else {
+                this.isDigitizing = false;
+                var seg = this.lastSegment();
+                seg.setEditing(false);
+                //seg = this.extendLine();
+                this.clearContext();
+                this.draw(this.context);
+                this.deactivateCanvas();
+                
+                this.clean();
+                var ls = new LineString();
+                var nodes = this.getNodes();
+                for (var i=0; i<nodes.length; ++i) {
+                  var node = nodes[i];
+                  ls.AddPoint(new Point(node.x, node.y));
+                }
+                this.handler(ls);
+                
+            }
+        }
+    },
+
+    mouseMove: function(e) {
+        //console.log('SelectRadius.mouseMove');
+        if (!this.isDigitizing) {
+            return;
+        }
+    
+        var p = this.getMap().getEventPosition(e);
+        var seg = this.lastSegment();
+        seg.to.setPx(p.x,p.y);
+        seg.to.updateGeo();
+        this.clearContext();
+        this.draw(this.context);
+    },
+}
+    
+RectangleHandlers = Class.create();
+RectangleHandlers.prototype = {
+    mouseDown: function(e) {
+        if (Event.isLeftClick(e)) {
+            var p = this.getMap().getEventPosition(e);
+
+            if (!this.isDigitizing) {
+                this.segments = [];
+                var point = this.getMap().pixToGeo(p.x, p.y);
+                var from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                var to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                this.seg1 = new Fusion.Tool.Canvas.Segment(from,to);
+                this.addSegment(this.seg1);
+                from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                this.seg2 = new Fusion.Tool.Canvas.Segment(from,to);
+                this.addSegment(this.seg2);
+                from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                this.seg3 = new Fusion.Tool.Canvas.Segment(from,to);
+                this.addSegment(this.seg3);
+                from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                this.seg4 = new Fusion.Tool.Canvas.Segment(from,to);
+                this.addSegment(this.seg4);
+                this.clearContext();
+                this.draw(this.context);     
+
+                this.isDigitizing = true;
+            } else {
+                this.clearContext();
+                this.draw(this.context);
+                this.deactivateCanvas();
+                
+                this.clean();
+                var p1 = new Point(this.seg1.from.x,this.seg1.from.y);
+                var p2 = new Point(this.seg3.from.x,this.seg3.from.y);
+                var rect = new Rectangle(p1, p2);
+                this.handler(rect);
+                
+            }
+        }
+    },
+
+    mouseMove: function(e) {
+        //console.log('SelectRadius.mouseMove');
+        if (!this.isDigitizing) {
+            return;
+        }
+    
+        var p = this.getMap().getEventPosition(e);
+        this.seg1.to.setPx(p.x, this.seg1.from.py);
+        this.seg1.to.updateGeo();
+        this.seg2.from.setPx(p.x, this.seg1.from.py);
+        this.seg2.from.updateGeo();
+        this.seg2.to.setPx(p.x, p.y);
+        this.seg2.to.updateGeo();
+        this.seg3.from.setPx(p.x, p.y);
+        this.seg3.from.updateGeo();
+        this.seg3.to.setPx(this.seg1.from.px, p.y);
+        this.seg3.to.updateGeo();
+        this.seg4.from.setPx(this.seg1.from.px, p.y);
+        this.seg4.from.updateGeo();
+        this.clearContext();
+        this.draw(this.context);
+    },
+}
+    
+MultiPointHandlers = Class.create();
+MultiPointHandlers.prototype = {
+    mouseDown: function(e) {
+        if (Event.isLeftClick(e)) {
+            var p = this.getMap().getEventPosition(e);
+
+            if (!this.isDigitizing) {
+                this.segments = [];
+                var point = this.getMap().pixToGeo(p.x, p.y);
+                var from = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                var to = new Fusion.Tool.Canvas.Node(point.x,point.y, this.getMap());
+                var seg = new Fusion.Tool.Canvas.Segment(from,to);
+                seg.setEditing(true);
+                this.addSegment(seg);
+                this.clearContext();
+                this.draw(this.context);     
+
+                this.isDigitizing = true;
+            } else {
+                var seg = this.lastSegment();
+                seg.setEditing(false);
+                seg = this.extendLine();
+                seg.setEditing(true);
+                this.clearContext();
+                this.draw(this.context);
+            }
+        }
+    },
+
+    mouseMove: function(e) {
+        //console.log('SelectRadius.mouseMove');
+        if (!this.isDigitizing) {
+            return;
+        }
+    
+        var p = this.getMap().getEventPosition(e);
+        var seg = this.lastSegment();
+        seg.to.setPx(p.x,p.y);
+        seg.to.updateGeo();
+        this.clearContext();
+        this.draw(this.context);
+    },
+    
+    dblClick: function(e) {
+        //console.log('Digitizer.dblClick');
+        if (!this.isDigitizing) {
+            return;
+        }
+        this.event = e;
+        var p = this.getMap().getEventPosition(e);
+        var point = this.getMap().pixToGeo(p.x, p.y);
+        var seg = this.lastSegment();
+        seg.setEditing(false);
+        seg.to.set(point.x,point.y);
+        this.clearContext();
+        this.draw(this.context);
+        this.isDigitizing = false;
+        this.deactivateCanvas();
+        
+        this.clean();
+        var ls = new LineString();
+        var nodes = this.getNodes();
+        for (var i=0; i<nodes.length; ++i) {
+          var node = nodes[i];
+          ls.AddPoint(new Point(node.x, node.y));
+        }
+        this.handler(ls);
+    }
+}
+    
+function Point(x, y) {
+    this.X = x;
+    this.Y = y;
+}
+
+function LineString()
+{
+    this.points = new Array();
+    this.Count = 0;
+
+    this.AddPoint = function(pt)
+    {
+        this.points.push(pt);
+        this.Count ++;
+    }
+
+    this.Point = function(i)
+    {
+        if(i < 0 || i >= this.points.length)
+            return null;
+        return this.points[i];
+    }
+}
+
+function Circle()
+{
+    this.Center = null;
+    this.Radius = 0;
+
+    this.SetRadius = function(pt)
+    {
+        dx = pt.X - this.Center.X;
+        dy = pt.Y - this.Center.Y;
+        this.Radius = Math.sqrt(dx*dx + dy*dy);
+    }
+}
+
+function Rectangle(p1, p2)
+{
+    this.Point1 = p1;
+    this.Point2 = p2;
+}
+
+function Polygon()
+{
+    this.LineStringInfo = LineString;
+    this.LineStringInfo();
+}
+

Modified: sandbox/aboudreault/MapGuide/php/Buffer.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Buffer.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Buffer.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -43,11 +43,10 @@
         exit;
     }
 
-    /* currently no way to set this, but if we did provide a way, it
-       would allow creation of multiple buffers on individual objects
-       in the selection rather than a combined buffer */
-    $merge = false;
-
+    /* if merge is set, buffer the entire selection as one instead of creating buffers
+           * on each selected feature
+           */
+    $merge = ((isset($_REQUEST['merge'])) && $_REQUEST['merge'] == 1)?true:false;
     $layerName = $_REQUEST['layer'];
     $distance = $_REQUEST['distance'];
     $fillColor = $_REQUEST['fillcolor'];
@@ -200,7 +199,12 @@
 
         // create a SRS transformer if necessary.
         if($layerSrsWkt != $srsDefMap) {
-            $srsXform = $srsFactory->GetTransform($layerCs, $srsMap);
+            $verMajor = subStr(GetSiteVersion(), 0,1);
+            if ($verMajor == '1') {
+              $srsXform = new MgCoordinateSystemTransform($layerCs, $srsMap);
+            } else {
+              $srsXform = $srsFactory->GetTransform($layerCs, $srsMap);
+            }
         } else {
             $srsXform = null;
         }
@@ -236,7 +240,12 @@
         if($inputGeometries->GetCount() > 0) {
             $dist = $srsMap->ConvertMetersToCoordinateSystemUnits($distance);
             if(!$arbitraryMapSrs) {
-                $measure = $srsMap->GetMeasure();
+                $verMajor = subStr(GetSiteVersion(), 0,1);
+                if ($verMajor == '1') {
+                    $measure = new MgCoordinateSystemMeasure($srsMap);
+                } else {
+                    $measure = $srsMap->GetMeasure();
+                }
             } else {
                 $measure = null;
             }

Modified: sandbox/aboudreault/MapGuide/php/Common.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Common.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Common.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -29,21 +29,21 @@
  *          setting up the user and site connection.
  *****************************************************************************/
 
-/* 
+/*
  * If MapGuide Web Server Extensions are not installed in the default
- * location, you may need to edit these values to reflect the actual 
- * installation path.  You do not need to modify any other values in 
+ * location, you may need to edit these values to reflect the actual
+ * installation path.  You do not need to modify any other values in
  * this file to configure Fusion.
  */
- 
+
 $defaultInstallDir = dirname(__FILE__)."/../../../../../";
-$defaultExtensionDir = realpath($defaultInstallDir . "WebServerExtensions/www/");
+$defaultExtensionDir = realpath($defaultInstallDir . "webserverextensions/www/");
 
 /**
  * Developer's notes:
  *
  * This file should be included by all server-side scripts.  It includes some
- * default paths to install locations and manages all session-related and 
+ * default paths to install locations and manages all session-related and
  * user-related stuff except for actually creating a session.
  *
  * It also creates a MgResourceService instance for use by other scripts
@@ -84,8 +84,9 @@
          * credentials.  Handle this here, but keep the session the same.
          */
         $sessionID = $_REQUEST['session'];
-        session_start($sessionID);
-        
+        session_id(str_replace('_', '-', $sessionID));
+        session_start();
+
         /* current user is re-authenticating or not? */
         if (isset($_REQUEST['username']) && isset($_REQUEST['password'])) {
             $user = new MgUserInformation($_REQUEST['username'], $_REQUEST['password']);
@@ -93,13 +94,13 @@
         } else {
             $user = new MgUserInformation($sessionID);
         }
-        
+
         /* open a connection to the site.  This will generate exceptions if the user
          * is set up properly - not found, invalid password etc
          */
         $siteConnection = new MgSiteConnection();
         $siteConnection->Open($user);
-        
+
         /* MgUserInformation doesn't tell us who is logged in so we store it
          * in the php session for convenience
          */
@@ -147,7 +148,7 @@
 //common resource service to be used by all scripts
 $resourceService = $siteConnection->CreateService(MgServiceType::ResourceService);
 
-if (isset($_REQUEST['mapname'])) { 
+if (isset($_REQUEST['mapname'])) {
     $mapName = $_REQUEST['mapname'];
     $mapResourceID = new MgResourceIdentifier( 'Session:'.$sessionID.'//'.$mapName.'.MapDefinition');
     $mapStateID = new MgResourceIdentifier('Session:'.$sessionID.'//'.$mapName.'.'.MgResourceType::Map);
@@ -244,7 +245,7 @@
         {
             $numberString = str_replace($thousandSeparator, "", $numberString);
         }
-        
+
         // Replace localized decimal separators with "."
         $decimalSeparator = GetLocalizedString("DECIMALSEPARATOR", $locale);
         if($decimalSeparator != null && strlen($decimalSeparator) > 0 && $decimalSeparator != ".")
@@ -256,4 +257,4 @@
 }
 
 
-?>
\ No newline at end of file
+?>

Modified: sandbox/aboudreault/MapGuide/php/Constants.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Constants.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Constants.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Constants
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/MapGuide/php/Constants.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapGuide/php/LoadMap.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/LoadMap.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/LoadMap.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -93,8 +93,10 @@
     echo "sessionId:'$sessionID',";
     echo "mapId:'$mapid',";
     echo "metersPerUnit:$metersPerUnit,";
-    echo "mapTitle:'".addslashes(htmlentities($mapTitle))."',";
-    echo "mapName:'".addslashes(htmlentities($mapName))."',";
+    //echo "mapTitle:'".addslashes(htmlentities($mapTitle))."',";
+    //echo "mapName:'".addslashes(htmlentities($mapName))."',";
+    echo "mapTitle:'".addslashes($mapTitle)."',";
+    echo "mapName:'".addslashes($mapName)."',";
     echo "extent:[";
     echo $oMin->GetX().",";
     echo $oMin->GetY().",";
@@ -173,8 +175,8 @@
             $type = 1;
         }
     }
-    $typeStyles = array("PointTypeStyle", "LineTypeStyle", "AreaTypeStyle");
-    $ruleNames = array("PointRule", "LineRule", "AreaRule", );
+    $typeStyles = array("PointTypeStyle", "LineTypeStyle", "AreaTypeStyle", "CompositeTypeStyle");
+    $ruleNames = array("PointRule", "LineRule", "AreaRule", "CompositeRule");
     $output = 'scaleRanges: [';
     $scaleSep = '';
     for($sc = 0; $sc < $scaleRanges->length; $sc++)
@@ -216,8 +218,8 @@
                     $labelText = $label->length==1? $label->item(0)->nodeValue: "";
                     $filterText = $filter->length==1? $filter->item(0)->nodeValue: "";
                     $output .= $styleSep."{";
-                    $output .= "legendLabel:'".addslashes(htmlentities(trim($labelText)))."',";
-                    $output .= "filter:'".addslashes(htmlentities(trim($filterText)))."',";
+                    $output .= "legendLabel:'".addslashes(trim($labelText))."',";
+                    $output .= "filter:'".addslashes(trim($filterText))."',";
                     $output .= "geometryType:".($ts+1).",";
                     $output .= "categoryIndex:".($catIndex++);
                     $output .= '}';
@@ -246,8 +248,8 @@
 
 function OutputGroupInfo($group)
 {
-    echo "groupName:'".addslashes(htmlentities($group->GetName()))."',";
-    echo "legendLabel:'".addslashes(htmlentities($group->GetLegendLabel()))."',";
+    echo "groupName:'".addslashes($group->GetName())."',";
+    echo "legendLabel:'".addslashes($group->GetLegendLabel())."',";
     echo "uniqueId:'".$group->GetObjectId()."',";
     echo "displayInLegend:".BooleanToString($group->GetDisplayInLegend()).",";
     echo "expandInLegend:".BooleanToString($group->GetExpandInLegend()).",";
@@ -273,12 +275,12 @@
     echo "propertyMappings:{";
     $sep = '';
     foreach($mappings as $name => $value) {
-        echo $sep."$name:'$value'";
+        echo $sep."'$name':'$value'";
         $sep = ',';
     }
     echo "},";
     echo "uniqueId:'".$layer->GetObjectId()."',";
-    echo "layerName:'".addslashes(htmlentities($layer->GetName()))."',";
+    echo "layerName:'".addslashes($layer->GetName())."',";
     echo 'layerTypes:[';
     $sep = '';
     for ( $j=0; $j < count($aLayerTypes); $j++ )
@@ -292,7 +294,7 @@
     echo "resourceId:'".$layerDefinition->ToString()."',";
     echo "parentGroup:";
     echo $layer->GetGroup() ? "'".$layer->GetGroup()->GetObjectId()."'," : 'null,';
-    echo "legendLabel:'".addslashes(htmlentities($layer->GetLegendLabel()))."',";
+    echo "legendLabel:'".addslashes($layer->GetLegendLabel())."',";
     echo "selectable:".BooleanToString($layer->GetSelectable()).",";
     echo "visible:".BooleanToString($layer->GetVisible()).",";
     echo "actuallyVisible:".BooleanToString($layer->isVisible()).",";

Modified: sandbox/aboudreault/MapGuide/php/Measure.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Measure.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Measure.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Measure
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/MapGuide/php/Measure.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapGuide/php/Query.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Query.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Query.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -29,88 +29,6 @@
  *          a spatial filter
  *****************************************************************************/
 
-
-function GetPropertyValueFromFeatReader($featureReader, $propertyType, $propertyName)
-{
-    $val = "";
-
-    switch ($propertyType)
-    {
-       case MgPropertyType::Null :
-         //fwrite($logFileHandle, "$propertyName is a null propertyn");
-         $val= "";
-         break;
-       case MgPropertyType::Boolean :
-         $val = $featureReader->GetBoolean($propertyName);
-         //$valStr = printBoolean($val);
-         break;
-       case MgPropertyType::Byte :
-         $val = $featureReader->GetByte($propertyName);
-         break;
-       case MgPropertyType::DateTime :
-         $val = $featureReader->GetDateTime($propertyName);
-         //$valStr = printDateTime($val);
-         break;
-       case MgPropertyType::Single :
-         $val = $featureReader->GetSingle($propertyName);
-         break;
-       case MgPropertyType::Double :
-         $val = $featureReader->GetDouble($propertyName);
-         break;
-       case MgPropertyType::Int16 :
-         $val = $featureReader->GetInt16($propertyName);
-         break;
-       case MgPropertyType::Int32 :
-         $val = $featureReader->GetInt32($propertyName);
-         break;
-       case MgPropertyType::Int64 :
-         $val = $featureReader->GetInt64($propertyName);
-         break;
-       case MgPropertyType::String :
-         $val = $featureReader->GetString($propertyName);
-         break;
-       case MgPropertyType::Blob :
-         //fwrite($logFileHandle, "$propertyName is blobn");
-         break;
-       case MgPropertyType::Clob :
-         //fwrite($logFileHandle, "$propertyName is clobn");
-              break;
-       case MgPropertyType::Feature :
-         /*
-              $val = $featureReader->GetFeatureObject($propertyName);
-             if ($val != NULL) {
-                  fwrite($logFileHandle, "$propertyName is a featuren");
-                  printFeatureReader($val);
-             }
-         */
-         break;
-       case MgPropertyType::Geometry :
-         /*
-              fwrite($logFileHandle, "$propertyName is a geometryn");
-              $val = $featureReader->GetGeometry($propertyName);
-              if ($val != NULL) {
-                 $aGeometry = $agfReaderWriter->Read($val);
-                 //$aGeometry->Envelope();
-                 $wktRepresentation = $wktReaderWriter->Write($aGeometry);
-                 fwrite($logFileHandle, "WKT Representation: "$wktRepresentation"n");
-              } else {
-                 fwrite($logFileHandle, "This geometry property is nulln");
-              }
-         */
-         break;
-       case MgPropertyType::Raster :
-         /*
-              $val = $featureReader->GetRaster($propertyName);
-             fwrite($logFileHandle, "$propertyName is a rastern");
-         */
-         break;
-       default :
-         $val = "";
-    }
-
-    return $val;
-}
-
 try {
     /* set up the session */
     include ("Common.php");
@@ -143,7 +61,7 @@
         }
     }
     /* a filter expression to apply, in the form of an FDO SQL statement */
-    $filter = isset($_REQUEST['filter']) ? str_replace(array('*', '"'), array('%', "'"),html_entity_decode(urldecode( $_REQUEST['filter']))) : false;
+    $filter = isset($_REQUEST['filter']) ? str_replace(array('*', '"'), array('%', "'"),html_entity_decode(urldecode( $_REQUEST['filter']))) : '';
     //echo "<!-- filter: $filter -->\n";
     /* a spatial filter in the form on a WKT geometry */
     $spatialFilter = (isset($_REQUEST['spatialfilter']) && $_REQUEST['spatialfilter'] != '') ? urldecode($_REQUEST['spatialfilter']) : false;
@@ -156,16 +74,6 @@
     $map = new MgMap();
     $map->Open($resourceService, $mapName);
 
-
-
-
-    /* add the spatial filter if provided.  It is expected to come as a
-       WKT string, so we need to convert it to an MgGeometry */
-    if ($spatialFilter !== false ) {
-        //echo 'setting spatial filter<br>';
-        $wktRW = new MgWktReaderWriter();
-        $geom = $wktRW->Read($spatialFilter);
-    }
     /* add the features to the map selection and save it*/
     $selection = new MgSelection($map);
     
@@ -238,13 +146,47 @@
                 $queryOptions->AddFeatureProperty($geomName);
             }
 
-            /* add the attribute query if provided */
-            if ($filter !== false) {
-                //echo "<!-- setting filter $filter -->\n";
-                $queryOptions->SetFilter($filter);
+            //get the layer filter value if supplied
+            $layerReader = $resourceService->GetResourceContent($layerObj->GetLayerDefinition());
+            $xmldoc = DOMDocument::loadXML(ByteReaderToString($layerReader));
+            $xpathObj = new domXPath($xmldoc);
+            $xpathStr = "/LayerDefinition/VectorLayerDefinition/Filter"; //TODO: need this for DWF or Grid layers?
+            $xpathQuery = $xpathObj->query($xpathStr);
+            $layerFilter = '';
+            if ($xpathQuery->length > 0) {
+              $layerFilter = $xpathQuery->item(0)->nodeValue;
             }
+            /* create the combined filter value*/
+            if ($filter!='' && $layerFilter!='') {
+                $filter = "(".$filter.") AND (".$layerFilter.")";
+            } else {
+                $filter = $filter.$layerFilter;
+            }
+            if ($filter!='') {
+              //echo "/* setting filter:".$filter."*/";
+              $queryOptions->SetFilter($filter);
+            }
 
             if ($spatialFilter !== false ) {
+                $spatialContext = $featureService->GetSpatialContexts($featureResId, true);
+                $srsLayerWkt = false;
+                if ($spatialContext != null && $spatialContext->ReadNext() != null) {
+                    $srsLayerWkt = $spatialContext->GetCoordinateSystemWkt();
+                    /* skip this layer if the srs is empty */
+                }
+                if ($srsLayerWkt == null) {
+                    $srsLayerWkt = $srsDefMap;
+                }
+                /* create a coordinate system from the layer's SRS wkt */
+                $srsLayer = $srsFactory->Create($srsLayerWkt);
+                $verMajor = subStr(GetSiteVersion(), 0,1);
+                if ($verMajor == '1') {
+                  $srsXform = new MgCoordinateSystemTransform($srsMap, $srsLayer);
+                } else {
+                  $srsXform = $srsFactory->GetTransform($srsMap, $srsLayer);
+                }
+                $wktRW = new MgWktReaderWriter();
+                $geom = $wktRW->Read($spatialFilter, $srsXform);
                 $queryOptions->SetSpatialFilter($featureGeometryName, $geom, $variant);
             }
 
@@ -256,6 +198,13 @@
                 echo $e->GetDetails() . "\n";
                 echo $e->GetStackTrace() . "\n";
             }
+            
+            //debug block
+            //$testSelection = new MgSelection($map);
+            //$testSelection->AddFeatures($layerObj, $featureReader, $maxFeatures);
+            //$featureReader->Close();
+            //echo "/* features selected:".$testSelection->ToXML()."*/";
+            //$featureReader = $featureService->SelectFeatures($featureResId, $class, $queryOptions);
 
             $layerName = $layerObj->GetName();
             array_push($properties->layers, $layerName);
@@ -324,7 +273,9 @@
             echo $onfe->GetStackTrace() . "\n";
         } catch (MgException $e) {
             //what should we do with general exceptions?
-            echo "general exception";
+            echo "/*general exception:";
+            echo "ERROR: " . $e->GetMessage();
+            echo $e->GetDetails() . "*/";
         }
     }
 
@@ -394,7 +345,7 @@
     $selection->Save($resourceService, $mapName);
 
     //print_r($properties);
-    //echo var2json($properties);
+    //echo "/* SelectionXML:".$selection->ToXML()."*/";
 
     header('Content-type: text/x-json');
     header('X-JSON: true');
@@ -482,134 +433,4 @@
     return $aLayers;
 }
 
-
-/**
-   keep all the attributes of selected features in an array
- */
-function BuildSelectionArray($featureReader, $layerName, $properties, $bComputedProperties,
-                             $srsLayer, $bNeedsTransform, $layerObj)
-{
-    $agf = new MgAgfReaderWriter();
-    $srsFactory = new MgCoordinateSystemFactory();
-
-    $properties->$layerName->propertynames = array();
-    $properties->$layerName->propertyvalues = array();
-    $properties->$layerName->propertytypes = array();
-    $properties->$layerName->numelements = 0;
-    $properties->$layerName->values = array();
-
-    $properties->$layerName->metadatanames= array();
-    array_push($properties->$layerName->metadatanames, 'dimension');
-    array_push($properties->$layerName->metadatanames, 'bbox');
-    array_push($properties->$layerName->metadatanames, 'center');
-    array_push($properties->$layerName->metadatanames, 'area');
-    array_push($properties->$layerName->metadatanames, 'length');
-
-    $propCount = $featureReader->GetPropertyCount();
-    $numproperties =0;
-    for($j=0; $j<$propCount; $j++)
-    {
-        $propName = $featureReader->GetPropertyName($j);
-        $propType = $featureReader->GetPropertyType($propName);
-        if ($propType == MgPropertyType::Geometry) {
-            continue;
-        }
-        $mappings = $_SESSION['property_mappings'][$layerObj->GetObjectId()];
-        if (count($mappings) > 0)
-        {
-          if (!in_array($propName, array_keys($mappings)))
-            continue;
-        }
-        $mapping = isset($mappings[$propName]) ? $mappings[$propName] : $propName;
-        array_push($properties->$layerName->propertynames, $propName);
-        array_push($properties->$layerName->propertyvalues, $mapping);
-        array_push($properties->$layerName->propertytypes, $propType);
-        $numproperties++;
-
-    }
-
-    $srsTarget = null;
-    $srsXform = null;
-
-    while ($featureReader->ReadNext())
-    {
-        $properties->$layerName->values[$properties->$layerName->numelements] = array();
-        $properties->$layerName->metadata[$properties->$layerName->numelements] = array();
-
-        $dimension = '';
-        $bbox = '';
-        $center = '';
-        $area = '';
-        $length = '';
-        if ($bComputedProperties)
-        {
-            $classDef = $featureReader->GetClassDefinition();
-            $geomName = $classDef->GetDefaultGeometryPropertyName();
-            if ($geomName != '') {
-                $geomByteReader = $featureReader->GetGeometry($geomName);
-                $agf = new MgAgfReaderWriter();
-                $geom = $agf->Read($geomByteReader);
-
-                $envelope = $geom->Envelope();
-                $ll = $envelope->GetLowerLeftCoordinate();
-                $ur = $envelope->GetUpperRightCoordinate();
-                $bbox = $ll->GetX().','.$ll->GetY().','.$ur->GetX().','.$ur->GetY();
-                $centroid = $geom->GetCentroid()->GetCoordinate();
-                $center = $centroid->GetX().','.$centroid->GetY();
-
-                /* 0 = point, 1 = curve, 2 = surface */
-                $dimension = $geom->GetDimension();
-
-                if ($geom->GetDimension() > 0) {
-                    if ($bNeedsTransform && $srsTarget == null && $srsXform == null) {
-                        $srsTarget = $srsFactory->Create(getUtmWkt($centroid->GetX(),
-                                                                   $centroid->GetY()));
-                        $srsXform = $srsFactory->GetTransform($srsLayer, $srsTarget);
-                    }
-                    if ($srsXform != null) {
-                        try {
-                            $ageom = $geom->Transform($srsXform);
-                            $geom = $ageom;
-                        } catch (MgException $ee) {}
-                    }
-
-                    if ($geom->GetDimension() > 1) {
-                        $area = $geom->GetArea();
-                    }
-                    if ($geom->GetDimension() > 0) {
-                        $length = $geom->GetLength();
-                    }
-                }
-            }
-        }
-        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $dimension);
-        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $bbox);
-        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $center);
-        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $area);
-        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $length);
-
-
-        for($j=0; $j<$numproperties; $j++)
-        {
-            $propname = $properties->$layerName->propertynames[$j];
-            $value =  GetPropertyValueFromFeatReader($featureReader,
-                                                     $properties->$layerName->propertytypes[$j],
-                                                     $propname);
-            $value = htmlentities($value);
-            $value = addslashes($value);
-            $value = preg_replace( "/\r?\n/", "<br>", $value );
-            $aTmp = $properties->$layerName->values[$properties->$layerName->numelements];
-            array_push($properties->$layerName->values[$properties->$layerName->numelements], $value);
-            //$properties->$layerName->values[$properties->$layerName->numelements][$propname] = $value;
-        }
-        $properties->$layerName->numelements= $properties->$layerName->numelements+1;
-    }
-    return $properties;
-}
-
-function getUtmWkt($lon, $lat) {
-    $epsg42003 = "PROJCS[\"WGS 84 / Auto Orthographic\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS_1984\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Decimal_Degree\",0.0174532925199433]],PROJECTION[\"Orthographic\"],PARAMETER[\"central_meridian\",%.3e],PARAMETER[\"latitude_of_origin\",%.3e],UNIT[\"Meter\",1]]";
-
-    return sprintf( $epsg42003, $lon, $lat);;
-}
 ?>

Modified: sandbox/aboudreault/MapGuide/php/SaveMapFrame.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/SaveMapFrame.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/SaveMapFrame.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -35,7 +35,7 @@
     <script type="text/javascript" charset="utf-8">
     function Save(){
         setTimeout(function(){
-            window.frames['theImage'].document.execCommand('SaveAs', true, "<?php echo $_REQUEST['mapname'].'.'.$REQUEST['format']?>");
+            window.frames['theImage'].document.execCommand('SaveAs', true, "<?php echo $_REQUEST['mapname'].'.'.$_REQUEST['format']?>");
         },2500);
     };
     </script>
@@ -43,11 +43,17 @@
 <body onload='Save()'>
 <H4>Preparing Image for download...</H4>
 <?php
-include('MGCommon.php');
-echo "<iframe style='visibility: hidden;' id='theImage' src='SaveMap.php?format=".$_REQUEST['format'].
-                            "&mapname=".$_REQUEST['mapname'].
-                            "&session=".$_REQUEST['session'].
-                            "'></iframe>";
+include('Common.php');
+
+$szLayout="";
+if (isset($_REQUEST['layout']) &&  $_REQUEST['layout'] != "")
+  $szLayout = "&layout=".$_REQUEST['layout'];
+
+$szScale="";
+if (isset($_REQUEST['scale']) &&  $_REQUEST['scale'] != "")
+  $szScale = "&scale=".$_REQUEST['scale'];
+
+echo "<iframe style='visibility: hidden;' id='theImage' src='SaveMap.php?format=".trim($_REQUEST['format'])."&mapname=".$_REQUEST['mapname']."&session=".$_REQUEST['session']. $szLayout . $szScale."'></iframe>";
 ?>
 </body>
 </html>

Modified: sandbox/aboudreault/MapGuide/php/SetLayers.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/SetLayers.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/SetLayers.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Query
  *
- * $Id: Query.php 963 2007-10-16 15:37:30Z madair $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/MapGuide/php/SetLayers.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapGuide/php/SetSelection.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/SetSelection.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/SetSelection.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * SetSelection
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -25,14 +25,10 @@
  */
 
 include('Common.php');
+include('../../common/php/Utilities.php');
 include('Utilities.php');
-include('../../common/php/Utilities.php');
 
-    $mapName = "";
-    $sessionId = "";
     $selText = "";
-    $queryInfo = false;
-
     GetRequestParameters();
 
     try
@@ -41,65 +37,147 @@
         //
         $map = new MgMap();
         $map->Open($resourceService, $mapName);
-
         // Create the selection set and save it
-        $sel = new MgSelection($map);
-        if($selText != "")
-            $sel->FromXml($selText);
-        $sel->Save($resourceService, $mapName);
+        $selection = new MgSelection($map);
+        if($selText != "") {
+            $selection->FromXml($selText);
+        }
+        $selection->Save($resourceService, $mapName);
+        
+        //now return a data struture which is the same as Query.php
+        $featureService = $siteConnection->CreateService(MgServiceType::FeatureService);
+        
+        /* Get the map SRS - we use this to convert distances */
+        $srsFactory = new MgCoordinateSystemFactory();
+        //safely get an SRS ... (in Utilities)
+        $srsDefMap = GetMapSRS($map);
+        $srsMap = $srsFactory->Create($srsDefMap);
 
-        if($queryInfo) {
-            //Query feature info for the feature in the selection set. This will return the current set
-            //along with property info
-            //There must be only one feature in the feature set
-            $layers = $sel->GetLayers();
-            if($layers == null || $layers->GetCount() != 1) {
-                echo "Error: There must be exactly one feature in the set."; ///NOXLATE dbg report only
-                return;
+        /*holds selection array*/
+        $properties = NULL;
+        $properties->layers = array();
+
+        //process 
+        header('Content-type: text/x-json');
+        header('X-JSON: true');
+        $layers = $selection->GetLayers();
+        $nLayers = $layers->GetCount();
+        echo "/* nLayers:".$nLayers."*/";
+        for ($i=0; $i<$nLayers; $i++) {
+            $oLayer = $layers->GetItem($i);
+            $featureResId = new MgResourceIdentifier($oLayer->GetFeatureSourceId());
+            /* the class that is used for this layer will be used to select  features */
+            $class = $oLayer->GetFeatureClassName();
+
+            /* select the features */
+            $queryOptions = new MgFeatureQueryOptions();
+            
+            //TODO : seems that property mapping breaks the selection ????
+            //could it be that $selection->AddFeatures($layerObj, $featureReader, 0) is
+            //the one causing a problem when the properies are limited ?
+            $mappings = $_SESSION['property_mappings'][$oLayer->GetObjectId()];
+            if (0 && count($mappings) > 0) {
+                foreach($mappings as $name => $value) {
+                    $queryOptions->AddFeatureProperty($name);
+                    //echo "$name $value <br>\n";
+                }
+                $geomName = $oLayer->GetFeatureGeometryName();
+                $queryOptions->AddFeatureProperty($geomName);
             }
-            $layer = $layers->GetItem(0);
-            $featureClassName = $layer->GetFeatureClassName();
-            $filter = $sel->GenerateFilter($layer, $featureClassName);
-            $featureSrvc = $siteConnection->CreateService(MgServiceType::FeatureService);
-            $query = new MgFeatureQueryOptions();
-            $query->SetFilter($filter);
-            $featureSource = new MgResourceIdentifier($layer->GetFeatureSourceId());
-            $features = $featureSrvc->SelectFeatures($featureSource, $featureClassName, $query);
-            $featCount = 0;
-            while($features->ReadNext()) 
+            
+            $filter = $selection->GenerateFilter($oLayer, $class);
+            $queryOptions->SetFilter($filter);
+            $featureReader = $featureService->SelectFeatures($featureResId, $class, $queryOptions);
+            //$featureReader = $selection->GetSelectedFeatures($oLayer, $class, true );//this doesn't seem to work but would replace much of the above code
+
+            $layerName = $oLayer->GetName();
+            array_push($properties->layers, $layerName);
+
+            $spatialContext = $featureService->GetSpatialContexts($featureResId, true);
+            $srsLayerWkt = false;
+            if($spatialContext != null && $spatialContext->ReadNext() != null) {
+                $srsLayerWkt = $spatialContext->GetCoordinateSystemWkt();
+                /* skip this layer if the srs is empty */
+            }
+            if ($srsLayerWkt == null) {
+                $srsLayerWkt = $srsDefMap;
+            }
+            /* create a coordinate system from the layer's SRS wkt */
+            $srsLayer = $srsFactory->Create($srsLayerWkt);
+
+            // exclude layer if:
+            //  the map is non-arbitrary and the layer is arbitrary or vice-versa
+            //     or
+            //  layer and map are both arbitrary but have different units
+            //
+            $bLayerSrsIsArbitrary = ($srsLayer->GetType() == MgCoordinateSystemType::Arbitrary);
+            $bMapSrsIsArbitrary = ($srsMap->GetType() == MgCoordinateSystemType::Arbitrary);
+            $bComputedProperties = false;
+            $bNeedsTransform = false;
+            if (($bLayerSrsIsArbitrary != $bMapSrsIsArbitrary) ||
+                ($bLayerSrsIsArbitrary && ($srsLayer->GetUnits() != $srsMap->GetUnits()))) {
+                $bComputedProperties = false;
+            } else {
+                $srsTarget = null;
+                $srsXform = null;
+                $bNeedsTransform = ($srsLayer->GetUnitScale() != 1.0);
+            }
+
+            $properties = BuildSelectionArray($featureReader, $layerName, $properties,
+                                              $bComputedProperties,
+                                              $srsLayer, $bNeedsTransform, $oLayer);
+            $featureReader->Close();
+        }
+        
+        $result = NULL;
+        $result->hasSelection = false;
+        if ($layers && $layers->GetCount() >= 0)
+        {
+            $result->hasSelection = true;
+            $oExtents = $selection->GetExtents($featureService);
+            if ($oExtents)
             {
-                if($featCount++ == 1)
-                    break;
+                $oMin = $oExtents->GetLowerLeftCoordinate();
+                $oMax = $oExtents->GetUpperRightCoordinate();
+                $result->extents = NULL;
+                $result->extents->minx = $oMin->GetX();
+                $result->extents->miny = $oMin->GetY();
+                $result->extents->maxx = $oMax->GetX();
+                $result->extents->maxy = $oMax->GetY();
+
+                /*keep the full extents of the selection when saving the selection in the session*/
+                $properties->extents = NULL;
+                $properties->extents->minx = $oMin->GetX();
+                $properties->extents->miny = $oMin->GetY();
+                $properties->extents->maxx = $oMax->GetX();
+                $properties->extents->maxy = $oMax->GetY();
             }
-            if($featCount != 1) {
-                echo "Error: There must be exactly one feature in the set."; ///NOXLATE dbg report only
-                return;
+            $result->layers = array();
+            for ($i=0; $i<$layers->GetCount(); $i++) {
+              $layer = $layers->GetItem($i);
+              $layerName = $layer->GetName();
+              array_push($result->layers, $layerName);
+              $layerClassName = $layer->GetFeatureClassName();
+              $filter = $selection->GenerateFilter($layer, $layerClassName);
+              $a = explode('OR', $filter);
+              $result->$layerName->featureCount = count($a);
             }
-            $renderingSrvc = $siteConnection->CreateService(MgServiceType::RenderingService);
-            $layerNames = new MgStringCollection();
-            $layerNames->Add($layer->GetName());
-            $featInfo = $renderingSrvc->QueryFeatures($map, $layerNames, NULL, MgFeatureSpatialOperations::Intersects, $selText, 1, 2);
-            //header('Content-Type: text/xml; charset: UTF-8');
-            //echo $featInfo->ToXml()->ToString();
-            header('Content-type: text/x-json');
-            header('X-JSON: true');
-            echo xml2json($featInfo->ToXml());
+
+            /*save selection in the session*/
+            $_SESSION['selection_array'] = $properties;
         }
+        echo var2json($result);
 
 
     } catch(MgException $e) {
-        echo "ClearSelection Exception: " . $e->GetDetails();
+        echo "/* SetSelection Exception: " . $e->GetDetails()."*/";
     }
 
 function GetParameters($params)
 {
-    global $mapName, $sessionId, $selText, $queryInfo;
+    global $selText;
 
-    $mapName = $params['mapname'];
-    $sessionId = $params['session'];
     $selText = UnescapeMagicQuotes($params['selection']);
-    if(isset($params['queryinfo']))
-        $queryInfo = $params['queryinfo'] == "1";
 }
 
 


Property changes on: sandbox/aboudreault/MapGuide/php/SetSelection.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapGuide/php/UserManager.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/UserManager.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/UserManager.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -93,7 +93,8 @@
             $siteConnection = new MgSiteConnection();
             $siteConnection->Open($user);
             $site = $siteConnection->GetSite();
-            $fullname = trim($firstName." ".$surName);
+            $username = trim($username);
+            $fullname = $username;
             $site->AddUser($username, $username, $password, $fullname);                
             //set author role
             $usersToGrant = new MgStringCollection();
@@ -505,23 +506,6 @@
     }
 }
 
-
-function ByteReaderToString($byteReader)
-{
-    $buffer = '';
-    do
-    {
-        $data = str_pad("\0", 50000, "\0");
-        $len = $byteReader->Read($data, 50000);
-        if ($len > 0)
-        {
-            $buffer = $buffer . substr($data, 0, $len);
-        }
-    } while ($len > 0);
-
-    return $buffer;
-}
-
 function Test() {
     $manager = new MGUserManager(NULL);
     $prefId = $manager->AddPref('map', 'Sheboygan');
@@ -556,4 +540,4 @@
        mt_rand()
    );
 }
-?>
\ No newline at end of file
+?>

Modified: sandbox/aboudreault/MapGuide/php/Utilities.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Utilities.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapGuide/php/Utilities.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -663,4 +663,235 @@
 
     return $buffer;
 }
+
+
+
+function GetPropertyValueFromFeatReader($featureReader, $propertyType, $propertyName)
+{
+    $val = "";
+    if ($propertyType == null) {
+      $propertyType = $featureReader->GetPropertyType($propertyName);
+    }
+
+    try {
+        switch ($propertyType)
+        {
+           case MgPropertyType::Null :
+             //fwrite($logFileHandle, "$propertyName is a null propertyn");
+             $val= "";
+             break;
+           case MgPropertyType::Boolean :
+             $val = $featureReader->GetBoolean($propertyName);
+             //$valStr = printBoolean($val);
+             break;
+           case MgPropertyType::Byte :
+             $val = $featureReader->GetByte($propertyName);
+             break;
+           case MgPropertyType::DateTime :
+             $val = $featureReader->GetDateTime($propertyName);
+             //$valStr = printDateTime($val);
+             break;
+           case MgPropertyType::Single :
+             $val = $featureReader->GetSingle($propertyName);
+             break;
+           case MgPropertyType::Double :
+             $val = $featureReader->GetDouble($propertyName);
+             break;
+           case MgPropertyType::Int16 :
+             $val = $featureReader->GetInt16($propertyName);
+             break;
+           case MgPropertyType::Int32 :
+             $val = $featureReader->GetInt32($propertyName);
+             break;
+           case MgPropertyType::Int64 :
+             $val = $featureReader->GetInt64($propertyName);
+             break;
+           case MgPropertyType::String :
+             $val = $featureReader->GetString($propertyName);
+             break;
+           case MgPropertyType::Blob :
+             //fwrite($logFileHandle, "$propertyName is blobn");
+             break;
+           case MgPropertyType::Clob :
+             //fwrite($logFileHandle, "$propertyName is clobn");
+                  break;
+           case MgPropertyType::Feature :
+             /*
+                  $val = $featureReader->GetFeatureObject($propertyName);
+                 if ($val != NULL) {
+                      fwrite($logFileHandle, "$propertyName is a featuren");
+                      printFeatureReader($val);
+                 }
+             */
+             break;
+           case MgPropertyType::Geometry :
+             /*
+                  fwrite($logFileHandle, "$propertyName is a geometryn");
+                  $val = $featureReader->GetGeometry($propertyName);
+                  if ($val != NULL) {
+                     $aGeometry = $agfReaderWriter->Read($val);
+                     //$aGeometry->Envelope();
+                     $wktRepresentation = $wktReaderWriter->Write($aGeometry);
+                     fwrite($logFileHandle, "WKT Representation: "$wktRepresentation"n");
+                  } else {
+                     fwrite($logFileHandle, "This geometry property is nulln");
+                  }
+             */
+             break;
+           case MgPropertyType::Raster :
+             /*
+                  $val = $featureReader->GetRaster($propertyName);
+                 fwrite($logFileHandle, "$propertyName is a rastern");
+             */
+             break;
+           default :
+             $val = "";
+        }
+    } catch (MgException $e) {
+        //this switch block seems to throw an exception rather for null property values rather than just returning 
+        //a null value, so catch the exception here and set value to an empty string
+        $val = "";
+    }
+
+    if ( null == $val ) {
+      $val = "";
+    }
+    return $val;
+}
+
+/**
+   keep all the attributes of selected features in an array
+ */
+function BuildSelectionArray($featureReader, $layerName, $properties, $bComputedProperties,
+                             $srsLayer, $bNeedsTransform, $layerObj)
+{
+    $agf = new MgAgfReaderWriter();
+    $srsFactory = new MgCoordinateSystemFactory();
+
+    $properties->$layerName->propertynames = array();
+    $properties->$layerName->propertyvalues = array();
+    $properties->$layerName->propertytypes = array();
+    $properties->$layerName->numelements = 0;
+    $properties->$layerName->values = array();
+
+    $properties->$layerName->metadatanames= array();
+    array_push($properties->$layerName->metadatanames, 'dimension');
+    array_push($properties->$layerName->metadatanames, 'bbox');
+    array_push($properties->$layerName->metadatanames, 'center');
+    array_push($properties->$layerName->metadatanames, 'area');
+    array_push($properties->$layerName->metadatanames, 'length');
+
+    $mappings = $_SESSION['property_mappings'][$layerObj->GetObjectId()];
+    foreach($mappings as $name => $value)
+    {
+        $propType = $featureReader->GetPropertyType($name);
+        array_push($properties->$layerName->propertynames, $name);
+        array_push($properties->$layerName->propertyvalues, $value);
+        array_push($properties->$layerName->propertytypes, $propType);
+    }
+
+    $srsTarget = null;
+    $srsXform = null;
+
+    while ($featureReader->ReadNext())
+    {
+        $properties->$layerName->values[$properties->$layerName->numelements] = array();
+        $properties->$layerName->metadata[$properties->$layerName->numelements] = array();
+
+        $dimension = '';
+        $bbox = '';
+        $center = '';
+        $area = '';
+        $length = '';
+        if ($bComputedProperties)
+        {
+            $classDef = $featureReader->GetClassDefinition();
+            $geomName = $classDef->GetDefaultGeometryPropertyName();
+            if ($geomName != '') {
+                $geomByteReader = $featureReader->GetGeometry($geomName);
+                /* is this needed? We declare one outside the loop too?*/
+                $agf = new MgAgfReaderWriter();
+                $geom = $agf->Read($geomByteReader);
+
+                $envelope = $geom->Envelope();
+                $ll = $envelope->GetLowerLeftCoordinate();
+                $ur = $envelope->GetUpperRightCoordinate();
+                $bbox = $ll->GetX().','.$ll->GetY().','.$ur->GetX().','.$ur->GetY();
+                $centroid = $geom->GetCentroid()->GetCoordinate();
+                $center = $centroid->GetX().','.$centroid->GetY();
+
+                /* 0 = point, 1 = curve, 2 = surface */
+                $dimension = $geom->GetDimension();
+
+                if ($geom->GetDimension() > 0) {
+                    if ($bNeedsTransform && $srsTarget == null && $srsXform == null) {
+                        $srsTarget = $srsFactory->Create(getUtmWkt($centroid->GetX(),
+                                                                   $centroid->GetY()));
+                        $verMajor = subStr(GetSiteVersion(), 0,1);
+                        if ($verMajor == '1') {
+                          $srsXform = new MgCoordinateSystemTransform($srsLayer, $srsTarget);
+                        } else {
+                          $srsXform = $srsFactory->GetTransform($srsLayer, $srsTarget);
+                        }
+                    }
+                    if ($srsXform != null) {
+                        try {
+                            $ageom = $geom->Transform($srsXform);
+                            $geom = $ageom;
+                        } catch (MgException $ee) {
+                          echo "/*transform exception:";
+                          echo "ERROR: " . $ee->GetMessage() . "\n";
+                          echo $ee->GetDetails() . "\n*/";
+                        }
+                    }
+
+                    if ($geom->GetDimension() > 1) {
+                        $area = $geom->GetArea();
+                    }
+                    if ($geom->GetDimension() > 0) {
+                        $length = $geom->GetLength();
+                    }
+                }
+            }
+        }
+        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $dimension);
+        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $bbox);
+        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $center);
+        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $area);
+        array_push($properties->$layerName->metadata[$properties->$layerName->numelements], $length);
+
+
+        $numproperties = count($properties->$layerName->propertynames);
+        for($j=0; $j<$numproperties; $j++)
+        {
+            $propname = $properties->$layerName->propertynames[$j];
+            $value =  GetPropertyValueFromFeatReader($featureReader,
+                                                     $properties->$layerName->propertytypes[$j],
+                                                     $propname);
+            $value = htmlentities($value);
+            $value = addslashes($value);
+            $value = preg_replace( "/\r?\n/", "<br>", $value );
+            array_push($properties->$layerName->values[$properties->$layerName->numelements], $value);
+            //$properties->$layerName->values[$properties->$layerName->numelements][$propname] = $value;
+        }
+        $properties->$layerName->numelements= $properties->$layerName->numelements+1;
+    }
+    return $properties;
+}
+
+function getUtmWkt($lon, $lat) {
+    $epsg42003 = "PROJCS[\"WGS 84 / Auto Orthographic\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS_1984\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Decimal_Degree\",0.0174532925199433]],PROJECTION[\"Orthographic\"],PARAMETER[\"central_meridian\",%.3e],PARAMETER[\"latitude_of_origin\",%.3e],UNIT[\"Meter\",1]]";
+
+    return sprintf( $epsg42003, $lon, $lat);
+}
+
+function GetSiteVersion() {
+    global $user;
+    $serverAdmin = new MgServerAdmin();
+    $serverAdmin->Open($user);
+    $infoProps = $serverAdmin->GetInformationProperties();
+    $versionProp = $infoProps->GetItem(MgServerInformationProperties::ServerVersion);
+    $serverVersion = $versionProp->GetValue();
+    return $serverVersion;
+}
 ?>

Modified: sandbox/aboudreault/MapServer/MapServer.js
===================================================================
--- sandbox/aboudreault/MapServer/MapServer.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/MapServer.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -24,7 +24,7 @@
  */
 
 /******************************************************************************
- * Class: Fusion.Maps.MapServer 
+ * Class: Fusion.Maps.MapServer
  *
  * Implementation of the map widget for MapServer CGI interface services
 */
@@ -48,17 +48,19 @@
     bMapLoaded : false,
     bIsMapWidgetLayer : true,  //Setthis to false for overview map layers
     bLayersReversed: true,     //MS returns layers bottom-most layer first, we treat layer order in reverse sense
+    mapMetadataKeys: null,
+    layerMetadataKeys: null,
 
     //the map file
     sMapFile: null,
-    
+
     //imagetype
     _sImageType : 'png',
-    
+
     initialize : function(map, mapTag, isMapWidgetLayer) {
         //console.log('Fusion.Maps.MapServer.initialize');
         Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
-                
+
         this.registerEventID(Fusion.Event.MAP_SESSION_CREATED);
         this.registerEventID(Fusion.Event.MAP_SELECTION_ON);
         this.registerEventID(Fusion.Event.MAP_SELECTION_OFF);
@@ -75,7 +77,7 @@
         var extension = mapTag.extension;
         this.ratio = extension.MapRatio ? extension.MapRatio[0] : '1.0';
         //this.selectionType = extension.SelectionType ? extension.SelectionType[0] : 'INTERSECTS';
-        
+
         rootOpts = {
           displayInLegend: this.bDisplayInLegend,
           expandInLegend: this.bExpandInLegend,
@@ -87,9 +89,12 @@
           //TODO: set other opts for group initialization as required
         };
         this.layerRoot = new Fusion.Maps.MapServer.Group(rootOpts,this);
-        
+
         this.sMapFile = extension.MapFile ? extension.MapFile[0] : '';
 
+        this.mapMetadataKeys = extension.MapMetadata ? extension.MapMetadata[0] : null;
+        this.layerMetadataKeys = extension.LayerMetadata ? extension.LayerMetadata[0] : null;
+
         this.bSingleTile = mapTag.singleTile;// this is set by the AppDef.Map object
 
         this.keepAliveInterval = parseInt(extension.KeepAliveInterval ? extension.KeepAliveInterval[0] : 300);
@@ -108,7 +113,7 @@
             var sl = Fusion.getScriptLanguage();
             var scriptURL = this.arch + '/' + sl + '/CreateSession.' + sl;
             var options = {onComplete: this.createSessionCB.bind(this)};
-            Fusion.ajaxRequest(scriptURL,options);  
+            Fusion.ajaxRequest(scriptURL,options);
         }
         if (this.session[0] instanceof Fusion.Maps.MapServer) {
             this.session[0].registerForEvent(Fusion.Event.MAP_SESSION_CREATED, this.mapSessionCreated.bind(this));
@@ -116,7 +121,7 @@
             this.mapSessionCreated();
         }
     },
-    
+
     createSessionCB : function(r, json) {
         if (r.status == 200 && json) {
             var o;
@@ -140,14 +145,18 @@
     getSessionID: function() {
         return this.session[0];
     },
-    
+
     getMapName: function() {
         return this._sMapname;
     },
-    
+
+    getMapTitle: function() {
+        return this._sMapTitle;
+    },
+
     loadMap: function(mapfile, options) {
         while (this.mapWidget.isBusy()) {
-	        this.mapWidget._removeWorker(); 
+	        this.mapWidget._removeWorker();
 		}
         this.bMapLoaded = false;
         //console.log('loadMap: ' + resourceId);
@@ -160,59 +169,69 @@
             this.sMapFile = mapfile;
             return;
         }
-        
+
         if (this.bIsMapWidgetLayer) {
             this.mapWidget.triggerEvent(Fusion.Event.MAP_LOADING);
         } else {
             this.triggerEvent(Fusion.Event.MAP_LOADING);
         }
         this.mapWidget._addWorker();
-        
+
         this._fScale = -1;
         this._nDpi = 72;
-        
+
         options = options || {};
-        
+
         this._oMaxExtent = null;
         this.aVisibleLayers = options.showlayers || [];
         this.aVisibleGroups = options.showgroups || [];
         this.aLayers = [];
-        
+
         this.oSelection = null;
         this.aSelectionCallbacks = [];
         this._bSelectionIsLoading = false;
 
         var sl = Fusion.getScriptLanguage();
         var loadmapScript = this.arch + '/' + sl  + '/LoadMap.' + sl;
-        
+
         var sessionid = this.getSessionID();
-        
-        var params = 'mapfile='+mapfile+"&session="+sessionid;
-        var options = {onSuccess: this.mapLoaded.bind(this), 
+
+        var metadata = '';
+        if (this.mapMetadataKeys) {
+            metadata += '&map_metadata='+this.mapMetadataKeys;
+        }
+        if (this.layerMetadataKeys) {
+            metadata += '&layer_metadata='+this.layerMetadataKeys;
+        }
+
+        var params = 'mapfile='+mapfile+"&session="+sessionid+metadata;
+        var options = {onSuccess: this.mapLoaded.bind(this),
                                      parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
     },
-    
+
     mapLoaded: function(r, json) {
-        if (json)  
-        { 
-            var o; 
-            eval('o='+r.responseText); 
+        if (json)
+        {
+            var o;
+            eval('o='+r.responseText);
             this._sMapFile = o.mapId;
-            this._sMapname = o.mapName; 
+            this._sMapname = o.mapName;
             this._sMapTitle = o.mapTitle;
-            this._fMetersperunit = o.metersPerUnit; 
+            this._fMetersperunit = o.metersPerUnit;
             this.mapWidget._fMetersperunit = this._fMetersperunit;
-            this._sImageType = o.imagetype; 
+            this._sImageType = o.imagetype;
+            this.metadata = o.metadata;
 
-            this._oMaxExtent = OpenLayers.Bounds.fromArray(o.extent); 
-            
+            this._oMaxExtent = OpenLayers.Bounds.fromArray(o.extent);
+
             this.layerRoot.clear();
             this.layerRoot.legendLabel = this._sMapTitle;
-            
+
             this.parseMapLayersAndGroups(o);
-      			var minScale = 1.0e10;
-      			var maxScale = 0;
+
+            var minScale = 1.0e10;
+            var maxScale = 0;
             for (var i=0; i<this.aLayers.length; i++) {
               if (this.aLayers[i].visible) {
                   this.aVisibleLayers.push(this.aLayers[i].layerName);
@@ -224,13 +243,13 @@
             if (minScale <= 0) {
               minScale = 1.0;
             }
-            
+
             if (o.dpi) {
                 OpenLayers.DOTS_PER_INCH = o.dpi;
             }
 
             var layerOptions = {
-      				singleTile: true, 
+      				singleTile: true,
       				ratio: this.ratio,
       				maxExtent : this._oMaxExtent,
               		maxResolution : 'auto',
@@ -288,15 +307,15 @@
             }
 
             this.bMapLoaded = true;
-        }  
-        else 
+        }
+        else
         {
-            Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL, 
+            Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
 					'Failed to load requested map:\n'+r.responseText));
         }
         this.mapWidget._removeWorker();
     },
-    
+
     reloadMap: function() {
         this.mapWidget._addWorker();
         this.aShowLayers = [];
@@ -306,22 +325,33 @@
         this.aRefreshLayers = [];
         this.layerRoot.clear();
         this.aLayers = [];
-        
+
         var sl = Fusion.getScriptLanguage();
         var loadmapScript = this.arch + '/' + sl  + '/LoadMap.' + sl;
-        
+
         var sessionid = this.getSessionID();
-        
-        var params = 'mapname='+this._sMapname+"&session="+sessionid;
-        var options = {onSuccess: this.mapReloaded.bind(this), 
+        var metadata = '';
+        if (this.mapMetadataKeys) {
+            metadata += '&map_metadata='+this.mapMetadataKeys;
+        }
+        if (this.layerMetadataKeys) {
+            metadata += '&layer_metadata='+this.layerMetadataKeys;
+        }
+
+        var params = 'mapname='+this._sMapname+"&session="+sessionid+metadata;
+        var options = {onSuccess: this.mapReloaded.bind(this),
                                      parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
     },
-    
+
     mapReloaded: function(r,json) {  /* update this with OL code */
         if (json) {
             var o;
             eval('o='+r.responseText);
+
+            //can metadata change?
+            //this.metadata = o.metadata;
+
             this.parseMapLayersAndGroups(o);
             this.aVisibleLayers = [];
             for (var i=0; i<this.aLayers.length; i++) {
@@ -332,25 +362,25 @@
             this.drawMap();
             this.mapWidget.triggerEvent(Fusion.Event.MAP_RELOADED);
         } else {
-            Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL, 
-						'Failed to load requested map:\n'+r.responseText));
+            Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
+                OpenLayers.String.translate('mapLoadError', r.responseText)));
         }
         this.mapWidget._removeWorker();
     },
-    
+
     reorderLayers: function(aLayerIndex) {
         var sl = Fusion.getScriptLanguage();
         var loadmapScript = this.arch + '/' + sl  + '/SetLayers.' + sl;
-        
+
         var sessionid = this.getSessionID();
         var params = 'mapname='+this._sMapname+"&session="+sessionid;
         params += '&layerindex=' + aLayerIndex.join();
-		
-        var options = {onSuccess: this.mapLayersReset.bind(this, aLayerIndex), 
+
+        var options = {onSuccess: this.mapLayersReset.bind(this, aLayerIndex),
                                      parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
     },
-    
+
     mapLayersReset: function(aLayerIndex,r,json) {
       if (json) {
         var o;
@@ -359,7 +389,7 @@
   				var layerCopy = this.aLayers.clone();
   				this.aLayers = [];
   				this.aVisibleLayers = [];
-  			
+
           for (var i=0; i<aLayerIndex.length; ++i) {
             this.aLayers.push( layerCopy[ aLayerIndex[i] ] );
             if (this.aLayers[i].visible) {
@@ -367,15 +397,15 @@
             }
   				}
   				//this.layerRoot.clear();
-  			
+
   				this.drawMap();
   				this.triggerEvent(Fusion.Event.MAP_LAYER_ORDER_CHANGED);
   			} else {
-  				alert("setLayers failure:"+o.layerindex);
+          alert(OpenLayers.String.translate('setLayersError', o.layerindex));
   			}
       }
     },
-			
+
     parseMapLayersAndGroups: function(o) {
         for (var i=0; i<o.groups.length; i++) {
             var group = new Fusion.Maps.MapServer.Group(o.groups[i], this);
@@ -403,7 +433,7 @@
 
     /**
      * Function: isMapLoaded
-     * 
+     *
      * Returns true if the Map has been laoded succesfully form the server
      */
     isMapLoaded: function() {
@@ -413,19 +443,25 @@
     getScale : function() {
         return this.mapWidget.getScale();
     },
-    
+
     updateLayer: function() {   //to be fleshed out, add query file to layer if selection, call this before draw
       if (this.hasSelection()) {
           this.oLayerOL.addOptions({queryfile: this._sQueryfile});
       }
     },
-    
+
     drawMap: function() {
-        if (!this.bMapLoaded) {
+        if (!this.bMapLoaded || this.deferredDraw) {
             return;
         }
-
-        var params = { layers: this.aVisibleLayers.join(' '), ts : (new Date()).getTime()};
+        var aLayers = [];
+        for (var i=0; i<this.aLayers.length; i++) {
+            var l = this.aLayers[i];
+            if (l.isVisible()) {
+                aLayers.push(l.layerName);
+            }
+        }
+        var params = { layers: /*this.aVisibleLayers */aLayers.join(' '), ts : (new Date()).getTime()};
         if (this.hasSelection()) {
             params['queryfile']=this._sQueryfile;
         } else {
@@ -433,7 +469,7 @@
         }
         this.oLayerOL.mergeNewParams(params);
     },
-    
+
     showLayer: function( sLayer ) {
         this.aVisibleLayers.push(sLayer);
         this.drawMap();
@@ -454,7 +490,12 @@
         this.oLayerOL.setVisibility(true);
       } else {
         this.aVisibleGroups.push(sGroup);
-        //TODO: manipulate aVisibleLayers based on layers in the group
+        var group = this.layerRoot.findGroup(sGroup);
+        this.deferredDraw = true;
+        for (var i=0; i<group.layers.length; ++i) {
+          group.layers[i].show();
+        }
+        this.deferredDraw = false;
         this.drawMap();
       }
     },
@@ -469,7 +510,12 @@
                 break;
             }
         }
-        //TODO: manipulate aVisibleLayers based on layers in the group
+        var group = this.layerRoot.findGroup(sGroup);
+        this.deferredDraw = true;
+        for (var i=0; i<group.layers.length; ++i) {
+          group.layers[i].hide();
+        }
+        this.deferredDraw = false;
         this.drawMap();
       }
     },
@@ -481,7 +527,7 @@
     hasSelection: function() { return this.bSelectionOn; },
 
     getSelectionCB : function(userFunc, layers, startend, r, json) {
-      if (json) 
+      if (json)
       {
           var o;
           eval("o="+r.responseText);
@@ -490,7 +536,7 @@
           userFunc(oSelection);
       }
     },
-    
+
     /**
      * advertise a new selection is available and redraw the map
      */
@@ -548,25 +594,25 @@
      *        selection has loaded
      * @param layers {string} Optional parameter.  A comma separated
      *        list of layer names (Roads,Parcels). If it is not
-     *        given, all the layers that have a selection will be used  
+     *        given, all the layers that have a selection will be used
      *
      * @param startcount {string} Optional parameter.  A comma separated
      *        list of a statinh index and the number of features to be retured for
      *        each layer given in the layers parameter. Index starts at 0
      *        (eg: 0:4,2:6 : return 4 elements for the first layers starting at index 0 and
      *         six elements for layer 2 starting at index 6). If it is not
-     *        given, all the elemsnts will be returned.  
+     *        given, all the elemsnts will be returned.
      */
     getSelection : function(userFunc, layers, startcount) {
-        
-        if (userFunc) 
+
+        if (userFunc)
         {
             var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Selection." + Fusion.getScriptLanguage() ;
-            var params = {parameters:'session='+this.getSessionID()+'&mapname='+ this._sMapname+ '&layers='+layers+'&startcount='+startcount+'&queryfile='+this._sQueryfile, 
+            var params = {parameters:'session='+this.getSessionID()+'&mapname='+ this._sMapname+ '&layers='+layers+'&startcount='+startcount+'&queryfile='+this._sQueryfile,
                           onComplete: this.getSelectionCB.bind(this, userFunc, layers, startcount)};
             Fusion.ajaxRequest(s, params);
         }
-        
+
     },
 
     /**
@@ -574,7 +620,7 @@
     */
     clearSelection : function() {
       if (!this.aLayers) return;
-      
+
         //clear the selection count for the layers
         for (var j=0; j<this.aLayers.length; ++j) {
           this.aLayers[j].selectedFeatureCount = 0;
@@ -591,12 +637,12 @@
     /**
        Call back function when slect functions are called (eg queryRect)
     */
-    processQueryResults : function(r, json) {
+    processQueryResults : function(zoomTo, r, json) {
         this.mapWidget._removeWorker();
         if (json) {
             var o;
             eval("o="+r.responseText);
-            if (!o.hasSelection) { 
+            if (!o.hasSelection) {
                 //this.drawMap();
                 return;
             } else {
@@ -610,6 +656,11 @@
                   }
                 }
                 this.newSelection();
+                if (zoomTo) {
+                var ext = oNode.extents
+                var extents = new OpenLayers.Bounds(ext.minx, ext.miny, ext.maxx, ext.maxy);
+                this.zoomToSelection(extents);
+              }
             }
         }
     },
@@ -627,7 +678,7 @@
             for (var j=0; j<this.aLayers.length; ++j) {
                 this.aLayers[j].selectedFeatureCount = 0;
             }
-
+            
             var geometry = options.geometry || '';
             var maxFeatures = options.maxFeatures || -1;
             var bPersistant = options.persistent || true;
@@ -640,14 +691,14 @@
             }
             var extend = options.extendSelection ? '&extendselection=true' : '';
             var computed = options.computedProperties ? '&computed=true' : '';
-
+            var zoomTo = options.zoomTo || false;
             var sl = Fusion.getScriptLanguage();
             var loadmapScript = this.arch + '/' + sl  + '/Query.' + sl;
-
+            
             var sessionid = this.getSessionID();
-
+            
             var params = 'mapname='+this._sMapname+"&session="+sessionid+'&spatialfilter='+geometry+'&maxfeatures='+maxFeatures+filter+'&layers='+layers+'&variant='+selectionType+extend;
-            var options = {onSuccess: this.processQueryResults.bind(this), 
+            var options = {onSuccess: this.processQueryResults.bind(this, zoomTo),
                 parameters: params};
             Fusion.ajaxRequest(loadmapScript, options);
         }
@@ -667,14 +718,14 @@
         var matchlimit = options.matchlimit || -1;
         var layer = options.layer || '';
         var attribute = options.attribute || '';
-        var value = options.value || '';
+        var pattern = options.pattern || '';
         var sl = Fusion.getScriptLanguage();
         var loadmapScript = this.arch + '/' + sl  + '/Search.' + sl;
 
         var sessionid = this.getSessionID();
 
-        var params = 'mapname='+this._sMapname+"&session="+sessionid+'&matchlimit='+matchlimit+'&layer='+layer+'&attribute='+attribute+'&value='+value;
-        var options = {onSuccess: this.processQueryResults.bind(this), 
+        var params = 'mapname='+this._sMapname+"&session="+sessionid+'&matchlimit='+matchlimit+'&layer='+layer+'&attribute='+attribute+'&pattern='+pattern;
+        var options = {onSuccess: this.processQueryResults.bind(this, false), 
                                      parameters: params};
         Fusion.ajaxRequest(loadmapScript, options);
     },
@@ -682,20 +733,37 @@
     loadStart: function() {
       this.mapWidget._addWorker();
     },
-    
+
     loadEnd: function() {
       this.mapWidget._removeWorker();
     },
-    
+
     pingServer: function() {
         var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Common." + Fusion.getScriptLanguage() ;
         var params = {};
         params.parameters = 'session='+this.getSessionID();
         Fusion.ajaxRequest(s, params);
-    }
+  },
+
+    getGroupInfoUrl: function(groupName) {
+      return null;
+   },
+
+    getLayerInfoUrl: function(layerName) {
+      return null;
+  },
+
+  getMetadata: function(key) {
+      if (typeof this.metadata[key] != 'undefined') {
+          return this.metadata[key];
+      } else {
+          return '';
+      }
+  }
+
 };
 
-    
+
 /******************************************************************************
  * Class: Fusion.Maps.MapServer.Group
  *
@@ -718,26 +786,27 @@
         this.visible = o.visible;
         this.actuallyVisible = o.actuallyVisible;
     },
-    
+
     clear: function() {
         Fusion.Widget.Map.Group.prototype.clear.apply(this, []);
         //this.oMap = null;
     },
-     
+
     show: function() {
+        this.visible = true;
         this.oMap.showGroup(this.groupName);
-        this.visible = true;
     },
-    
+
     hide: function() {
+        this.visible = false;
         this.oMap.hideGroup(this.groupName);
-        this.visible = false;
     },
-    
+
     isVisible: function() {
-        return this.visible;
+        var bParentVisible = (this.parentGroup && this.parentGroup.isVisible) ? this.parentGroup.isVisible() : true;
+        return this.visible && bParentVisible;
     }
-    
+
 };
 
 var MSLAYER_POINT_TYPE = 0;
@@ -754,11 +823,11 @@
 
 Fusion.Maps.MapServer.Layer = Class.create();
 Fusion.Maps.MapServer.Layer.prototype = {
-    
+
     scaleRanges: null,
-    
+
     oMap: null,
-    
+
     initialize: function(o, oMap) {
         this.uniqueId = o.uniqueId;
         Object.inheritFrom(this, Fusion.Widget.Map.Layer.prototype, [this.uniqueId]);
@@ -776,6 +845,7 @@
         this.actuallyVisible = o.actuallyVisible;
         this.editable = o.editable;
         this.parentGroup = o.parentGroup;
+        this.metadata = o.metadata;
         this.scaleRanges = [];
     		this.minScale = 1.0e10;
     		this.maxScale = 0;
@@ -786,13 +856,13 @@
       			this.maxScale = Math.max(this.maxScale, scaleRange.maxScale);
         }
     },
-    
+
     clear: function() {
         Fusion.Widget.Map.Layer.prototype.clear.apply(this, []);
         this.oMap = null;
         this.legend = null;
     },
-    
+
     supportsType: function(type) {
         for (var i=0; i<this.layerTypes.length; i++) {
             if (this.layerTypes[i] == type) {
@@ -801,7 +871,7 @@
         }
         return false;
     },
-    
+
     getScaleRange: function(fScale) {
         for (var i=0; i<this.scaleRanges.length; i++) {
             if (this.scaleRanges[i].contains(fScale)) {
@@ -812,17 +882,26 @@
     },
 
     show: function() {
+        this.set('visible', true);
         this.oMap.showLayer(this.layerName);
-        this.set('visible', true);
     },
 
     hide: function() {
+        this.set('visible',false);
         this.oMap.hideLayer(this.layerName);
-        this.set('visible',false);
     },
 
     isVisible: function() {
-        return this.visible;
+        var bParentVisible = this.parentGroup ? this.parentGroup.isVisible() : true;
+        return this.visible && bParentVisible;
+    },
+
+    getMetadata: function(key) {
+        if (typeof this.metadata[key] != 'undefined') {
+            return this.metadata[key];
+        } else {
+            return '';
+        }
     }
 };
 
@@ -842,7 +921,7 @@
         if (!o.styles) {
             return;
         }
-        
+
         /*special case : if there are no classes and it is a raster layer
           we set it to use the default static raster icon*/
         if (o.styles.length == 0 && bRaster)
@@ -854,7 +933,7 @@
           tmpsyle.staticIcon = true;
           var styleItem = new Fusion.Maps.MapServer.StyleItem(tmpsyle, tmpsyle.staticIcon);
           this.styles.push(styleItem);
-        }    
+        }
         else
         {
           var staticIcon = o.styles.length>=1 ? false : bRaster;

Modified: sandbox/aboudreault/MapServer/php/LegendIcon.php
===================================================================
--- sandbox/aboudreault/MapServer/php/LegendIcon.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/LegendIcon.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -25,7 +25,7 @@
  */
 
 /*****************************************************************************
- * Purpose: Draw a legend icon 
+ * Purpose: Draw a legend icon
  *****************************************************************************/
 
 include(dirname(__FILE__).'/Common.php');
@@ -33,7 +33,61 @@
 if (!isset($mapName)) {
     die('mapname not set');
 }
+
+$legendIconCacheFile = "";
+
 if (isset($_SESSION['maps']) && isset($_SESSION['maps'][$mapName])) {
+    /* json decode only in PHP 5.2 and later */
+    if (function_exists('json_decode')) {
+        $configFile = realpath(dirname(__FILE__)."/../../config.json");
+        if (file_exists($configFile)) {
+            $configStr = file_get_contents($configFile);
+            /* replace single quotes with double quotes */
+            $configStr = str_replace("'", '"', $configStr);
+            /* get rid of new lines, it just complicates things */
+            $configStr = str_replace("\n", '', $configStr);
+            /* get rid of embedded comments */
+            $configStr = preg_replace("/\/\*.*\*\//U", "", $configStr);
+            /* the regex after this one can't handle http: as a value, so mangle it. */
+            $configStr = preg_replace("/http:/U", "http_", $configStr);
+            /* quote unquoted attribute names */
+            $configStr = preg_replace("/[^\"]{1}(\w*):/U", "\"$1\":", $configStr);
+            /* decode the whole thing */
+            $configObj = json_decode($configStr, false);
+            /* if the legendIconCache dir is set */
+            if (isset($configObj->mapserver->legendIconCacheDir)) {
+              $legendIconCacheDir = $configObj->mapserver->legendIconCacheDir;
+
+              // check for closing '/'
+              $legendIconCacheDir = str_replace( '\\', '/', trim( $legendIconCacheDir ) );
+              if ( substr( $legendIconCacheDir, -1 ) != '/' )
+              {
+                  $legendIconCacheDir .= '/';
+              }
+
+              $cacheLegendIcons = true;
+              $str = file_get_contents($_SESSION['maps'][$mapName]);
+              /* create a unique location for the map icons based on
+               * the content of the of map file.  If the content changes
+               * then the icons should be rebuilt anyway
+               */
+              $legendIconCacheDir = $legendIconCacheDir.md5($str)."/";
+              if (!is_dir($legendIconCacheDir)) {
+                mkdir($legendIconCacheDir);
+              }
+              /* TODO: can we figure out what the content type is? */
+              $legendIconCacheFile = $legendIconCacheDir."_".$REQUEST_VARS['layername']."_".$REQUEST_VARS['classindex'].".png";
+              /* if the icon exists, return it */
+              if (file_exists($legendIconCacheFile)) {
+                  /* TODO: can we figure out what the content type is? */
+                  header('Content-type: image/png');
+                  readfile($legendIconCacheFile);
+                  exit;
+              }
+            }
+        }
+    }
+
     $oMap = ms_newMapObj($_SESSION['maps'][$mapName]);
     $oLayer = $oMap->getLayerByName($REQUEST_VARS['layername']);
     $oClass = $oLayer->getClass($REQUEST_VARS['classindex']);
@@ -43,11 +97,16 @@
       $width = 16;
     if ($height <=0)
       $height = 16;
-    
+
     $oImg = $oClass->createLegendIcon($width, $height);
     /* TODO: can we figure out what the content type is? */
     header('Content-type: image/png');
-    $oImg->saveImage("");
+    if ($cacheLegendIcons) {
+        $oImg->saveImage($legendIconCacheFile);
+        readfile($legendIconCacheFile);
+    } else {
+      $oImg->saveImage("");
+    }
     $oImg->free();
 }
 ?>

Modified: sandbox/aboudreault/MapServer/php/LoadMap.php
===================================================================
--- sandbox/aboudreault/MapServer/php/LoadMap.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/LoadMap.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -41,16 +41,16 @@
 /* could potentially make this optional */
 $moveToSession = true;
 
-/** 
+/**
    TODO make it possible to specify only a relative path
    in the WebLayout and have this code know where to
    look for it on the server somehow
  */
- 
+
 /* only do something if a mapfile was requested */
 if (isset($_REQUEST['mapfile'])) {
     $oMap = ms_newMapObj($_REQUEST['mapfile']);
-    
+
     /* optionally move the mapfile to the session */
     if ($moveToSession) {
         //path to map file in the session is used by the client
@@ -70,7 +70,7 @@
             $oMap->setFontSet(realpath($fontSet));
         }
         /* need to modify all image symbols reference in the map file
-         eg STYLE 
+         eg STYLE
              SYMBOL "../etc/markers/target-7.gif" : this is relative to the map file
         */
         for ($i=0; $i<$oMap->numlayers; $i++)
@@ -115,6 +115,14 @@
     $mapObj->sessionId = $sessionID;
     $mapObj->mapId = $mapId;
 
+    $mapObj->metadata = NULL;
+    if (isset($_REQUEST['map_metadata'])) {
+        $mapMetadataKeys = explode(',',$_REQUEST['map_metadata']);
+        foreach($mapMetadataKeys as $key) {
+            $mapObj->metadata->$key = $oMap->getMetadata($key);
+        }
+    }
+
     $mapObj->metersPerUnit = GetMetersPerUnit($oMap->units);
 
     $mapObj->dpi = $oMap->resolution;
@@ -126,7 +134,7 @@
     if (!isset($_SESSION['maps'][$mapObj->mapName])) {
         $_SESSION['maps'][$mapObj->mapName] = $mapId;
     }
-    $mapObj->extent = array( $oMap->extent->minx, $oMap->extent->miny, 
+    $mapObj->extent = array( $oMap->extent->minx, $oMap->extent->miny,
                              $oMap->extent->maxx, $oMap->extent->maxy );
     $minScale = $oMap->web->minscale == -1 ? MIN_SCALE : $oMap->web->minscale;
     $maxScale = $oMap->web->maxscale == -1 ? MAX_SCALE : $oMap->web->maxscale;
@@ -138,6 +146,15 @@
     {
          $layer=$oMap->GetLayer($i);
          $layerObj = NULL;
+
+         $layerObj->metadata = NULL;
+         if (isset($_REQUEST['layer_metadata'])) {
+             $layerMetadataKeys = explode(',',$_REQUEST['layer_metadata']);
+             foreach($layerMetadataKeys as $key) {
+                 $layerObj->metadata->$key = $layer->getMetadata($key);
+             }
+         }
+
          $layerObj->propertyMappings = '';
          $layerObj->uniqueId = $i;
          $layerObj->layerName = $layer->name;
@@ -159,42 +176,42 @@
                 $type = 0;
          }
          $layerObj->layerTypes = array($type);
-         
+
          $displayInLegend = strtolower($layer->getMetaData('displayInLegend'));
          $layerObj->displayInLegend = $displayInLegend == 'false' ? false : true;
-         
+
          $expandInLegend = strtolower($layer->getMetaData('expandInLegend'));
-         $layerObj->expandInLegend = $expandInLegend == 'false' ? false : true;;
+         $layerObj->expandInLegend = $expandInLegend == 'false' ? false : true;
          $layerObj->resourceId = $layer->name;
-         $layerObj->parentGroup = '';
-         
+         $layerObj->parentGroup = $layer->group;
+
          $legendLabel = $layer->getMetaData('legendLabel');
          if ($legendLabel == '') {
              $legendLabel = $layer->name;
          }
          $layerObj->legendLabel = $legendLabel;
-         
+
          $selectable = strtolower($layer->getMetaData('selectable'));
          $layerObj->selectable = $selectable == 'true' ? true : false;
          $layerObj->visible = ($layer->status == MS_ON || $layer->status == MS_DEFAULT);
          $layerObj->actuallyVisible = true;
-         
+
          $editable = strtolower($layer->getMetaData('editable'));
          $layerObj->editable = $editable == 'true' ? true : false;
-         
-         /* process the classes.  The legend expects things 
+
+         /* process the classes.  The legend expects things
           * organized by scale range so we have to first
           * find all the scale breaks, then create ranges
           * for each scale break pair, then slot the classes
           * into the scale ranges that they apply to.
           */
-         
+
          $aScaleRanges = array();
          //create a default scale range for the layer as a whole
          $layerMin = $layer->minscale == -1 ? $minScale : $layer->minscale;
          $layerMax = $layer->maxscale == -1 ? $maxScale : $layer->maxscale;
-         
-         //find all the unique scale breaks in this layer                  
+
+         //find all the unique scale breaks in this layer
          $aScaleBreaks = array($layerMin, $layerMax);
          for ($j=0; $j<$layer->numclasses; $j++) {
              $oClass = $layer->getClass($j);
@@ -209,7 +226,7 @@
          }
          //sort them
          sort($aScaleBreaks);
-         
+
          //create scale ranges for each pair of breaks
          for ($j=0; $j<count($aScaleBreaks)-1; $j++) {
              $scaleRange = NULL;
@@ -218,7 +235,7 @@
              $scaleRange->styles = array();
              array_push($aScaleRanges, $scaleRange);
          }
-         
+
          //create classes and slot them into the scale breaks
          for ($j=0; $j<$layer->numclasses; $j++) {
              $oClass = $layer->getClass($j);
@@ -239,24 +256,36 @@
          }
          $layerObj->scaleRanges = $aScaleRanges;
          array_push($mapObj->layers, $layerObj);
-    } 
+    }
     $mapObj->groups = array();
+    $aGroups = $oMap->getAllGroupNames();
+    foreach($aGroups as $groupName) {
+        $aLayerIndexes = $oMap->getLayersIndexByGroup($groupName);
+        if (count($aLayerIndexes) > 0) {
+            array_push($mapObj->groups, getGroupObject($oMap->getLayer($aLayerIndexes[0])));
+        }
+    }
     echo var2json($mapObj);
 }
 
-function getGroupObject() {
+function getGroupObject($layer) {
     $group = NULL;
-    $group->groupName = '';
-    $group->legendLabel = '';
-    $group->uniqueId = '';
-    $group->displayInLegend = '';
-    $group->expandInLegend = '';
+    $group->groupName = $layer->group;
+    $ll = $layer->getMetaData('groupLegendLabel');
+    $group->legendLabel = $ll != '' ? $ll : $group->groupName;
+    $group->uniqueId = $group->groupName;
+    $b = $layer->getMetaData('groupDisplayInLegend');
+    $group->displayInLegend = ($b == 'false') ? false : true;
+    $b = $layer->getMetaData('groupExpandInLegend');
+    $group->expandInLegend = ($b == 'false') ? false : true;
     $group->layerGroupType = '';
+    /* parent is always not set for mapserver since we can't have nested groups */
     $group->parentUniqueId = '';
     $group->parent = '';
-    $group->visible = '';
-    $group->actuallyVisible = '';
-  
+    $b = $layer->getMetaData('groupVisible');
+    $group->visible = ($b == 'false') ? false : true;
+    $group->actuallyVisible = $layer->isVisible();
+
     return $group;
 }
 

Modified: sandbox/aboudreault/MapServer/php/Measure.php
===================================================================
--- sandbox/aboudreault/MapServer/php/Measure.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/Measure.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <?php
 /*****************************************************************************
  *
- * $Id: $
+ * $Id$
  *
  * Purpose: Measure a line segment and return the distance
  *
@@ -48,12 +48,16 @@
     if (isset($_SESSION['maps']) && isset($_SESSION['maps'][$mapName])) {
         $oMap = ms_newMapObj($_SESSION['maps'][$mapName]);
     }
-    $shapeObj = ms_newShapeObj(MS_SHAPE_LINE);
-    $lineObj = ms_newLineObj();
-    $lineObj->addXY($x1,$y1);
-    $lineObj->addXY($x2,$y2);
-    $shapeObj->add($lineObj);
-    $distance = $shapeObj->getLength($shapeObj);
+    if ($oMap->units == MS_DD)
+      /*this already returns a meter*/
+      $distance = distHaversine($x1,$y1, $x2,$y2);
+    else
+    {
+        $distance = sqrt (pow(($x2 - $x1),2) + pow(($y2 - $y1),2));
+        /*convert to meter*/
+        $distance = GetMetersPerUnit($oMap->units)*$distance;
+    }
+      
     header('Content-type: text/x-json');
     header('X-JSON: true');
     echo "{distance:$distance}";
@@ -64,4 +68,46 @@
     echo $e->GetDetails() . "\n";
     echo $e->GetStackTrace() . "\n";
 }
-?>
\ No newline at end of file
+
+
+
+/************************************************************************/
+/*         Calculate distance in meters fro 2 lat/long coordinates.     */
+/*      Comes from http://www.movable-type.co.uk/scripts/latlong.html   */
+/************************************************************************/
+function distHaversine($lon1, $lat1, $lon2, $lat2) 
+{
+  $R = 6371000; // earth's mean radius in m
+  $dLat = ($lat2-$lat1)*(M_PI/180);//toRad();
+  $dLon = ($lon2-$lon1)*(M_PI/180);//.toRad();
+  $lat1 = $lat1*(M_PI/180);
+  $lat2 = $lat2*(M_PI/180);
+
+  $a = sin($dLat/2) * sin($dLat/2) +
+          cos($lat1) * cos($lat2) * 
+          sin($dLon/2) * sin($dLon/2);
+  $c = 2 * atan2(sqrt($a), sqrt(1-$a));
+  $d = $R * $c;
+  return $d;
+}
+
+function GetMetersPerUnit($unit)       //, $center_y)
+{
+  if ($unit == MS_INCHES)
+    return 0.0254;
+  else if ($unit == MS_FEET)
+    return 0.3048;
+  else if ($unit == MS_MILES)
+    return 1609.344;
+  else if ($unit == MS_METERS)
+    return 1;
+  else if ($unit == MS_KILOMETERS)
+      return 1000;
+  else if ($unit == MS_DD)
+    return (111118.7516);
+    
+    else if ($unit == MS_PIXELS)
+      return 1;
+}
+
+?>


Property changes on: sandbox/aboudreault/MapServer/php/Measure.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/MapServer/php/Query.php
===================================================================
--- sandbox/aboudreault/MapServer/php/Query.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/Query.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -228,7 +228,7 @@
               array_push($selFields, $key);
 
               //we check if an alias if provided
-              if (isset($aQueryItems[$key]) && ($aQueryItems[$key] != ""))
+              if (isset($aQueryItems[$key]) && ($keyAlias != ""))
                 $key = $aQueryItems[$key];
 
               array_push($properties->$layerName->propertynames, $key);

Deleted: sandbox/aboudreault/MapServer/php/Search.php
===================================================================
--- sandbox/aboudreault/MapServer/php/Search.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/Search.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,259 +0,0 @@
-<?php
-/**
- * Search
- *
- * $Id: Search.php 1108 2007-12-11 00:27:33Z aboudreault at mapgears.com $
- *
- * Copyright (c) 2007, DM Solutions Group Inc.
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/*****************************************************************************
- * Purpose: create a query by attributes
- *****************************************************************************/
-
-/* set up the session */
-include ("Common.php");
-include ("Utilities.php");
-include('../../common/php/Utilities.php');
-
-/* the name of the layer in the map to query */
-if ( ($_REQUEST['layer'] != '') && ($_REQUEST['attribute'] != '') && ($_REQUEST['pattern'] != ''))  {
-    $szLayer = $_REQUEST['layer'];
-    $szAttribute = $_REQUEST['attribute'];
-    $szPattern = $_REQUEST['pattern'];
-} 
-else 
-{
-    die('layer, attribute or value not set');
-}
-
-if (!isset($mapName)) {
-    die('mapname not set');
-}
-if (isset($_SESSION['maps']) && isset($_SESSION['maps'][$mapName])) {
-    $oMap = ms_newMapObj($_SESSION['maps'][$mapName]);
-}
-
-$iMatchLimit = (int) $_REQUEST['matchlimit']; 
-
-$result = NULL;
-$result->hasSelection = false;
-$result->layers = array();
-
-$oLayer = $oMap->GetLayerByName($szLayer);
-
-if (@$oLayer->queryByAttributes($szAttribute,$szPattern, MS_MULTIPLE) == MS_SUCCESS)
-{
-    if ( ($iMatchLimit != -1) && ($oLayer->getNumResults() > $iMatchLimit) )
-        $numResults = $iMatchLimit;
-    else
-        $numResults = $oLayer->getNumResults();
-
-    $result->hasSelection = true;
-    $layerName = $oLayer->name;
-    array_push($result->layers, $layerName);
-    $result->$layerName->featureCount = $numResults;
-}
-
-
-header('Content-type: text/x-json');
-header('X-JSON: true');
-if ($result->hasSelection) 
-{
-    $oMap->savequery(getSessionSavePath()."query.qry");
-    $result->queryFile = getSessionSavePath()."query.qry";
-
-    //holds selection array
-    $properties = NULL;
-    $properties->layers = array();
-
-    $totalminx = 0;
-    $totalminy = 0;
-    $totalmaxx = 0;
-    $totalmaxy = 0;
-    
-    $bFirstElement = 1;
-    
-    $oLayer->open(); 
-
-    array_push($properties->layers, $layerName);
-    $properties->$layerName->numelements = $numResults;
-
-    $properties->$layerName->propertynames = array();
-    $properties->$layerName->propertyvalues = array();
-    $properties->$layerName->propertytypes = array();
-    $properties->$layerName->values = array();
-
-    $properties->$layerName->metadatanames= array();
-    array_push($properties->$layerName->metadatanames, 'dimension');
-    array_push($properties->$layerName->metadatanames, 'bbox');
-    array_push($properties->$layerName->metadatanames, 'center');
-    array_push($properties->$layerName->metadatanames, 'area');
-    array_push($properties->$layerName->metadatanames, 'length');
-
-    //get first shape to get the attributes
-    $oResultSet = $oLayer->getResult(0);
-    $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
-    $selFields = array();
-    
-    if (isset($_SESSION[$mapName][$layerName]['query_items']))
-    {
-        $aQueryItems = $_SESSION[$mapName][$layerName]['query_items'];
-    }
-    else
-    {
-        //token separator (for parsing displayed attributes on a query)
-        $tokenSeparator = ","; 
-        // checking if metadata "query_include_items" is set
-        $metadataItems = $oLayer->getMetaData('query_include_items');
-        if ( ($metadataItems == "") || ($metadataItems == "all") )
-        {
-            while ( list($key,$val) = each($oShape->values) )
-            {
-                $aQueryItems[$key]  = NULL;
-            }
-        }
-        else
-        {
-            $token = strtok($metadataItems, $tokenSeparator);
-            while ($token !== false) 
-            {
-                $aQueryItems[$token] = NULL;
-                $token = strtok($tokenSeparator);
-            }
-        }
-        
-        // checking if metadata "query_exclude_items" is set
-        $metadataItems = $oLayer->getMetaData('query_exclude_items');
-        if ($metadataItems != "")
-        {
-            $token = strtok($metadataItems, $tokenSeparator);
-            while ($token !== false) 
-            {
-                if (array_key_exists($token, $aQueryItems))
-                    unset($aQueryItems[$token]);
-                $token = strtok($tokenSeparator);
-            }
-        }
-        
-        // get all alias
-        while ( list($key,$val) = each($aQueryItems) )
-        {
-            $keyAlias = $oLayer->getMetaData("query_".$key."_alias");
-            trim($keyAlias);
-            if ($keyAlias != "")
-                $aQueryItems[$key] = $keyAlias;
-        }
-        $_SESSION[$mapName][$layerName]['query_items'] = $aQueryItems;
-    }
-    $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
-
-    while ( list($key,$val) = each($oShape->values) )
-    {
-        if (array_key_exists($key, $aQueryItems))
-        {
-            array_push($selFields, $key);
-
-            //we check if an alias if provided
-            if (isset($aQueryItems[$key]) && ($aQueryItems[$key] != ""))
-                $key = $aQueryItems[$key];
-
-            array_push($properties->$layerName->propertynames, $key);
-            array_push($properties->$layerName->propertyvalues, $val);
-
-            array_push($properties->$layerName->propertytypes, 0);
-        }
-        
-    }
-    
-    
-    for ($iRes=0; $iRes < $numResults; $iRes++)
-    {
-        $properties->$layerName->values[$iRes] = array();
-        $properties->$layerName->metadata[$iRes] = array();
-
-        $oResultSet = $oLayer->getResult($iRes);
-        $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
-        //TODO : area, length and distance are not set
-        $minx =  $oShape->bounds->minx;
-        $miny =  $oShape->bounds->miny;
-        $maxx =  $oShape->bounds->maxx;
-        $maxy =  $oShape->bounds->maxy;
-
-        if ($bFirstElement)
-        {
-            $bFirstElement = 0;
-            $totalminx =  $minx;
-            $totalminy =  $miny;
-            $totalmaxx =  $maxx;
-            $totalmaxy =  $maxy;
-        }
-        else
-        {
-            if ($totalminx > $minx)
-                $totalminx = $minx;
-            if ($totalminy > $miny)
-                $totalminy = $miny;
-            if ($totalmaxx < $maxx)
-                $totalmaxx = $maxx;
-            if ($totalmaxy < $maxy)
-                $totalmaxy = $maxy;
-        }
-
-        //metadata : TODO dimension, area, length and distance are not set
-        $dimension = 0;
-        $center = 0;
-        $area = 0;
-        $length = 0;
-        $bbox = $minx.','.$miny.','.$maxx.','.$maxy;
-
-        array_push($properties->$layerName->metadata[$iRes], $dimension);
-        array_push($properties->$layerName->metadata[$iRes], $bbox);
-        array_push($properties->$layerName->metadata[$iRes], $center);
-        array_push($properties->$layerName->metadata[$iRes], $area);
-        array_push($properties->$layerName->metadata[$iRes], $length);
-
-        //field values
-        for($iField=0; $iField < count($selFields); $iField++)
-        {
-            $value = $oShape->values[$selFields[$iField]];
-            //$value = preg_replace( "/\r?\n/", "<br>", $value );
-            $value = str_replace("'", "\'", $value);
-            array_push($properties->$layerName->values[$iRes], $value);
-        }
-    }
-
-    $oLayer->close();
-
-    //extents
-    $properties->extents = NULL;
-    $properties->extents->minx = $totalminx;
-    $properties->extents->miny = $totalminy;
-    $properties->extents->maxx = $totalmaxx;
-    $properties->extents->maxy = $totalmaxy;
-
-    //save selection in the session
-    $_SESSION['selection_array'] = $properties; 
-}
-
-echo var2json($result);
-
-?>
-

Added: sandbox/aboudreault/MapServer/php/Search.php
===================================================================
--- sandbox/aboudreault/MapServer/php/Search.php	                        (rev 0)
+++ sandbox/aboudreault/MapServer/php/Search.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,259 @@
+<?php
+/**
+ * Search
+ *
+ * $Id: Search.php 1108 2007-12-11 00:27:33Z aboudreault at mapgears.com $
+ *
+ * Copyright (c) 2007, DM Solutions Group Inc.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*****************************************************************************
+ * Purpose: create a query by attributes
+ *****************************************************************************/
+
+/* set up the session */
+include ("Common.php");
+include ("Utilities.php");
+include('../../common/php/Utilities.php');
+
+/* the name of the layer in the map to query */
+if ( ($_REQUEST['layer'] != '') && ($_REQUEST['attribute'] != '') && ($_REQUEST['pattern'] != ''))  {
+    $szLayer = $_REQUEST['layer'];
+    $szAttribute = $_REQUEST['attribute'];
+    $szPattern = $_REQUEST['pattern'];
+} 
+else 
+{
+    die('layer, attribute or value not set');
+}
+
+if (!isset($mapName)) {
+    die('mapname not set');
+}
+if (isset($_SESSION['maps']) && isset($_SESSION['maps'][$mapName])) {
+    $oMap = ms_newMapObj($_SESSION['maps'][$mapName]);
+}
+
+$iMatchLimit = (int) $_REQUEST['matchlimit']; 
+
+$result = NULL;
+$result->hasSelection = false;
+$result->layers = array();
+
+$oLayer = $oMap->GetLayerByName($szLayer);
+
+if (@$oLayer->queryByAttributes($szAttribute,$szPattern, MS_MULTIPLE) == MS_SUCCESS)
+{
+    if ( ($iMatchLimit != -1) && ($oLayer->getNumResults() > $iMatchLimit) )
+        $numResults = $iMatchLimit;
+    else
+        $numResults = $oLayer->getNumResults();
+
+    $result->hasSelection = true;
+    $layerName = $oLayer->name;
+    array_push($result->layers, $layerName);
+    $result->$layerName->featureCount = $numResults;
+}
+
+
+header('Content-type: text/x-json');
+header('X-JSON: true');
+if ($result->hasSelection) 
+{
+    $oMap->savequery(getSessionSavePath()."query.qry");
+    $result->queryFile = getSessionSavePath()."query.qry";
+
+    //holds selection array
+    $properties = NULL;
+    $properties->layers = array();
+
+    $totalminx = 0;
+    $totalminy = 0;
+    $totalmaxx = 0;
+    $totalmaxy = 0;
+    
+    $bFirstElement = 1;
+    
+    $oLayer->open(); 
+
+    array_push($properties->layers, $layerName);
+    $properties->$layerName->numelements = $numResults;
+
+    $properties->$layerName->propertynames = array();
+    $properties->$layerName->propertyvalues = array();
+    $properties->$layerName->propertytypes = array();
+    $properties->$layerName->values = array();
+
+    $properties->$layerName->metadatanames= array();
+    array_push($properties->$layerName->metadatanames, 'dimension');
+    array_push($properties->$layerName->metadatanames, 'bbox');
+    array_push($properties->$layerName->metadatanames, 'center');
+    array_push($properties->$layerName->metadatanames, 'area');
+    array_push($properties->$layerName->metadatanames, 'length');
+
+    //get first shape to get the attributes
+    $oResultSet = $oLayer->getResult(0);
+    $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
+    $selFields = array();
+    
+    if (isset($_SESSION[$mapName][$layerName]['query_items']))
+    {
+        $aQueryItems = $_SESSION[$mapName][$layerName]['query_items'];
+    }
+    else
+    {
+        //token separator (for parsing displayed attributes on a query)
+        $tokenSeparator = ","; 
+        // checking if metadata "query_include_items" is set
+        $metadataItems = $oLayer->getMetaData('query_include_items');
+        if ( ($metadataItems == "") || ($metadataItems == "all") )
+        {
+            while ( list($key,$val) = each($oShape->values) )
+            {
+                $aQueryItems[$key]  = NULL;
+            }
+        }
+        else
+        {
+            $token = strtok($metadataItems, $tokenSeparator);
+            while ($token !== false) 
+            {
+                $aQueryItems[$token] = NULL;
+                $token = strtok($tokenSeparator);
+            }
+        }
+        
+        // checking if metadata "query_exclude_items" is set
+        $metadataItems = $oLayer->getMetaData('query_exclude_items');
+        if ($metadataItems != "")
+        {
+            $token = strtok($metadataItems, $tokenSeparator);
+            while ($token !== false) 
+            {
+                if (array_key_exists($token, $aQueryItems))
+                    unset($aQueryItems[$token]);
+                $token = strtok($tokenSeparator);
+            }
+        }
+        
+        // get all alias
+        while ( list($key,$val) = each($aQueryItems) )
+        {
+            $keyAlias = $oLayer->getMetaData("query_".$key."_alias");
+            trim($keyAlias);
+            if ($keyAlias != "")
+                $aQueryItems[$key] = $keyAlias;
+        }
+        $_SESSION[$mapName][$layerName]['query_items'] = $aQueryItems;
+    }
+    $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
+
+    while ( list($key,$val) = each($oShape->values) )
+    {
+        if (array_key_exists($key, $aQueryItems))
+        {
+            array_push($selFields, $key);
+
+            //we check if an alias if provided
+            if (isset($aQueryItems[$key]) && ($aQueryItems[$key] != ""))
+                $key = $aQueryItems[$key];
+
+            array_push($properties->$layerName->propertynames, $key);
+            array_push($properties->$layerName->propertyvalues, $val);
+
+            array_push($properties->$layerName->propertytypes, 0);
+        }
+        
+    }
+    
+    
+    for ($iRes=0; $iRes < $numResults; $iRes++)
+    {
+        $properties->$layerName->values[$iRes] = array();
+        $properties->$layerName->metadata[$iRes] = array();
+
+        $oResultSet = $oLayer->getResult($iRes);
+        $oShape = $oLayer->getShape($oResultSet->tileindex,$oResultSet->shapeindex);
+        //TODO : area, length and distance are not set
+        $minx =  $oShape->bounds->minx;
+        $miny =  $oShape->bounds->miny;
+        $maxx =  $oShape->bounds->maxx;
+        $maxy =  $oShape->bounds->maxy;
+
+        if ($bFirstElement)
+        {
+            $bFirstElement = 0;
+            $totalminx =  $minx;
+            $totalminy =  $miny;
+            $totalmaxx =  $maxx;
+            $totalmaxy =  $maxy;
+        }
+        else
+        {
+            if ($totalminx > $minx)
+                $totalminx = $minx;
+            if ($totalminy > $miny)
+                $totalminy = $miny;
+            if ($totalmaxx < $maxx)
+                $totalmaxx = $maxx;
+            if ($totalmaxy < $maxy)
+                $totalmaxy = $maxy;
+        }
+
+        //metadata : TODO dimension, area, length and distance are not set
+        $dimension = 0;
+        $center = 0;
+        $area = 0;
+        $length = 0;
+        $bbox = $minx.','.$miny.','.$maxx.','.$maxy;
+
+        array_push($properties->$layerName->metadata[$iRes], $dimension);
+        array_push($properties->$layerName->metadata[$iRes], $bbox);
+        array_push($properties->$layerName->metadata[$iRes], $center);
+        array_push($properties->$layerName->metadata[$iRes], $area);
+        array_push($properties->$layerName->metadata[$iRes], $length);
+
+        //field values
+        for($iField=0; $iField < count($selFields); $iField++)
+        {
+            $value = $oShape->values[$selFields[$iField]];
+            //$value = preg_replace( "/\r?\n/", "<br>", $value );
+            $value = str_replace("'", "\'", $value);
+            array_push($properties->$layerName->values[$iRes], $value);
+        }
+    }
+
+    $oLayer->close();
+
+    //extents
+    $properties->extents = NULL;
+    $properties->extents->minx = $totalminx;
+    $properties->extents->miny = $totalminy;
+    $properties->extents->maxx = $totalmaxx;
+    $properties->extents->maxy = $totalmaxy;
+
+    //save selection in the session
+    $_SESSION['selection_array'] = $properties; 
+}
+
+echo var2json($result);
+
+?>
+

Modified: sandbox/aboudreault/MapServer/php/SetLayers.php
===================================================================
--- sandbox/aboudreault/MapServer/php/SetLayers.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/MapServer/php/SetLayers.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * SetLayers
  *
- * $Id: Selection.php 963 2007-10-16 15:37:30Z madair $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/MapServer/php/SetLayers.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/build.xml
===================================================================
--- sandbox/aboudreault/build.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/build.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -123,6 +123,7 @@
                       redist/** 
                       samples/** 
                       templates/** 
+                      text/** 
                       widgets/**"
             excludes="selenium/**"
        />
@@ -145,25 +146,38 @@
     <mkdir dir="${build.home}/docs/NaturalDocs"/>
     
     <echo message="Generating documentation"/>
-    <exec executable="cmd" os="Windows Vista" dir="${build.home}">
-        <!--arg value="/c"/>
-        <arg value="NaturalDocs.bat"/>
+    <exec executable="cmd" os="Windows Vista, Windows XP" dir="${build.home}">
+	<!--
+        <arg value="/c"/>
+		<arg value="NaturalDocs.bat"/>
         <arg value="-i ./"/>
         <arg value="-o html ./docs"/>
         <arg value="-p ./docs/NaturalDocs"/>
         <arg value="-xi ./scriptaculous"/>
         <arg value="-xi ./lib"/>
-        <arg value="-r"/-->
+        <arg value="-r"/>
+		-->
         <arg line="/c perl C:\Progra~1\NaturalDocs\NaturalDocs -i ./lib -i ./widgets -o html ./docs/NaturalDocs -p ./docs/NaturalDocs -r"/>
     </exec>
   </target>
+    
+  <!--
+  <target description="Create documentation" name="docs2" depends="prepare">
+    <delete dir="${build.home}/docs/widgetinfo"/>
+    <mkdir dir="${build.home}/docs/widgetinfo"/>
+    <xslt basedir="${basedir}/widgets/widgetinfo" 
+          destdir="${build.home}/docs/widgetinfo"
+          style="${basedir}/widgets/widgetinfo/widgetInfo.xsl" 
+          excludes="WidgetInfoTemplate.xml widgetInfo.xsl"/>
+  </target>
+  -->
 
   
 <!-- =================== Compress Target ================================== -->
 
   <target description="Compress JS files" name="compress" depends="prepare">
     <echo message="Concatenating into -lib version"/>
-    <concat destfile="${build.home}/lib/fusion-combined.js">
+    <concat destfile="${build.home}/lib/fusion-combined.js" outputencoding="UTF-8">
         <filelist dir="${build.home}/lib" 
         files=" utils.js 
                 Error.js 
@@ -181,10 +195,11 @@
                 />
         <fileset dir="${build.home}/MapGuide" includes="*.js"/>
         <fileset dir="${build.home}/MapServer" includes="*.js"/>
+        <fileset dir="${build.home}/text" includes="**/*.json"/>
         <fileset dir="${build.home}/widgets" includes="*.js **/*.js" excludes="Recenter.js"/>
     </concat>
     <echo message="compressing..."/>
-    <exec executable="jsmin.exe" os="Windows Vista" 
+    <exec executable="jsmin.exe" os="Windows Vista, Windows XP" 
       input="${build.home}/lib/fusion-combined.js" output="${build.home}/lib/fusion-compressed.js"/>
   </target>
 

Modified: sandbox/aboudreault/config.json
===================================================================
--- sandbox/aboudreault/config.json	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/config.json	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,34 +1,37 @@
 /* This is the fusion configuration file.  Adjust as necessary. */
-{ 
-    /* The general section contains settings that are general to 
+{
+    /* The general section contains settings that are general to
        fusion as a whole. */
-    general: {
-	    /* PHP is the default and only script language supported.  
-	       Don't change this. */
-	    scriptLanguage: 'php',
-	    
+    "general": {
+	    /* PHP is the default and only script language supported.
+	       Don"t change this. */
+	    "scriptLanguage": "php",
+
 	    /* A directory on this system that fusion can use for
 	       temporary files. */
-	    temporaryDirectory: '/tmp'
+	    "temporaryDirectory": "/tmp"
     },
-    /* The MapGuide section is required if you are installing 
+    /* The MapGuide section is required if you are installing
        fusion for MapGuide. */
-    mapguide: {
-	    /* The WebTierURL is the url to mapguide, it should start 
-	       with http and end with /mapguide.  If you have installed 
+    "mapguide": {
+	    /* The WebTierURL is the url to mapguide, it should start
+	       with http and end with /mapguide.  If you have installed
 	       fusion inside the www directory of MapGuide, then you can
 	       leave this empty as it will be automatically calculated. */
-           webTierUrl: ''
+           "webTierUrl": ""
     },
     /* The MapServer section is required if you are installing fusion
        for MapServer. */
-   mapserver: {
+   "mapserver": {
 	    /* The URL of the mapserver CGI that you want to use.  */
-	    cgi: '/cgi-bin/mapserv',
+	    "cgi": "/cgi-bin/mapserv",
 	    /* The file system path to where mapserver should put
 	        web-accessible temporary images. */
-	    imagePath: '/tmp/ms_tmp',
+	    "imagePath": "/tmp/ms_tmp",
 	    /* The URL to the image path configured above. */
-	    imageUrl: 'http://localhost/tmp/ms_tmp'
+	    "imageUrl": "http://localhost/tmp/ms_tmp",
+	    /* The file system path to where mapserver should put
+	        web-accessible temporary legend images. */
+	    "legendIconCacheDir":"/tmp/ms_tmp"
     }
 }
\ No newline at end of file


Property changes on: sandbox/aboudreault/config.json
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/containerinfo/contextmenu.xml
===================================================================
--- sandbox/aboudreault/containerinfo/contextmenu.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/containerinfo/contextmenu.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,5 +2,5 @@
 <Type>ContextMenu</Type>
 <LocalizedType>Menu</LocalizedType>
 <Description>A context menu to contain menu items to perform various tasks</Description>
-<PreviewImageUrl>fusion/containerinfo/menu.gif</PreviewImageUrl>
+<PreviewImageUrl>fusion/containerinfo/menu.png</PreviewImageUrl>
 </ContainerInfo>


Property changes on: sandbox/aboudreault/containerinfo/contextmenu.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Deleted: sandbox/aboudreault/containerinfo/menu.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/containerinfo/menu.png (from rev 1352, trunk/containerinfo/menu.png)
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/containerinfo/splitterbar.png (from rev 1352, trunk/containerinfo/splitterbar.png)
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/containerinfo/splitterbar.xml (from rev 1352, trunk/containerinfo/splitterbar.xml)
===================================================================
--- sandbox/aboudreault/containerinfo/splitterbar.xml	                        (rev 0)
+++ sandbox/aboudreault/containerinfo/splitterbar.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,6 @@
+<ContainerInfo>
+<Type>Splitterbar</Type>
+<LocalizedType>Splitter Bar</LocalizedType>
+<Description>A splitter bar to contain controls to display status items</Description>
+<PreviewImageUrl>fusion/containerinfo/splitterbar.png</PreviewImageUrl>
+</ContainerInfo>

Deleted: sandbox/aboudreault/containerinfo/toolbar.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/containerinfo/toolbar.png (from rev 1352, trunk/containerinfo/toolbar.png)
===================================================================
(Binary files differ)

Modified: sandbox/aboudreault/containerinfo/toolbar.xml
===================================================================
--- sandbox/aboudreault/containerinfo/toolbar.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/containerinfo/toolbar.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <ContainerInfo>
 <Type>Toolbar</Type>
+<LocalizedType>Toolbar</LocalizedType>
 <Description>A toolbar to contain buttons to perform various tasks</Description>
-<PreviewImageUrl>fusion/containerinfo/toolbar.gif</PreviewImageUrl>
+<PreviewImageUrl>fusion/containerinfo/toolbar.png</PreviewImageUrl>
 </ContainerInfo>


Property changes on: sandbox/aboudreault/containerinfo/toolbar.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/docs/ApplicationDefinition-1.0.0.xsd
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/docs/ApplicationDefinition.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/fusion.cfg
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Copied: sandbox/aboudreault/jx (from rev 1352, trunk/jx)

Deleted: sandbox/aboudreault/jx/JX_VERSION.txt
===================================================================
--- trunk/jx/JX_VERSION.txt	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/JX_VERSION.txt	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +0,0 @@
-Jx is an open source library available from http://jxlib.org/.  A copy of a specific version of Jx is included with Fusion.  The current version is:
-
-Jx 1.0.3
-
-You may replace jx with any version including an svn version.  However, Fusion may not work with newer versions.  Also, Fusion requires the combined or compressed version of Jx.  See Jx documentation for information on building the combined and compressed versions.
\ No newline at end of file

Copied: sandbox/aboudreault/jx/JX_VERSION.txt (from rev 1352, trunk/jx/JX_VERSION.txt)
===================================================================
--- sandbox/aboudreault/jx/JX_VERSION.txt	                        (rev 0)
+++ sandbox/aboudreault/jx/JX_VERSION.txt	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,5 @@
+Jx is an open source library available from http://jxlib.org/.  A copy of a specific version of Jx is included with Fusion.  The current version is:
+
+Jx 1.0.3
+
+You may replace jx with any version including an svn version.  However, Fusion may not work with newer versions.  Also, Fusion requires the combined or compressed version of Jx.  See Jx documentation for information on building the combined and compressed versions.
\ No newline at end of file

Copied: sandbox/aboudreault/jx/css (from rev 1352, trunk/jx/css)

Deleted: sandbox/aboudreault/jx/css/jxskin-border.css
===================================================================
--- trunk/jx/css/jxskin-border.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/css/jxskin-border.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,720 +0,0 @@
-/**
- * @project         Jx
- * @revision        $Id: jxskin-border.css 512 2008-03-07 21:15:45Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* =================================== */
-/* VISUAL STYLES W. BORDERS AND COLORS */
-/* =================================== */
-
-
-/* ============= */
-/* DIALOG STYLES */
-/* ============= */
-
-.jxDialogContainer {
-}
-
-.jxDialog {
-    border: 1px solid #666;
-    background-color: #d9d9d9;
-    margin: 6px;
-}
-
-.jxDialogModal {
-    background-color: #000;
-    opacity: .2;
-    -moz-opacity: .2;
-    filter: Alpha(opacity=20);
-}
-
-.jxDialogBgTL {
-    top: 0px;
-    left: 0px;
-}
-
-.jxDialogBgTL img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgT {
-    top: 0px;
-    left: 12px;
-}
-
-.jxDialogBgT img {
-    height: 12px;
-}
-
-.jxDialogBgTR {
-    top: 0px;
-    right: 0px;
-}
-
-.jxDialogBgTR img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgR {
-    top: 12px;
-    right: 0px;
-}
-
-.jxDialogBgR img {
-    width: 12px;
-}
-
-.jxDialogBgBR {
-    bottom: 0px;
-    right: 0px;
-}
-
-.jxDialogBgBR img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgB {
-    bottom: 0px;
-    left: 12px;
-}
-
-.jxDialogBgB img {
-    height: 12px;
-}
-
-.jxDialogBgBL {
-    bottom: 0px;
-    left: 0px;
-}
-
-.jxDialogBgBL img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgL {
-    top: 12px;
-    left: 0px;
-}
-
-.jxDialogBgL img {
-    width: 12px;
-}
-
-.jxDialogTitle {
-    background-color: #ccc;
-    border-top: 1px solid #fff;
-    border-left: 1px solid #fff;
-    border-bottom: 1px solid #999;
-    font-family: Arial, Helvetica, sans-serif;
-    font-weight: bold;
-    font-size: 12px;
-    text-align: center;
-    height: 22px;
-    line-height: 22px;
-    cursor: move;
-}
-
-.jxDialogContent {
-    border-top: 1px solid #fff;
-    border-left: 1px solid #fff;
-    padding: 0px;
-}
-
-.jxDialogAction {
-    border-left: 1px solid #fff;
-    height: 30px;
-    text-align: right;
-    margin-right:15px;
-}
-
-.jxDialogAction input {
-    margin: 5px;
-    margin-left:0px;
-}
-
-.jxDialogCloseButton, 
-.jxDialogHelpButton {
-    width: 20px;
-    height: 20px;
-    top: 0px;
-    right: 2px;
-    padding: 0px;
-    margin: 0px; 
-    border: 0px;
-}
-
-.jxDialogHelpButton {
-  right: 22px;
-}
-
-.jxDialogCloseButton img, 
-.jxDialogHelpButton img {
-  border: 0px;
-  /* the margin needs to make up the difference between it's width/height
-     and the width/height of the parent a */
-  margin: 0px;
-  /* width/height has to be the actual image width/height */
-  width: 20px;
-  height: 20px;
-}
-
-.jxDialogResize {
-    width: 20px;
-    height: 20px;
-/*    bottom: 0px;
-    right: 0px; */
-    border: 0px;
-    cursor: se-resize;
-    background-image: url(../images/dialog_resize.png);
-}
-
-
-/* ================= */
-/* JX TOOLBAR STYLES */
-/* ================= */
-
-.jxToolbarContainer {
-  margin: 0px;
-  padding: 0px;
-  border: 0px;
-  /* simulates an underline at the bottom of the container*/
-  background-image:url(../images/container_bg.png); 
-  background-color: #d9d9d9;
-}
-
-/* Horizontally oriented toolbars */
-.jxBarTop, 
-.jxBarBottom {
-  background-repeat:repeat-x;
-  background-position: bottom;
-}
-
-/* Vertically oriented toolbars */
-.jxBarLeft, 
-.jxBarRight {
-  background-repeat:repeat-y;
-  background-position: right;
-}
-
-.toolbarLabel {
-  margin: 0px;
-  padding: 0px;
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 11px;
-  line-height: 24px;
-  color: #000;
-}
-
-ul.jxToolbar {
-  margin: 0px;  /* margins don't seem to work properly in IE */
-  padding: 0px;
-}
-
-.jxBarTop ul.jxToolbar, 
-.jxBarBottom ul.jxToolbar {
-  border-left: 1px solid #fff;
-  border-right: 1px solid #999;
-  border-top: 1px solid #fff;
-}
-
-.jxBarLeft ul.jxToolbar, 
-.jxBarRight ul.jxToolbar {
-  border-left: 1px solid #fff;
-  border-top: 1px solid #fff;
-  border-bottom: 1px solid #999;
-}
-
-li.jxToolItem {
-  padding: 0px;
-  margin: 0px;  /* margins don't seem to work properly in IE */
-}
-
-.jxBarTop li.jxToolItem, 
-.jxBarBottom li.jxToolItem {
-  border-top: none;
-  border-right: none;
-  border-bottom: 1px solid #999;
-  border-left: none;
-}
-
-.jxBarLeft li.jxToolItem, 
-.jxBarRight li.jxToolItem {
-  border-top: none;
-  border-right: 1px solid #999;
-  border-bottom: none;
-  border-left: none;
-}
-
-li.jxToolItem  span.separator {
-  /* width/height should be defined */
-  width: 8px;
-  height: 18px;
-  border: 0px;
-  margin: 0px;  /* margins don't seem to work properly in IE */
-  padding: 4px;
-  background-repeat: no-repeat;
-  background-position: center center;
-}
-
-.jxBarTop  li.jxToolItem  span.separator, 
-.jxBarBottom  li.jxToolItem  span.separator {
-  background-image: url(../images/toolbar_separator_h.png);
-}
-
-.jxBarLeft  li.jxToolItem  span.separator, 
-.jxBarRight  li.jxToolItem  span.separator {
-  background-image: url(../images/toolbar_separator_v.png);
-}
-
-
-/* ================ */
-/* JX BUTTON STYLES */
-/* ================ */
-
-div.jxButtonContainer {
-  margin: 0px;
-  padding: 0px;
-  border: none;
-}
-
-a.jxButton {
-  /* If using background images, the A contains the left side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 6px;*/ /* makes room for the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 4px; 
-  border: 1px solid #d9d9d9;
-  background-repeat: no-repeat;
-  text-decoration: none;
-}
-
-a.jxButton:hover {
-  border-top: 1px solid #fff;
-  border-left: 1px solid #fff;
-  border-bottom: 1px solid #999;
-  border-right: 1px solid #999;
-}
-
-a.jxButton:active {
-  border-bottom: 1px solid #fff;
-  border-right: 1px solid #fff;
-  border-top: 1px solid #999;
-  border-left: 1px solid #999;
-}
-
-a.jxButtonActive {
-  background-color: #f0f0f0;
-  border-bottom: 1px solid #fff;
-  border-right: 1px solid #fff;
-  border-top: 1px solid #999;
-  border-left: 1px solid #999;
-}
-
-a.jxButtonActive:hover {
-  border-bottom: 1px solid #fff;
-  border-right: 1px solid #fff;
-  border-top: 1px solid #999;
-  border-left: 1px solid #999;
-}
-
-a.jxButtonActive:active {
-  border-bottom: 1px solid #fff;
-  border-right: 1px solid #fff;
-  border-top: 1px solid #999;
-  border-left: 1px solid #999;
-}
-
-.jxDisabled a.jxButton:hover, 
-.jxDisabled a.jxButton:active {
-  border: 1px solid #d9d9d9;
-}
-
-span.jxButtonSpan {
-  /* If using background images, the SPAN contains the right side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 0px;
-  background-repeat: no-repeat;
-}
-
-/* colour swatch styles
-   smaller image with borders */
-img.jxButtonSwatch {
-  width: 14px;
-  height: 14px;
-  border: 1px solid #000;
-}
-
-a.jxButtonMenu span.jxButtonSpan, 
-a.jxButtonFlyout span.jxButtonSpan {
-  background-image: url(../images/menu_item_arrow_d2.png);
-  background-position: right center;
-  background-repeat: no-repeat;
-}
-
-span.jxButtonContent {
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 16px;
-  line-height: 16px;
-}
-
-a.jxButtonMenu span.jxButtonContent, 
-a.jxButtonFlyout span.jxButtonContent {
-  padding-right: 16px;
-}
-
-span.jxButtonLabel {
-  /* If using background images, the SPAN contains the right side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 0px 4px;
-  color: #000;
-  background-position: right center;
-  background-repeat: no-repeat;
-  font-size: 11px;
-}
-
-.jxMenu span.jxButtonLabel,
-.jxSubMenu span.jxButtonLabel {
-  /* TODO: this is just really not right.  The padding-right value should be
-     20px but the label is collapsing somehow ... we'll need to investigate
-     why at some point, but not today!
-  */
-  padding-right: 30px;
-}
-
-span.jxButtonIcon {
-  padding-left: 14px;
-  background-position: left center;
-  background-repeat: no-repeat;
-}
-
-span.jxButtonIcon.jxButtonLabel {
-  padding-left: 22px;
-}
-
-.jxFlyout {
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-  background-color: #fff;
-  /* because of jxToolbarItem */
-  font-size: 12px;
-  line-height: 14px;
-}
-
-.jxFlyout .jxBarRight,
-.jxFlyout .jxBarLeft {
-  float: left;
-  height: auto;
-  width: auto;
-} 
-
-a.jxButtonMulti {
-  padding-left: 0px;
-  padding-right: 0px;
-}
-
-a.jxButtonMulti span.jxButtonSpan {
-  padding-left: 0px;
-  padding-right: 16px;
-}
-
-a.jxButtonMulti span.jxButtonLabel {
-  padding-left: 0px;
-  padding-right: 0px;
-}
-
-a.jxButtonColor span.jxButtonSpan {
-  padding-left: 2px;
-  padding-right: 16px;
-}
-a.jxButtonColor span.jxButtonLabel {
-  padding-left: 0px;
-  padding-right: 0px;
-}
-
-/* ============= */
-/* JX TAB STYLES */
-/* ============= */
-
-.jxTabSetContainer {
-  /* This is an example of a container that can be used to hold a tabBox
-     the position need to be explicitly set, as well as the width and height. */
-  width: 200px;
-  height: 200px;
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-}
-
-.tabContent {
-}
-
-.tabContentActive {
-  display: block;
-}
-
-.jxTabSetContainer .jxToolbarContainer, 
-.jxTabSetContainer ul.jxToolbar {
-  border: none;
-}
-
-/* The tabbar is built out of a UL
-   The tab background uses the sliding door technique so tabs can expand to
-   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
-   (left/right tabs).  All parts and states of the tab BG graphics are in the 
-   same image so they can be treated like sprites.
-
-   Horizontal tabs can contain text or an image label.  Vertical tabs need an
-   image label.
-*/
-
-li.jxTabItem {
-  margin: 0px;
-  padding: 0px;
-}
-
-.jxBarTop li.jxTabItem, 
-.jxBarBottom li.jxTabItem {
-  border: none;
-}
-
-.jxBarLeft li.jxTabItem, 
-.jxBarRight li.jxTabItem {
-  border: none;
-}
-
-
-a.jxTab {
-  /* The A contains one side of the tab background image */
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999; /* same color as the tabBox border */
-  background-repeat: no-repeat;
-  text-decoration: none;
-  color: #000;
-}
-
-a.jxTab:hover {
-  background-color: #ccc;
-}
-
-a.jxTab:active {
-  background-color: #fff;
-}
-
-a.tabActive {
-  background-color: #fff;
-}
-
-a.jxTab span.jxButtonSpan {
-  /* The SPAN contains the other side of the tab background image
-     and the tab label */
-  margin: 0px;
-  padding: 0px;
-}
-
-.jxBarTop a.jxTab span.jxButtonLabel,
-.jxBarBottom a.jxTab span.jxButtonLabel {
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 11px;
-  line-height: 11px;
-}
-
-/* ============== */
-/* TAB BAR ON TOP */
-/* ============== */
-
-.jxTabBoxTop {
-    margin-top: 27px;
-}
-
-.jxTabBoxTop .jxBarTop {
-    top: -27px;
-}
-
-.jxBarTop a.jxTab {
-  margin: 0px 1px;
-  padding: 7px; /* makes space around the label */
-}
-
-.jxBarTop a.tabActive {
-  border-bottom: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-/* ================= */
-/* TAB BAR ON BOTTOM */
-/* ================= */
-
-.jxTabBoxBottom {
-  margin-bottom: 27px;
-}
-
-.jxTabBoxBottom .jxBarBottom {
-  bottom: -27px;
-  background-position: top;
-}
-
-.jxBarBottom a.jxTab {
-  margin: 0px 1px;
-  padding: 7px; /* makes space around the label */
-}
-
-.jxBarBottom a.tabActive {
-  border-top: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-/* =============== */
-/* TAB BAR ON LEFT */
-/* =============== */
-
-.jxTabBoxLeft {
-  margin-left: 27px;
-}
-
-.jxTabBoxLeft .jxBarLeft {
-  left: -27px;
-}
-
-.jxBarLeft a.jxTab {
-  margin: 1px 0px 1px 2px;
-  padding: 7px; /* makes space around the label */
-}
-
-.jxBarLeft a.tabActive {
-  border-right: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-/* ================ */
-/* TAB BAR ON RIGHT */
-/* ================ */
-
-.jxTabBoxRight {
-  margin-right: 27px;
-}
-
-.jxTabBoxRight .jxBarRight {
-  right: -27px;
-  background-position: left
-}
-
-.jxBarRight a.jxTab {
-  margin: 1px 2px 1px 0px;
-  padding: 7px; /* makes space around the label */
-}
-
-.jxBarRight a.tabActive {
-  border-left: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-
-/* ============== */
-/* JX MENU STYLES */
-/* ============== */
-
-/* Jx Menus and Sub-menus are all built out of nested ULs
-   For this to work visually, the margins and padding need to be flattened
-   out, and the list marker needs to be hidden
-*/
-
-ul.jxMenu, 
-ul.jxSubMenu {
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-  background-color: #fff;
-}
-
-ul.jxSubMenu {
-  /* this makes pop-out sub menus align to the right edge of the 
-     parent li. 100% aligns perfectly, less causes an overlap.
-   */
-  left: 98%;
-  /* this makes pop-out sub menus align to the top of their parent li
-     it needs to be the ul.jxMenu a line-height plus 1 px (and negative)
-   */
-  margin-top: -18px;
-}
-
-li.jxMenuItem, 
-li.jxSubMenuItem {
-  /* This is needed for IE to make sure submenus don't open space in the parent menu */
-  margin: 0px;
-  padding: 0px;
-}
-
-ul.jxMenu a.jxButton, 
-ul.jxSubMenu a.jxButton {
-  border: 1px solid #fff;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 11px;
-  text-decoration: none;
-  padding: 0px;
-  /* padding-left: 20px; */
-  /*padding-right: 20px;*/
-  /* this value needs to be the height of it's parent
-     minus it's own margin, padding and border values */ 
-  line-height:20px;
-  color: #000;
-}
-
-ul.jxMenu span.jxButtonSpan, 
-ul.jxSubMenu span.jxButtonSpan {
-  /* background image is used for ... */
-  background-position: 5px center;
-  background-repeat: no-repeat;
-}
-
-
-ul.jxMenu a.jxButton:hover, 
-ul.jxSubMenu a.jxButton:hover {
-  border: 1px solid #E1EDFA;
-  background-color: #E1EDFA; 
-}
-
-ul.jxMenu a.jxButtonSubMenu span.jxButtonSpan,
-ul.jxSubMenu a.jxButtonSubMenu span.jxButtonSpan {
-  background-image: url(../images/menu_item_arrow_r2.png);
-  background-position: right center;
-  background-repeat: no-repeat;
-}
-
-ul.jxMenu span.jxButtonLabel, 
-ul.jxSubMenu span.jxButtonLabel {
-  padding-top: 1px;
-  padding-bottom: 1px;
-}
-
-ul.jxMenu span.jxMenuSeparator {
-  font-size: 10px;
-  line-height: 10px;
-  background-image: url(../images/toolbar_separator_v.png);
-  background-repeat: repeat-x;
-  background-position: left center;
-}
-
-ul.jxMenu a.jxMenuItemSelected {
-  background-image: url(../images/menu_item_radio.png);
-  background-position: 2px center;
-  background-repeat: no-repeat;
-}
-
-ul.jxMenu a.jxDisabled span.jxButtonLabel, 
-ul.jxSubMenu a.jxDisabled span.jxButtonLabel {   
-  color: #ccc;  
-}
-
-ul.jxMenu a.jxDisabled:hover, 
-ul.jxSubMenu a.jxDisabled:hover {   
-  background-color: #fff;
-  border: 1px solid #fff;
-}

Copied: sandbox/aboudreault/jx/css/jxskin-border.css (from rev 1352, trunk/jx/css/jxskin-border.css)
===================================================================
--- sandbox/aboudreault/jx/css/jxskin-border.css	                        (rev 0)
+++ sandbox/aboudreault/jx/css/jxskin-border.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,720 @@
+/**
+ * @project         Jx
+ * @revision        $Id: jxskin-border.css 512 2008-03-07 21:15:45Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* =================================== */
+/* VISUAL STYLES W. BORDERS AND COLORS */
+/* =================================== */
+
+
+/* ============= */
+/* DIALOG STYLES */
+/* ============= */
+
+.jxDialogContainer {
+}
+
+.jxDialog {
+    border: 1px solid #666;
+    background-color: #d9d9d9;
+    margin: 6px;
+}
+
+.jxDialogModal {
+    background-color: #000;
+    opacity: .2;
+    -moz-opacity: .2;
+    filter: Alpha(opacity=20);
+}
+
+.jxDialogBgTL {
+    top: 0px;
+    left: 0px;
+}
+
+.jxDialogBgTL img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgT {
+    top: 0px;
+    left: 12px;
+}
+
+.jxDialogBgT img {
+    height: 12px;
+}
+
+.jxDialogBgTR {
+    top: 0px;
+    right: 0px;
+}
+
+.jxDialogBgTR img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgR {
+    top: 12px;
+    right: 0px;
+}
+
+.jxDialogBgR img {
+    width: 12px;
+}
+
+.jxDialogBgBR {
+    bottom: 0px;
+    right: 0px;
+}
+
+.jxDialogBgBR img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgB {
+    bottom: 0px;
+    left: 12px;
+}
+
+.jxDialogBgB img {
+    height: 12px;
+}
+
+.jxDialogBgBL {
+    bottom: 0px;
+    left: 0px;
+}
+
+.jxDialogBgBL img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgL {
+    top: 12px;
+    left: 0px;
+}
+
+.jxDialogBgL img {
+    width: 12px;
+}
+
+.jxDialogTitle {
+    background-color: #ccc;
+    border-top: 1px solid #fff;
+    border-left: 1px solid #fff;
+    border-bottom: 1px solid #999;
+    font-family: Arial, Helvetica, sans-serif;
+    font-weight: bold;
+    font-size: 12px;
+    text-align: center;
+    height: 22px;
+    line-height: 22px;
+    cursor: move;
+}
+
+.jxDialogContent {
+    border-top: 1px solid #fff;
+    border-left: 1px solid #fff;
+    padding: 0px;
+}
+
+.jxDialogAction {
+    border-left: 1px solid #fff;
+    height: 30px;
+    text-align: right;
+    margin-right:15px;
+}
+
+.jxDialogAction input {
+    margin: 5px;
+    margin-left:0px;
+}
+
+.jxDialogCloseButton, 
+.jxDialogHelpButton {
+    width: 20px;
+    height: 20px;
+    top: 0px;
+    right: 2px;
+    padding: 0px;
+    margin: 0px; 
+    border: 0px;
+}
+
+.jxDialogHelpButton {
+  right: 22px;
+}
+
+.jxDialogCloseButton img, 
+.jxDialogHelpButton img {
+  border: 0px;
+  /* the margin needs to make up the difference between it's width/height
+     and the width/height of the parent a */
+  margin: 0px;
+  /* width/height has to be the actual image width/height */
+  width: 20px;
+  height: 20px;
+}
+
+.jxDialogResize {
+    width: 20px;
+    height: 20px;
+/*    bottom: 0px;
+    right: 0px; */
+    border: 0px;
+    cursor: se-resize;
+    background-image: url(../images/dialog_resize.png);
+}
+
+
+/* ================= */
+/* JX TOOLBAR STYLES */
+/* ================= */
+
+.jxToolbarContainer {
+  margin: 0px;
+  padding: 0px;
+  border: 0px;
+  /* simulates an underline at the bottom of the container*/
+  background-image:url(../images/container_bg.png); 
+  background-color: #d9d9d9;
+}
+
+/* Horizontally oriented toolbars */
+.jxBarTop, 
+.jxBarBottom {
+  background-repeat:repeat-x;
+  background-position: bottom;
+}
+
+/* Vertically oriented toolbars */
+.jxBarLeft, 
+.jxBarRight {
+  background-repeat:repeat-y;
+  background-position: right;
+}
+
+.toolbarLabel {
+  margin: 0px;
+  padding: 0px;
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 11px;
+  line-height: 24px;
+  color: #000;
+}
+
+ul.jxToolbar {
+  margin: 0px;  /* margins don't seem to work properly in IE */
+  padding: 0px;
+}
+
+.jxBarTop ul.jxToolbar, 
+.jxBarBottom ul.jxToolbar {
+  border-left: 1px solid #fff;
+  border-right: 1px solid #999;
+  border-top: 1px solid #fff;
+}
+
+.jxBarLeft ul.jxToolbar, 
+.jxBarRight ul.jxToolbar {
+  border-left: 1px solid #fff;
+  border-top: 1px solid #fff;
+  border-bottom: 1px solid #999;
+}
+
+li.jxToolItem {
+  padding: 0px;
+  margin: 0px;  /* margins don't seem to work properly in IE */
+}
+
+.jxBarTop li.jxToolItem, 
+.jxBarBottom li.jxToolItem {
+  border-top: none;
+  border-right: none;
+  border-bottom: 1px solid #999;
+  border-left: none;
+}
+
+.jxBarLeft li.jxToolItem, 
+.jxBarRight li.jxToolItem {
+  border-top: none;
+  border-right: 1px solid #999;
+  border-bottom: none;
+  border-left: none;
+}
+
+li.jxToolItem  span.separator {
+  /* width/height should be defined */
+  width: 8px;
+  height: 18px;
+  border: 0px;
+  margin: 0px;  /* margins don't seem to work properly in IE */
+  padding: 4px;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
+.jxBarTop  li.jxToolItem  span.separator, 
+.jxBarBottom  li.jxToolItem  span.separator {
+  background-image: url(../images/toolbar_separator_h.png);
+}
+
+.jxBarLeft  li.jxToolItem  span.separator, 
+.jxBarRight  li.jxToolItem  span.separator {
+  background-image: url(../images/toolbar_separator_v.png);
+}
+
+
+/* ================ */
+/* JX BUTTON STYLES */
+/* ================ */
+
+div.jxButtonContainer {
+  margin: 0px;
+  padding: 0px;
+  border: none;
+}
+
+a.jxButton {
+  /* If using background images, the A contains the left side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 6px;*/ /* makes room for the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 4px; 
+  border: 1px solid #d9d9d9;
+  background-repeat: no-repeat;
+  text-decoration: none;
+}
+
+a.jxButton:hover {
+  border-top: 1px solid #fff;
+  border-left: 1px solid #fff;
+  border-bottom: 1px solid #999;
+  border-right: 1px solid #999;
+}
+
+a.jxButton:active {
+  border-bottom: 1px solid #fff;
+  border-right: 1px solid #fff;
+  border-top: 1px solid #999;
+  border-left: 1px solid #999;
+}
+
+a.jxButtonActive {
+  background-color: #f0f0f0;
+  border-bottom: 1px solid #fff;
+  border-right: 1px solid #fff;
+  border-top: 1px solid #999;
+  border-left: 1px solid #999;
+}
+
+a.jxButtonActive:hover {
+  border-bottom: 1px solid #fff;
+  border-right: 1px solid #fff;
+  border-top: 1px solid #999;
+  border-left: 1px solid #999;
+}
+
+a.jxButtonActive:active {
+  border-bottom: 1px solid #fff;
+  border-right: 1px solid #fff;
+  border-top: 1px solid #999;
+  border-left: 1px solid #999;
+}
+
+.jxDisabled a.jxButton:hover, 
+.jxDisabled a.jxButton:active {
+  border: 1px solid #d9d9d9;
+}
+
+span.jxButtonSpan {
+  /* If using background images, the SPAN contains the right side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 0px;
+  background-repeat: no-repeat;
+}
+
+/* colour swatch styles
+   smaller image with borders */
+img.jxButtonSwatch {
+  width: 14px;
+  height: 14px;
+  border: 1px solid #000;
+}
+
+a.jxButtonMenu span.jxButtonSpan, 
+a.jxButtonFlyout span.jxButtonSpan {
+  background-image: url(../images/menu_item_arrow_d2.png);
+  background-position: right center;
+  background-repeat: no-repeat;
+}
+
+span.jxButtonContent {
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 16px;
+  line-height: 16px;
+}
+
+a.jxButtonMenu span.jxButtonContent, 
+a.jxButtonFlyout span.jxButtonContent {
+  padding-right: 16px;
+}
+
+span.jxButtonLabel {
+  /* If using background images, the SPAN contains the right side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 0px 4px;
+  color: #000;
+  background-position: right center;
+  background-repeat: no-repeat;
+  font-size: 11px;
+}
+
+.jxMenu span.jxButtonLabel,
+.jxSubMenu span.jxButtonLabel {
+  /* TODO: this is just really not right.  The padding-right value should be
+     20px but the label is collapsing somehow ... we'll need to investigate
+     why at some point, but not today!
+  */
+  padding-right: 30px;
+}
+
+span.jxButtonIcon {
+  padding-left: 14px;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+span.jxButtonIcon.jxButtonLabel {
+  padding-left: 22px;
+}
+
+.jxFlyout {
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+  background-color: #fff;
+  /* because of jxToolbarItem */
+  font-size: 12px;
+  line-height: 14px;
+}
+
+.jxFlyout .jxBarRight,
+.jxFlyout .jxBarLeft {
+  float: left;
+  height: auto;
+  width: auto;
+} 
+
+a.jxButtonMulti {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+a.jxButtonMulti span.jxButtonSpan {
+  padding-left: 0px;
+  padding-right: 16px;
+}
+
+a.jxButtonMulti span.jxButtonLabel {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+a.jxButtonColor span.jxButtonSpan {
+  padding-left: 2px;
+  padding-right: 16px;
+}
+a.jxButtonColor span.jxButtonLabel {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+/* ============= */
+/* JX TAB STYLES */
+/* ============= */
+
+.jxTabSetContainer {
+  /* This is an example of a container that can be used to hold a tabBox
+     the position need to be explicitly set, as well as the width and height. */
+  width: 200px;
+  height: 200px;
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+}
+
+.tabContent {
+}
+
+.tabContentActive {
+  display: block;
+}
+
+.jxTabSetContainer .jxToolbarContainer, 
+.jxTabSetContainer ul.jxToolbar {
+  border: none;
+}
+
+/* The tabbar is built out of a UL
+   The tab background uses the sliding door technique so tabs can expand to
+   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
+   (left/right tabs).  All parts and states of the tab BG graphics are in the 
+   same image so they can be treated like sprites.
+
+   Horizontal tabs can contain text or an image label.  Vertical tabs need an
+   image label.
+*/
+
+li.jxTabItem {
+  margin: 0px;
+  padding: 0px;
+}
+
+.jxBarTop li.jxTabItem, 
+.jxBarBottom li.jxTabItem {
+  border: none;
+}
+
+.jxBarLeft li.jxTabItem, 
+.jxBarRight li.jxTabItem {
+  border: none;
+}
+
+
+a.jxTab {
+  /* The A contains one side of the tab background image */
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999; /* same color as the tabBox border */
+  background-repeat: no-repeat;
+  text-decoration: none;
+  color: #000;
+}
+
+a.jxTab:hover {
+  background-color: #ccc;
+}
+
+a.jxTab:active {
+  background-color: #fff;
+}
+
+a.tabActive {
+  background-color: #fff;
+}
+
+a.jxTab span.jxButtonSpan {
+  /* The SPAN contains the other side of the tab background image
+     and the tab label */
+  margin: 0px;
+  padding: 0px;
+}
+
+.jxBarTop a.jxTab span.jxButtonLabel,
+.jxBarBottom a.jxTab span.jxButtonLabel {
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 11px;
+  line-height: 11px;
+}
+
+/* ============== */
+/* TAB BAR ON TOP */
+/* ============== */
+
+.jxTabBoxTop {
+    margin-top: 27px;
+}
+
+.jxTabBoxTop .jxBarTop {
+    top: -27px;
+}
+
+.jxBarTop a.jxTab {
+  margin: 0px 1px;
+  padding: 7px; /* makes space around the label */
+}
+
+.jxBarTop a.tabActive {
+  border-bottom: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+/* ================= */
+/* TAB BAR ON BOTTOM */
+/* ================= */
+
+.jxTabBoxBottom {
+  margin-bottom: 27px;
+}
+
+.jxTabBoxBottom .jxBarBottom {
+  bottom: -27px;
+  background-position: top;
+}
+
+.jxBarBottom a.jxTab {
+  margin: 0px 1px;
+  padding: 7px; /* makes space around the label */
+}
+
+.jxBarBottom a.tabActive {
+  border-top: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+/* =============== */
+/* TAB BAR ON LEFT */
+/* =============== */
+
+.jxTabBoxLeft {
+  margin-left: 27px;
+}
+
+.jxTabBoxLeft .jxBarLeft {
+  left: -27px;
+}
+
+.jxBarLeft a.jxTab {
+  margin: 1px 0px 1px 2px;
+  padding: 7px; /* makes space around the label */
+}
+
+.jxBarLeft a.tabActive {
+  border-right: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+/* ================ */
+/* TAB BAR ON RIGHT */
+/* ================ */
+
+.jxTabBoxRight {
+  margin-right: 27px;
+}
+
+.jxTabBoxRight .jxBarRight {
+  right: -27px;
+  background-position: left
+}
+
+.jxBarRight a.jxTab {
+  margin: 1px 2px 1px 0px;
+  padding: 7px; /* makes space around the label */
+}
+
+.jxBarRight a.tabActive {
+  border-left: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+
+/* ============== */
+/* JX MENU STYLES */
+/* ============== */
+
+/* Jx Menus and Sub-menus are all built out of nested ULs
+   For this to work visually, the margins and padding need to be flattened
+   out, and the list marker needs to be hidden
+*/
+
+ul.jxMenu, 
+ul.jxSubMenu {
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+  background-color: #fff;
+}
+
+ul.jxSubMenu {
+  /* this makes pop-out sub menus align to the right edge of the 
+     parent li. 100% aligns perfectly, less causes an overlap.
+   */
+  left: 98%;
+  /* this makes pop-out sub menus align to the top of their parent li
+     it needs to be the ul.jxMenu a line-height plus 1 px (and negative)
+   */
+  margin-top: -18px;
+}
+
+li.jxMenuItem, 
+li.jxSubMenuItem {
+  /* This is needed for IE to make sure submenus don't open space in the parent menu */
+  margin: 0px;
+  padding: 0px;
+}
+
+ul.jxMenu a.jxButton, 
+ul.jxSubMenu a.jxButton {
+  border: 1px solid #fff;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 11px;
+  text-decoration: none;
+  padding: 0px;
+  /* padding-left: 20px; */
+  /*padding-right: 20px;*/
+  /* this value needs to be the height of it's parent
+     minus it's own margin, padding and border values */ 
+  line-height:20px;
+  color: #000;
+}
+
+ul.jxMenu span.jxButtonSpan, 
+ul.jxSubMenu span.jxButtonSpan {
+  /* background image is used for ... */
+  background-position: 5px center;
+  background-repeat: no-repeat;
+}
+
+
+ul.jxMenu a.jxButton:hover, 
+ul.jxSubMenu a.jxButton:hover {
+  border: 1px solid #E1EDFA;
+  background-color: #E1EDFA; 
+}
+
+ul.jxMenu a.jxButtonSubMenu span.jxButtonSpan,
+ul.jxSubMenu a.jxButtonSubMenu span.jxButtonSpan {
+  background-image: url(../images/menu_item_arrow_r2.png);
+  background-position: right center;
+  background-repeat: no-repeat;
+}
+
+ul.jxMenu span.jxButtonLabel, 
+ul.jxSubMenu span.jxButtonLabel {
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+
+ul.jxMenu span.jxMenuSeparator {
+  font-size: 10px;
+  line-height: 10px;
+  background-image: url(../images/toolbar_separator_v.png);
+  background-repeat: repeat-x;
+  background-position: left center;
+}
+
+ul.jxMenu a.jxMenuItemSelected {
+  background-image: url(../images/menu_item_radio.png);
+  background-position: 2px center;
+  background-repeat: no-repeat;
+}
+
+ul.jxMenu a.jxDisabled span.jxButtonLabel, 
+ul.jxSubMenu a.jxDisabled span.jxButtonLabel {   
+  color: #ccc;  
+}
+
+ul.jxMenu a.jxDisabled:hover, 
+ul.jxSubMenu a.jxDisabled:hover {   
+  background-color: #fff;
+  border: 1px solid #fff;
+}

Deleted: sandbox/aboudreault/jx/css/jxskin-graphic.css
===================================================================
--- trunk/jx/css/jxskin-graphic.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/css/jxskin-graphic.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,830 +0,0 @@
-/**
- * @project         Jx
- * @revision        $Id: jxskin-graphic.css 443 2007-10-26 22:03:29Z fwarnock $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ==================================== */
-/* VISUAL STYLES W. BACKGROUND GRAPHICS */
-/* ==================================== */
-
-
-/* ============= */
-/* DIALOG STYLES */
-/* ============= */
-
-.jxDialogContainer {
-}
-
-.jxDialog {
-    border: 1px solid #666;
-    background-color: #d9d9d9;
-    margin: 6px;
-}
-
-.jxDialogModal {
-    background-color: #000;
-    opacity: .2;
-    -moz-opacity: .2;
-    filter: Alpha(opacity=20);
-}
-
-.jxDialogBgTL {
-    top: 0px;
-    left: 0px;
-}
-
-.jxDialogBgTL img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgT {
-    top: 0px;
-    left: 12px;
-}
-
-.jxDialogBgT img {
-    height: 12px;
-}
-
-.jxDialogBgTR {
-    top: 0px;
-    right: 0px;
-}
-
-.jxDialogBgTR img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgR {
-    top: 12px;
-    right: 0px;
-}
-
-.jxDialogBgR img {
-    width: 12px;
-}
-
-.jxDialogBgBR {
-    bottom: 0px;
-    right: 0px;
-}
-
-.jxDialogBgBR img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgB {
-    bottom: 0px;
-    left: 12px;
-}
-
-.jxDialogBgB img {
-    height: 12px;
-}
-
-.jxDialogBgBL {
-    bottom: 0px;
-    left: 0px;
-}
-
-.jxDialogBgBL img {
-    width: 12px;
-    height: 12px;
-}
-
-.jxDialogBgL {
-    top: 12px;
-    left: 0px;
-}
-
-.jxDialogBgL img {
-    width: 12px;
-}
-
-.jxDialogTitle {
-    border-top: 1px solid #fff;
-    border-left: 1px solid #fff;
-    border-bottom: 1px solid #999;
-    background-image: url(../images/dialog_bg.png);
-    font-family: Arial, Helvetica, sans-serif;
-    font-weight: bold;
-    font-size: 12px;
-    text-align: center;
-    /* note this is hard coded into jx.js Jx.Dialog initialize function - change there as well as here */
-    height: 22px;
-    line-height: 22px;
-    cursor: move;
-}
-
-.jxDialogContent {
-    border-top: 1px solid #fff;
-    border-left: 1px solid #fff;
-    padding: 0px;
-}
-
-.jxDialogAction {
-    border-left: 1px solid #fff;
-    /* note this is hard coded into jx.js Jx.Dialog initialize function - change there as well as here */
-    height: 30px;
-    text-align: right;
-    margin-right:15px;
-}
-
-.jxDialogAction input {
-    margin: 5px;
-    margin-left:0px;
-}
-
-.jxDialogCloseButton, 
-.jxDialogHelpButton {
-    width: 20px;
-    height: 20px;
-    top: 0px;
-    right: 2px;
-    padding: 0px;
-    margin: 0px; 
-    border: 0px;
-}
-
-.jxDialogHelpButton {
-  right: 22px;
-}
-
-.jxDialogCloseButton img, 
-.jxDialogHelpButton img {
-  border: 0px;
-  /* the margin needs to make up the difference between it's width/height
-     and the width/height of the parent a */
-  margin: 0px;
-  /* width/height has to be the actual image width/height */
-  width: 20px;
-  height: 20px;
-}
-
-.jxDialogResize {
-    width: 20px;
-    height: 20px;
-/*    bottom: 0px;
-    right: 0px; */
-    border: 0px;
-    cursor: se-resize;
-    background-image: url(../images/dialog_resize.png);
-}
-
-
-/* ================= */
-/* JX TOOLBAR STYLES */
-/* ================= */
-
-.jxToolbarContainer {
-  margin: 0px;
-  padding: 0px;
-  border: 0px;
-  /* simulates an underline at the bottom of the container*/
-  background-image:url(../images/container_bg.png); 
-  background-color: #d9d9d9;
-}
-
-/* Horizontally oriented toolbars */
-.jxBarTop, 
-.jxBarBottom {
-  background-repeat:repeat-x;
-  background-position: bottom;
-}
-
-/* Vertically oriented toolbars */
-.jxBarLeft, 
-.jxBarRight {
-  background-repeat:repeat-y;
-  background-position: right;
-}
-
-.toolbarLabel {
-  margin: 0px;
-  padding: 0px;
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 11px;
-  line-height: 24px;
-  color: #000;
-}
-
-ul.jxToolbar {
-  margin: 0px;  /* margins don't seem to work properly in IE */
-  padding: 0px;
-}
-
-.jxBarTop ul.jxToolbar, 
-.jxBarBottom ul.jxToolbar {
-  border-left: 1px solid #fff;
-  border-right: 1px solid #999;
-  border-top: 1px solid #fff;
-}
-
-.jxBarLeft ul.jxToolbar, 
-.jxBarRight ul.jxToolbar {
-  border-left: 1px solid #fff;
-  border-top: 1px solid #fff;
-  border-bottom: 1px solid #999;
-}
-
-li.jxToolItem {
-  padding: 0px;
-  margin: 0px;  /* margins don't seem to work properly in IE */
-}
-
-.jxBarTop li.jxToolItem, 
-.jxBarBottom li.jxToolItem {
-  border-top: none;
-  border-right: none;
-  border-bottom: 1px solid #999;
-  border-left: none;
-}
-
-.jxBarLeft li.jxToolItem, 
-.jxBarRight li.jxToolItem {
-  border-top: none;
-  border-right: 1px solid #999;
-  border-bottom: none;
-  border-left: none;
-}
-
-li.jxToolItem  span.separator {
-  /* width/height should be defined */
-  width: 8px;
-  height: 20px;
-  border: 0px;
-  margin: 0px;  /* margins don't seem to work properly in IE */
-  padding: 4px;
-  background-repeat: no-repeat;
-  background-position: center center;
-}
-
-.jxBarTop  li.jxToolItem  span.separator,
-.jxBarBottom  li.jxToolItem  span.separator {
-  background-image: url(../images/toolbar_separator_h.png);
-}
-
-.jxBarLeft  li.jxToolItem  span.separator, 
-.jxBarRight  li.jxToolItem  span.separator {
-  background-image: url(../images/toolbar_separator_v.png);
-}
-
-
-/* ================ */
-/* JX BUTTON STYLES */
-/* ================ */
-
-div.jxButtonContainer {
-  margin: 0px;
-  padding: 0px;
-  border: none;
-}
-
-/* normal button */
-a.jxButton {
-  /* Using background images, the A contains the left side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 6px;*/ /* makes room for the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 0px 0px 0px 3px; /* makes room for the left of the button bg */
-  border: none;
-  background-image: url(../images/button_bg.png);
-  background-position: left top; 
-  background-repeat: no-repeat;
-  text-decoration: none;
-}
-
-span.jxButtonSpan {
-  /* Using background images, the SPAN contains the right side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 6px 6px 6px 3px; /* makes room for the left of the button bg */
-  border: none;
-  background-image: url(../images/button_bg.png);
-  background-position: right top; 
-  background-repeat: no-repeat;
-}
-
-a.jxButtonMenu,
-a.jxButtonFlyout,
-a.jxButtonMenu span.jxButtonSpan,
-a.jxButtonFlyout span.jxButtonSpan {
-  background-image: url(../images/button_bg_arrow_d2.png);
-}
-
-/* hover button */
-a.jxButton:hover {
-  background-position: left -56px; 
-}
-
-a.jxButton:hover span.jxButtonSpan {
-  background-position: right -56px;
-}
-
-/* clicking button */
-a.jxButton:active {
-  background-position: left -112px; 
-}
-
-a.jxButton:active span.jxButtonSpan {
-  background-position: right -112px;
-}
-
-/* active button */
-a.jxButtonActive {
-  background-position: left -168px; 
-}
-
-a.jxButtonActive span.jxButtonSpan {
-  background-position: right -168px;
-}
-
-/* hover active button */
-a.jxButtonActive:hover {
-  background-position: left -224px; 
-}
-
-a.jxButtonActive:active {
-  border-bottom: 1px solid #fff;
-  border-right: 1px solid #fff;
-  border-top: 1px solid #999;
-  border-left: 1px solid #999;
-}
-
-a.jxButtonActive:hover span.jxButtonSpan {
-  background-position: right -224px;
-}
-
-/* hover and active disabled button */
-.jxDisabled a.jxButton:hover, 
-.jxDisabled a.jxButton:active {
-  background-position: left top; 
-}
-
-.jxDisabled a.jxButton:hover span.jxButtonSpan,
-.jxDisabled a.jxButton:active span.jxButtonSpan {
-  background-position: right top;
-}
-
-/* colour swatch styles
-   smaller image with borders */
-img.jxButtonSwatch {
-  width: 14px;
-  height: 14px;
-  border: 1px solid #000;
-}
-
-span.jxButtonContent {
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 16px;
-  line-height: 16px;
-}
-
-a.jxButtonMenu span.jxButtonContent, 
-a.jxButtonFlyout span.jxButtonContent {
-  padding-right: 16px;
-}
-
-span.jxButtonLabel {
-  /* Using background images, the SPAN contains the right side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
-  margin: 0px; /* margins don't seem to work properly in IE */
-  padding: 0 4px 0 4px;
-  color: #000;
-  font-size: 11px;
-}
-
-a.jxButtonMenu span.jxButtonLabel, 
-a.jxButtonFlyout span.jxButtonLabel {
-  padding-right: 16px;
-}
-
-.jxMenu span.jxButtonLabel,
-.jxSubMenu span.jxButtonLabel {
-  /* TODO: this is just really not right.  The padding-right value should be
-     20px but the label is collapsing somehow ... we'll need to investigate
-     why at some point, but not today!
-  */
-  padding-right: 30px;
-}
-
-span.jxButtonEmptyLabel {
-  /* collapse empty labels */
-  padding: 0px;
-  overflow: hidden;
-}
-
-span.jxButtonIcon {
-  padding-left: 14px;
-  background-position: left center;
-  background-repeat: no-repeat;
-}
-
-span.jxButtonIcon.jxButtonLabel {
-  padding-left: 22px;
-}
-
-.jxFlyout {
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-  background-color: #fff;
-  /* because of jxToolbarItem */
-  font-size: 12px;
-  line-height: 14px;
-}
-
-.jxFlyout .jxBarRight,
-.jxFlyout .jxBarLeft {
-  float: left;
-  height: auto;
-  width: auto;
-} 
-
-a.jxButtonMulti span.jxButtonSpan {
-  padding-left: 0px;
-  padding-right: 12px;
-}
-
-a.jxButtonMulti span.jxButtonLabel {
-  padding-left: 0px;
-  padding-right: 0px;
-}
-
-a.jxButtonColor span.jxButtonSpan {
-  padding-left: 2px;
-  padding-right: 16px;
-}
-a.jxButtonColor span.jxButtonLabel {
-  padding-left: 0px;
-  padding-right: 0px;
-}
-
-/* ============= */
-/* JX TAB STYLES */
-/* ============= */
-
-.jxTabSetContainer {
-  /* This is an example of a container that can be used to hold a tabBox
-     the position need to be explicitly set, as well as the width and height. */
-  width: 200px;
-  height: 200px;
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-}
-
-.tabContent {
-}
-
-.tabContentActive {
-  display: block;
-}
-
-
-/* The tabbar is built out of a UL
-   The tab background uses the sliding door technique so tabs can expand to
-   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
-   (left/right tabs).  All parts and states of the tab BG graphics are in the 
-   same image so they can be treated like sprites.
-
-   Horizontal tabs can contain text or an image label.  Vertical tabs need an
-   image label.
-*/
-
-li.jxTabItem {
-  margin: 0px;
-  padding: 0px;
-}
-
-.jxBarTop li.jxTabItem, 
-.jxBarBottom li.jxTabItem {
-  border: none;
-}
-
-.jxBarLeft li.jxTabItem, 
-.jxBarRight li.jxTabItem {
-  border: none;
-}
-
-
-a.jxTab {
-  /* The A contains one side of the tab background image */
-  margin: 0px;
-  padding: 0px;
-  border: none;
-  background-repeat: no-repeat;
-  text-decoration: none;
-  color: #000;
-}
-
-a.jxTab:hover {
-  border: none;
-}
-
-a.jxTab:active {
-  border: none;
-}
-
-a.jxTab span.jxButtonSpan {
-  /* The SPAN contains the other side of the tab background image
-     and the tab label */
-  margin: 0px;
-  padding: 0px;
-  background-repeat: no-repeat;
-}
-
-/* ============== */
-/* TAB BAR ON TOP */
-/* ============== */
-
-.jxTabBoxTop {
-    margin-top: 27px;
-}
-
-.jxTabBoxTop .jxBarTop {
-    top: -27px;
-}
-
-.jxBarTop a.jxTab {
-  padding-left: 6px; /* makes room for the left of the tab bg */
-  background-image: url(../images/tab_top_bg.png);
-  background-position: left 2px; /* shifts the left BG in 2 px for slide effect */
-  border-bottom: 1px solid #999; /* same color as the tabBox border */
-}
-
-.jxBarTop a.jxTab span.jxButtonSpan {
-  padding: 7px 6px 7px 0px; /* makes space around the label */
-  background-image: url(../images/tab_top_bg.png);
-  background-position: right 2px; /* shifts the right BG in 2 px for slide effect*/
-}
-
-.jxBarTop a.jxTab span.jxButtonLabel {
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 11px;
-  line-height: 11px;
-}
-
-.jxBarTop a.jxTab:hover {
-  background-position: left top; /* shifts the left BG out 2 px for slide effect */
-}
-
-.jxBarTop a.jxTab:hover span.jxButtonSpan {
-  background-position: right top; /* shifts the right BG out 2 px for slide effect */
-}
-
-.jxBarTop a.tabActive {
-  background-position: left -50px; /* switch to the active left BG */
-  border-bottom: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-.jxBarTop a.tabActive span.jxButtonSpan {
-  background-position: right -50px; /* switch to the active right BG  */
-}
-
-/* ================= */
-/* TAB BAR ON BOTTOM */
-/* ================= */
-
-.jxTabBoxBottom {
-  margin-bottom: 27px;
-}
-
-.jxTabBoxBottom .jxBarBottom {
-  bottom: -27px;
-}
-
-.jxBarBottom li.jxTabItem {
-  /* LIs are floated so tabs follow each other in a row */
-  float: left;
-}
-
-.jxBarBottom a.jxTab {
-  padding-left: 6px; /* makes room for the left of the tab bg */
-  background-image: url(../images/tab_bottom_bg.png);
-  background-position: left -2px; /* shifts the left BG in 2 px for slide effect */
-  border-top: 1px solid #999; /* same color as the tabBox border */
-}
-
-.jxBarBottom a.jxTab span.jxButtonSpan {
-  padding: 7px 6px 7px 0px; /* makes space around the label */
-  background-image: url(../images/tab_bottom_bg.png);
-  background-position: right -2px; /* shifts the right BG in 2 px for slide effect*/
-}
-
-.jxBarBottom a.jxTab:hover {
-  background-position: left top; /* shifts the left BG out 2 px for slide effect */
-}
-
-.jxBarBottom a.jxTab:hover span.jxButtonSpan {
-  background-position: right top; /* shifts the right BG out 2 px for slide effect */
-}
-
-.jxBarBottom a.tabActive {
-  background-position: left -50px; /* switch to the active left BG */
-  border-top: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-.jxBarBottom a.tabActive span.jxButtonSpan {
-  background-position: right -50px; /* switch to the active right BG  */
-}
-
-/* =============== */
-/* TAB BAR ON LEFT */
-/* =============== */
-
-.jxTabBoxLeft {
-  margin-left: 27px;
-}
-
-.jxTabBoxLeft .jxBarLeft {
-  left: -27px;
-}
-
-.jxBarLeft a.jxTab {
-  padding-top: 6px; /* makes room for the top of the tab bg */
-  background-image: url(../images/tab_left_bg.png);
-  background-position: 2px top; /* shifts the top BG in 2 px for slide effect */
-  border-right: 1px solid #999; /* same color as the tabBox border */
-}
-
-.jxBarLeft a.jxTab span.jxButtonSpan {
-  padding: 0px 7px 6px 7px; /* makes space around the label */
-  background-image: url(../images/tab_left_bg.png);
-  background-position: 2px bottom; /* shifts the bottom BG in 2 px for slide effect*/
-}
-
-.jxBarLeft a.jxTab:hover {
-  background-position: left top; /* shifts the top BG out 2 px for slide effect */
-}
-
-.jxBarLeft a.jxTab:hover span.jxButtonSpan {
-  background-position: left bottom; /* shifts the bottom BG out 2 px for slide effect */
-}
-
-.jxBarLeft a.tabActive {
-  background-position: -50px top; /* switch to the active top BG */
-  border-right: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-.jxBarLeft a.tabActive span.jxButtonSpan {
-  background-position: -50px bottom; /* switch to the active bottom BG  */
-}
-
-/* ================ */
-/* TAB BAR ON RIGHT */
-/* ================ */
-
-.jxTabBoxRight {
-  margin-right: 27px;
-}
-
-.jxTabBoxRight .jxBarRight {
-  right: -27px;
-}
-
-.jxBarRight a.jxTab {
-  padding-top: 6px; /* makes room for the top of the tab bg */
-  background-image: url(../images/tab_right_bg.png);
-  background-position: -2px top; /* shifts the top BG in 2 px for slide effect */
-  border-left: 1px solid #999; /* same color as the tabBox border */
-}
-
-.jxBarRight  a.jxTab span.jxButtonSpan {
-  padding: 0px 7px 6px 7px; /* makes space around the label */
-  background-image: url(../images/tab_right_bg.png);
-  background-position: -2px bottom; /* shifts the bottom BG in 2 px for slide effect*/
-}
-
-.jxBarRight  a.jxTab:hover {
-  background-position: left top; /* shifts the top BG out 2 px for slide effect */
-}
-
-.jxBarRight  a.jxTab:hover span.jxButtonSpan {
-  background-position: left bottom; /* shifts the bottom BG out 2 px for slide effect */
-}
-
-.jxBarRight  a.tabActive {
-  background-position: -50px top; /* switch to the active top BG */
-  border-left: 1px solid #fff; /* same color as the tabBox BG */
-}
-
-.jxBarRight  a.tabActive span.jxButtonSpan {
-  background-position: -50px bottom; /* switch to the active bottom BG  */
-}
-
-/* ============== */
-/* JX MENU STYLES */
-/* ============== */
-
-/* Jx Menus and Sub-menus are all built out of nested ULs
-   For this to work visually, the margins and padding need to be flattened
-   out, and the list marker needs to be hidden
-*/
-
-ul.jxMenu, 
-ul.jxSubMenu {
-  margin: 0px;
-  padding: 0px;
-  border: 1px solid #999;
-  background-color: #fff;
-}
-
-ul.jxSubMenu {
-  /* this makes pop-out sub menus align to the right edge of the 
-     parent li. 100% aligns perfectly, less causes an overlap.
-   */
-  left: 98%;
-  /* this makes pop-out sub menus align to the top of their parent li
-     it needs to be the ul.jxMenu a line-height plus 1 px (and negative)
-   */
-  margin-top: -18px;
-}
-
-li.jxMenuItem, 
-li.jxSubMenuItem {
-  /* This is needed for IE to make sure submenus don't open space in the parent menu */
-  margin: 0px;
-  padding: 0px;
-}
-
-ul.jxMenu a.jxButton, 
-ul.jxSubMenu a.jxButton {
-  background-image: none;
-  border: 1px solid #fff;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 11px;
-  text-decoration: none;
-  padding: 0px;
-  /* padding-left: 20px; */
-  /*padding-right: 20px;*/
-  /* this value needs to be the height of it's parent
-     minus it's own margin, padding and border values */ 
-  line-height:20px;
-  color: #000;
-}
-
-ul.jxMenu span.jxButtonSpan, 
-ul.jxSubMenu span.jxButtonSpan {
-  /* background image is used for ... */
-  background-image: none;
-  background-position: 5px top;
-  background-repeat: no-repeat;
-  padding-top: 0px;
-  padding-bottom: 0px;
-}
-
-
-ul.jxMenu a.jxButton:hover, 
-ul.jxSubMenu a.jxButton:hover {
-  background-image: none;
-  border: 1px solid #E1EDFA;
-  background-color: #E1EDFA; 
-}
-
-ul.jxMenu a.jxButtonSubMenu span.jxButtonSpan,
-ul.jxSubMenu a.jxButtonSubMenu span.jxButtonSpan,
-ul.jxMenu a.jxButtonSubMenu:hover span.jxButtonSpan,
-ul.jxSubMenu a.jxButtonSubMenu:hover span.jxButtonSpan {
-  background-image: url(../images/menu_item_arrow_r2.png);
-  background-position: right top;
-  background-repeat: no-repeat;
-}
-
-ul.jxMenu span.jxButtonLabel, 
-ul.jxSubMenu span.jxButtonLabel {
-  padding-top: 1px;
-  padding-bottom: 1px;
-}
-
-ul.jxMenu span.jxMenuSeparator {
-  font-size: 10px;
-  line-height: 10px;
-  background-image: url(../images/toolbar_separator_v.png);
-  background-repeat: repeat-x;
-  background-position: left center;
-}
-
-ul.jxMenu a.jxMenuItemSelected {
-  background-image: url(../images/menu_item_radio.png);
-  background-position: 2px top;
-  background-repeat: no-repeat;
-}
-
-ul.jxMenu a.jxDisabled span.jxButtonLabel, 
-ul.jxSubMenu a.jxDisabled span.jxButtonLabel {   
-  color: #ccc;  
-}
-
-ul.jxMenu a.jxDisabled:hover, 
-ul.jxSubMenu a.jxDisabled:hover {   
-  background-color: #fff;
-  border: 1px solid #fff;
-}

Copied: sandbox/aboudreault/jx/css/jxskin-graphic.css (from rev 1352, trunk/jx/css/jxskin-graphic.css)
===================================================================
--- sandbox/aboudreault/jx/css/jxskin-graphic.css	                        (rev 0)
+++ sandbox/aboudreault/jx/css/jxskin-graphic.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,830 @@
+/**
+ * @project         Jx
+ * @revision        $Id: jxskin-graphic.css 443 2007-10-26 22:03:29Z fwarnock $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ==================================== */
+/* VISUAL STYLES W. BACKGROUND GRAPHICS */
+/* ==================================== */
+
+
+/* ============= */
+/* DIALOG STYLES */
+/* ============= */
+
+.jxDialogContainer {
+}
+
+.jxDialog {
+    border: 1px solid #666;
+    background-color: #d9d9d9;
+    margin: 6px;
+}
+
+.jxDialogModal {
+    background-color: #000;
+    opacity: .2;
+    -moz-opacity: .2;
+    filter: Alpha(opacity=20);
+}
+
+.jxDialogBgTL {
+    top: 0px;
+    left: 0px;
+}
+
+.jxDialogBgTL img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgT {
+    top: 0px;
+    left: 12px;
+}
+
+.jxDialogBgT img {
+    height: 12px;
+}
+
+.jxDialogBgTR {
+    top: 0px;
+    right: 0px;
+}
+
+.jxDialogBgTR img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgR {
+    top: 12px;
+    right: 0px;
+}
+
+.jxDialogBgR img {
+    width: 12px;
+}
+
+.jxDialogBgBR {
+    bottom: 0px;
+    right: 0px;
+}
+
+.jxDialogBgBR img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgB {
+    bottom: 0px;
+    left: 12px;
+}
+
+.jxDialogBgB img {
+    height: 12px;
+}
+
+.jxDialogBgBL {
+    bottom: 0px;
+    left: 0px;
+}
+
+.jxDialogBgBL img {
+    width: 12px;
+    height: 12px;
+}
+
+.jxDialogBgL {
+    top: 12px;
+    left: 0px;
+}
+
+.jxDialogBgL img {
+    width: 12px;
+}
+
+.jxDialogTitle {
+    border-top: 1px solid #fff;
+    border-left: 1px solid #fff;
+    border-bottom: 1px solid #999;
+    background-image: url(../images/dialog_bg.png);
+    font-family: Arial, Helvetica, sans-serif;
+    font-weight: bold;
+    font-size: 12px;
+    text-align: center;
+    /* note this is hard coded into jx.js Jx.Dialog initialize function - change there as well as here */
+    height: 22px;
+    line-height: 22px;
+    cursor: move;
+}
+
+.jxDialogContent {
+    border-top: 1px solid #fff;
+    border-left: 1px solid #fff;
+    padding: 0px;
+}
+
+.jxDialogAction {
+    border-left: 1px solid #fff;
+    /* note this is hard coded into jx.js Jx.Dialog initialize function - change there as well as here */
+    height: 30px;
+    text-align: right;
+    margin-right:15px;
+}
+
+.jxDialogAction input {
+    margin: 5px;
+    margin-left:0px;
+}
+
+.jxDialogCloseButton, 
+.jxDialogHelpButton {
+    width: 20px;
+    height: 20px;
+    top: 0px;
+    right: 2px;
+    padding: 0px;
+    margin: 0px; 
+    border: 0px;
+}
+
+.jxDialogHelpButton {
+  right: 22px;
+}
+
+.jxDialogCloseButton img, 
+.jxDialogHelpButton img {
+  border: 0px;
+  /* the margin needs to make up the difference between it's width/height
+     and the width/height of the parent a */
+  margin: 0px;
+  /* width/height has to be the actual image width/height */
+  width: 20px;
+  height: 20px;
+}
+
+.jxDialogResize {
+    width: 20px;
+    height: 20px;
+/*    bottom: 0px;
+    right: 0px; */
+    border: 0px;
+    cursor: se-resize;
+    background-image: url(../images/dialog_resize.png);
+}
+
+
+/* ================= */
+/* JX TOOLBAR STYLES */
+/* ================= */
+
+.jxToolbarContainer {
+  margin: 0px;
+  padding: 0px;
+  border: 0px;
+  /* simulates an underline at the bottom of the container*/
+  background-image:url(../images/container_bg.png); 
+  background-color: #d9d9d9;
+}
+
+/* Horizontally oriented toolbars */
+.jxBarTop, 
+.jxBarBottom {
+  background-repeat:repeat-x;
+  background-position: bottom;
+}
+
+/* Vertically oriented toolbars */
+.jxBarLeft, 
+.jxBarRight {
+  background-repeat:repeat-y;
+  background-position: right;
+}
+
+.toolbarLabel {
+  margin: 0px;
+  padding: 0px;
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 11px;
+  line-height: 24px;
+  color: #000;
+}
+
+ul.jxToolbar {
+  margin: 0px;  /* margins don't seem to work properly in IE */
+  padding: 0px;
+}
+
+.jxBarTop ul.jxToolbar, 
+.jxBarBottom ul.jxToolbar {
+  border-left: 1px solid #fff;
+  border-right: 1px solid #999;
+  border-top: 1px solid #fff;
+}
+
+.jxBarLeft ul.jxToolbar, 
+.jxBarRight ul.jxToolbar {
+  border-left: 1px solid #fff;
+  border-top: 1px solid #fff;
+  border-bottom: 1px solid #999;
+}
+
+li.jxToolItem {
+  padding: 0px;
+  margin: 0px;  /* margins don't seem to work properly in IE */
+}
+
+.jxBarTop li.jxToolItem, 
+.jxBarBottom li.jxToolItem {
+  border-top: none;
+  border-right: none;
+  border-bottom: 1px solid #999;
+  border-left: none;
+}
+
+.jxBarLeft li.jxToolItem, 
+.jxBarRight li.jxToolItem {
+  border-top: none;
+  border-right: 1px solid #999;
+  border-bottom: none;
+  border-left: none;
+}
+
+li.jxToolItem  span.separator {
+  /* width/height should be defined */
+  width: 8px;
+  height: 20px;
+  border: 0px;
+  margin: 0px;  /* margins don't seem to work properly in IE */
+  padding: 4px;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+
+.jxBarTop  li.jxToolItem  span.separator,
+.jxBarBottom  li.jxToolItem  span.separator {
+  background-image: url(../images/toolbar_separator_h.png);
+}
+
+.jxBarLeft  li.jxToolItem  span.separator, 
+.jxBarRight  li.jxToolItem  span.separator {
+  background-image: url(../images/toolbar_separator_v.png);
+}
+
+
+/* ================ */
+/* JX BUTTON STYLES */
+/* ================ */
+
+div.jxButtonContainer {
+  margin: 0px;
+  padding: 0px;
+  border: none;
+}
+
+/* normal button */
+a.jxButton {
+  /* Using background images, the A contains the left side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 6px;*/ /* makes room for the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 0px 0px 0px 3px; /* makes room for the left of the button bg */
+  border: none;
+  background-image: url(../images/button_bg.png);
+  background-position: left top; 
+  background-repeat: no-repeat;
+  text-decoration: none;
+}
+
+span.jxButtonSpan {
+  /* Using background images, the SPAN contains the right side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 6px 6px 6px 3px; /* makes room for the left of the button bg */
+  border: none;
+  background-image: url(../images/button_bg.png);
+  background-position: right top; 
+  background-repeat: no-repeat;
+}
+
+a.jxButtonMenu,
+a.jxButtonFlyout,
+a.jxButtonMenu span.jxButtonSpan,
+a.jxButtonFlyout span.jxButtonSpan {
+  background-image: url(../images/button_bg_arrow_d2.png);
+}
+
+/* hover button */
+a.jxButton:hover {
+  background-position: left -56px; 
+}
+
+a.jxButton:hover span.jxButtonSpan {
+  background-position: right -56px;
+}
+
+/* clicking button */
+a.jxButton:active {
+  background-position: left -112px; 
+}
+
+a.jxButton:active span.jxButtonSpan {
+  background-position: right -112px;
+}
+
+/* active button */
+a.jxButtonActive {
+  background-position: left -168px; 
+}
+
+a.jxButtonActive span.jxButtonSpan {
+  background-position: right -168px;
+}
+
+/* hover active button */
+a.jxButtonActive:hover {
+  background-position: left -224px; 
+}
+
+a.jxButtonActive:active {
+  border-bottom: 1px solid #fff;
+  border-right: 1px solid #fff;
+  border-top: 1px solid #999;
+  border-left: 1px solid #999;
+}
+
+a.jxButtonActive:hover span.jxButtonSpan {
+  background-position: right -224px;
+}
+
+/* hover and active disabled button */
+.jxDisabled a.jxButton:hover, 
+.jxDisabled a.jxButton:active {
+  background-position: left top; 
+}
+
+.jxDisabled a.jxButton:hover span.jxButtonSpan,
+.jxDisabled a.jxButton:active span.jxButtonSpan {
+  background-position: right top;
+}
+
+/* colour swatch styles
+   smaller image with borders */
+img.jxButtonSwatch {
+  width: 14px;
+  height: 14px;
+  border: 1px solid #000;
+}
+
+span.jxButtonContent {
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 16px;
+  line-height: 16px;
+}
+
+a.jxButtonMenu span.jxButtonContent, 
+a.jxButtonFlyout span.jxButtonContent {
+  padding-right: 16px;
+}
+
+span.jxButtonLabel {
+  /* Using background images, the SPAN contains the right side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
+  margin: 0px; /* margins don't seem to work properly in IE */
+  padding: 0 4px 0 4px;
+  color: #000;
+  font-size: 11px;
+}
+
+a.jxButtonMenu span.jxButtonLabel, 
+a.jxButtonFlyout span.jxButtonLabel {
+  padding-right: 16px;
+}
+
+.jxMenu span.jxButtonLabel,
+.jxSubMenu span.jxButtonLabel {
+  /* TODO: this is just really not right.  The padding-right value should be
+     20px but the label is collapsing somehow ... we'll need to investigate
+     why at some point, but not today!
+  */
+  padding-right: 30px;
+}
+
+span.jxButtonEmptyLabel {
+  /* collapse empty labels */
+  padding: 0px;
+  overflow: hidden;
+}
+
+span.jxButtonIcon {
+  padding-left: 14px;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+span.jxButtonIcon.jxButtonLabel {
+  padding-left: 22px;
+}
+
+.jxFlyout {
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+  background-color: #fff;
+  /* because of jxToolbarItem */
+  font-size: 12px;
+  line-height: 14px;
+}
+
+.jxFlyout .jxBarRight,
+.jxFlyout .jxBarLeft {
+  float: left;
+  height: auto;
+  width: auto;
+} 
+
+a.jxButtonMulti span.jxButtonSpan {
+  padding-left: 0px;
+  padding-right: 12px;
+}
+
+a.jxButtonMulti span.jxButtonLabel {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+a.jxButtonColor span.jxButtonSpan {
+  padding-left: 2px;
+  padding-right: 16px;
+}
+a.jxButtonColor span.jxButtonLabel {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+/* ============= */
+/* JX TAB STYLES */
+/* ============= */
+
+.jxTabSetContainer {
+  /* This is an example of a container that can be used to hold a tabBox
+     the position need to be explicitly set, as well as the width and height. */
+  width: 200px;
+  height: 200px;
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+}
+
+.tabContent {
+}
+
+.tabContentActive {
+  display: block;
+}
+
+
+/* The tabbar is built out of a UL
+   The tab background uses the sliding door technique so tabs can expand to
+   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
+   (left/right tabs).  All parts and states of the tab BG graphics are in the 
+   same image so they can be treated like sprites.
+
+   Horizontal tabs can contain text or an image label.  Vertical tabs need an
+   image label.
+*/
+
+li.jxTabItem {
+  margin: 0px;
+  padding: 0px;
+}
+
+.jxBarTop li.jxTabItem, 
+.jxBarBottom li.jxTabItem {
+  border: none;
+}
+
+.jxBarLeft li.jxTabItem, 
+.jxBarRight li.jxTabItem {
+  border: none;
+}
+
+
+a.jxTab {
+  /* The A contains one side of the tab background image */
+  margin: 0px;
+  padding: 0px;
+  border: none;
+  background-repeat: no-repeat;
+  text-decoration: none;
+  color: #000;
+}
+
+a.jxTab:hover {
+  border: none;
+}
+
+a.jxTab:active {
+  border: none;
+}
+
+a.jxTab span.jxButtonSpan {
+  /* The SPAN contains the other side of the tab background image
+     and the tab label */
+  margin: 0px;
+  padding: 0px;
+  background-repeat: no-repeat;
+}
+
+/* ============== */
+/* TAB BAR ON TOP */
+/* ============== */
+
+.jxTabBoxTop {
+    margin-top: 27px;
+}
+
+.jxTabBoxTop .jxBarTop {
+    top: -27px;
+}
+
+.jxBarTop a.jxTab {
+  padding-left: 6px; /* makes room for the left of the tab bg */
+  background-image: url(../images/tab_top_bg.png);
+  background-position: left 2px; /* shifts the left BG in 2 px for slide effect */
+  border-bottom: 1px solid #999; /* same color as the tabBox border */
+}
+
+.jxBarTop a.jxTab span.jxButtonSpan {
+  padding: 7px 6px 7px 0px; /* makes space around the label */
+  background-image: url(../images/tab_top_bg.png);
+  background-position: right 2px; /* shifts the right BG in 2 px for slide effect*/
+}
+
+.jxBarTop a.jxTab span.jxButtonLabel {
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 11px;
+  line-height: 11px;
+}
+
+.jxBarTop a.jxTab:hover {
+  background-position: left top; /* shifts the left BG out 2 px for slide effect */
+}
+
+.jxBarTop a.jxTab:hover span.jxButtonSpan {
+  background-position: right top; /* shifts the right BG out 2 px for slide effect */
+}
+
+.jxBarTop a.tabActive {
+  background-position: left -50px; /* switch to the active left BG */
+  border-bottom: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+.jxBarTop a.tabActive span.jxButtonSpan {
+  background-position: right -50px; /* switch to the active right BG  */
+}
+
+/* ================= */
+/* TAB BAR ON BOTTOM */
+/* ================= */
+
+.jxTabBoxBottom {
+  margin-bottom: 27px;
+}
+
+.jxTabBoxBottom .jxBarBottom {
+  bottom: -27px;
+}
+
+.jxBarBottom li.jxTabItem {
+  /* LIs are floated so tabs follow each other in a row */
+  float: left;
+}
+
+.jxBarBottom a.jxTab {
+  padding-left: 6px; /* makes room for the left of the tab bg */
+  background-image: url(../images/tab_bottom_bg.png);
+  background-position: left -2px; /* shifts the left BG in 2 px for slide effect */
+  border-top: 1px solid #999; /* same color as the tabBox border */
+}
+
+.jxBarBottom a.jxTab span.jxButtonSpan {
+  padding: 7px 6px 7px 0px; /* makes space around the label */
+  background-image: url(../images/tab_bottom_bg.png);
+  background-position: right -2px; /* shifts the right BG in 2 px for slide effect*/
+}
+
+.jxBarBottom a.jxTab:hover {
+  background-position: left top; /* shifts the left BG out 2 px for slide effect */
+}
+
+.jxBarBottom a.jxTab:hover span.jxButtonSpan {
+  background-position: right top; /* shifts the right BG out 2 px for slide effect */
+}
+
+.jxBarBottom a.tabActive {
+  background-position: left -50px; /* switch to the active left BG */
+  border-top: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+.jxBarBottom a.tabActive span.jxButtonSpan {
+  background-position: right -50px; /* switch to the active right BG  */
+}
+
+/* =============== */
+/* TAB BAR ON LEFT */
+/* =============== */
+
+.jxTabBoxLeft {
+  margin-left: 27px;
+}
+
+.jxTabBoxLeft .jxBarLeft {
+  left: -27px;
+}
+
+.jxBarLeft a.jxTab {
+  padding-top: 6px; /* makes room for the top of the tab bg */
+  background-image: url(../images/tab_left_bg.png);
+  background-position: 2px top; /* shifts the top BG in 2 px for slide effect */
+  border-right: 1px solid #999; /* same color as the tabBox border */
+}
+
+.jxBarLeft a.jxTab span.jxButtonSpan {
+  padding: 0px 7px 6px 7px; /* makes space around the label */
+  background-image: url(../images/tab_left_bg.png);
+  background-position: 2px bottom; /* shifts the bottom BG in 2 px for slide effect*/
+}
+
+.jxBarLeft a.jxTab:hover {
+  background-position: left top; /* shifts the top BG out 2 px for slide effect */
+}
+
+.jxBarLeft a.jxTab:hover span.jxButtonSpan {
+  background-position: left bottom; /* shifts the bottom BG out 2 px for slide effect */
+}
+
+.jxBarLeft a.tabActive {
+  background-position: -50px top; /* switch to the active top BG */
+  border-right: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+.jxBarLeft a.tabActive span.jxButtonSpan {
+  background-position: -50px bottom; /* switch to the active bottom BG  */
+}
+
+/* ================ */
+/* TAB BAR ON RIGHT */
+/* ================ */
+
+.jxTabBoxRight {
+  margin-right: 27px;
+}
+
+.jxTabBoxRight .jxBarRight {
+  right: -27px;
+}
+
+.jxBarRight a.jxTab {
+  padding-top: 6px; /* makes room for the top of the tab bg */
+  background-image: url(../images/tab_right_bg.png);
+  background-position: -2px top; /* shifts the top BG in 2 px for slide effect */
+  border-left: 1px solid #999; /* same color as the tabBox border */
+}
+
+.jxBarRight  a.jxTab span.jxButtonSpan {
+  padding: 0px 7px 6px 7px; /* makes space around the label */
+  background-image: url(../images/tab_right_bg.png);
+  background-position: -2px bottom; /* shifts the bottom BG in 2 px for slide effect*/
+}
+
+.jxBarRight  a.jxTab:hover {
+  background-position: left top; /* shifts the top BG out 2 px for slide effect */
+}
+
+.jxBarRight  a.jxTab:hover span.jxButtonSpan {
+  background-position: left bottom; /* shifts the bottom BG out 2 px for slide effect */
+}
+
+.jxBarRight  a.tabActive {
+  background-position: -50px top; /* switch to the active top BG */
+  border-left: 1px solid #fff; /* same color as the tabBox BG */
+}
+
+.jxBarRight  a.tabActive span.jxButtonSpan {
+  background-position: -50px bottom; /* switch to the active bottom BG  */
+}
+
+/* ============== */
+/* JX MENU STYLES */
+/* ============== */
+
+/* Jx Menus and Sub-menus are all built out of nested ULs
+   For this to work visually, the margins and padding need to be flattened
+   out, and the list marker needs to be hidden
+*/
+
+ul.jxMenu, 
+ul.jxSubMenu {
+  margin: 0px;
+  padding: 0px;
+  border: 1px solid #999;
+  background-color: #fff;
+}
+
+ul.jxSubMenu {
+  /* this makes pop-out sub menus align to the right edge of the 
+     parent li. 100% aligns perfectly, less causes an overlap.
+   */
+  left: 98%;
+  /* this makes pop-out sub menus align to the top of their parent li
+     it needs to be the ul.jxMenu a line-height plus 1 px (and negative)
+   */
+  margin-top: -18px;
+}
+
+li.jxMenuItem, 
+li.jxSubMenuItem {
+  /* This is needed for IE to make sure submenus don't open space in the parent menu */
+  margin: 0px;
+  padding: 0px;
+}
+
+ul.jxMenu a.jxButton, 
+ul.jxSubMenu a.jxButton {
+  background-image: none;
+  border: 1px solid #fff;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 11px;
+  text-decoration: none;
+  padding: 0px;
+  /* padding-left: 20px; */
+  /*padding-right: 20px;*/
+  /* this value needs to be the height of it's parent
+     minus it's own margin, padding and border values */ 
+  line-height:20px;
+  color: #000;
+}
+
+ul.jxMenu span.jxButtonSpan, 
+ul.jxSubMenu span.jxButtonSpan {
+  /* background image is used for ... */
+  background-image: none;
+  background-position: 5px top;
+  background-repeat: no-repeat;
+  padding-top: 0px;
+  padding-bottom: 0px;
+}
+
+
+ul.jxMenu a.jxButton:hover, 
+ul.jxSubMenu a.jxButton:hover {
+  background-image: none;
+  border: 1px solid #E1EDFA;
+  background-color: #E1EDFA; 
+}
+
+ul.jxMenu a.jxButtonSubMenu span.jxButtonSpan,
+ul.jxSubMenu a.jxButtonSubMenu span.jxButtonSpan,
+ul.jxMenu a.jxButtonSubMenu:hover span.jxButtonSpan,
+ul.jxSubMenu a.jxButtonSubMenu:hover span.jxButtonSpan {
+  background-image: url(../images/menu_item_arrow_r2.png);
+  background-position: right top;
+  background-repeat: no-repeat;
+}
+
+ul.jxMenu span.jxButtonLabel, 
+ul.jxSubMenu span.jxButtonLabel {
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+
+ul.jxMenu span.jxMenuSeparator {
+  font-size: 10px;
+  line-height: 10px;
+  background-image: url(../images/toolbar_separator_v.png);
+  background-repeat: repeat-x;
+  background-position: left center;
+}
+
+ul.jxMenu a.jxMenuItemSelected {
+  background-image: url(../images/menu_item_radio.png);
+  background-position: 2px top;
+  background-repeat: no-repeat;
+}
+
+ul.jxMenu a.jxDisabled span.jxButtonLabel, 
+ul.jxSubMenu a.jxDisabled span.jxButtonLabel {   
+  color: #ccc;  
+}
+
+ul.jxMenu a.jxDisabled:hover, 
+ul.jxSubMenu a.jxDisabled:hover {   
+  background-color: #fff;
+  border: 1px solid #fff;
+}

Deleted: sandbox/aboudreault/jx/css/reset.css
===================================================================
--- trunk/jx/css/reset.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/css/reset.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,21 +0,0 @@
-/*
-Copyright (c) 2006, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 0.11.0
-*/
-body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
-table{border-collapse:collapse;border-spacing:0;}
-fieldset,img{border:0;}
-address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
-ol,ul {list-style:none;}
-caption,th {text-align:left;}
-h1,h2,h3,h4,h5,h6{font-size:100%;}
-q:before,q:after{content:'';}
-/*
-DMSG additions for Jx
-*/
-a{outline:none;}
-.png24{filter:expression(Jx.applyPNGFilter(this))}
-.jxClearer{display:block;position:relative;float:none;clear:both;font-size:0;line-height:0;width:0;height:0;margin:0;padding:0;}
-.jxDisabled{opacity:0.4;-moz-opacity:0.4;filter:Alpha(opacity=40);}

Copied: sandbox/aboudreault/jx/css/reset.css (from rev 1352, trunk/jx/css/reset.css)
===================================================================
--- sandbox/aboudreault/jx/css/reset.css	                        (rev 0)
+++ sandbox/aboudreault/jx/css/reset.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
+table{border-collapse:collapse;border-spacing:0;}
+fieldset,img{border:0;}
+address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
+ol,ul {list-style:none;}
+caption,th {text-align:left;}
+h1,h2,h3,h4,h5,h6{font-size:100%;}
+q:before,q:after{content:'';}
+/*
+DMSG additions for Jx
+*/
+a{outline:none;}
+.png24{filter:expression(Jx.applyPNGFilter(this))}
+.jxClearer{display:block;position:relative;float:none;clear:both;font-size:0;line-height:0;width:0;height:0;margin:0;padding:0;}
+.jxDisabled{opacity:0.4;-moz-opacity:0.4;filter:Alpha(opacity=40);}

Deleted: sandbox/aboudreault/jx/css/tests.css
===================================================================
--- trunk/jx/css/tests.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/css/tests.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,70 +0,0 @@
-body {
-  background-image:url(../images/page_grid.png);
-}
-
-h1 {
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 24px;
-  line-height: 30px;
-  font-weight: normal;
-  color: #000;
-  margin: 20px;
-}
-
-h2 {
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 18px;
-  line-height: 24px;
-  font-weight: normal;
-  color: #000;
-  margin: 20px;
-}
-
-p {
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 14px;
-  line-height: 20px;
-  font-weight: normal;
-  color: #333;
-  margin: 10px 20px;
-}
-
-ul.testList {
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 14px;
-  line-height: 20px;
-}
-
-.testList a {
-  text-decoration: none;
-}
-
-.testList a:hover {
-  text-decoration: underline;
-}
-
-#ssSwitcher {
-  position: absolute;
-  top: 12px;
-  right: 12px;
-  border: 1px solid #999;
-  background-color: #d9d9d9;
-  z-index: 1000;
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 11px;
-  color: #000;
-}
-
-#ssSwitcher label {
-  display: block;
-  padding: 5px;
-  border-top: 1px solid #fff;
-  border-left: 1px solid #fff;
-}
-
-#ssSwitcher select {
-  font-family: Arial, Hevetica, sans-serif;
-  font-size: 11px;
-  color: #000;
-}
-

Copied: sandbox/aboudreault/jx/css/tests.css (from rev 1352, trunk/jx/css/tests.css)
===================================================================
--- sandbox/aboudreault/jx/css/tests.css	                        (rev 0)
+++ sandbox/aboudreault/jx/css/tests.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,70 @@
+body {
+  background-image:url(../images/page_grid.png);
+}
+
+h1 {
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 24px;
+  line-height: 30px;
+  font-weight: normal;
+  color: #000;
+  margin: 20px;
+}
+
+h2 {
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 18px;
+  line-height: 24px;
+  font-weight: normal;
+  color: #000;
+  margin: 20px;
+}
+
+p {
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 14px;
+  line-height: 20px;
+  font-weight: normal;
+  color: #333;
+  margin: 10px 20px;
+}
+
+ul.testList {
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 14px;
+  line-height: 20px;
+}
+
+.testList a {
+  text-decoration: none;
+}
+
+.testList a:hover {
+  text-decoration: underline;
+}
+
+#ssSwitcher {
+  position: absolute;
+  top: 12px;
+  right: 12px;
+  border: 1px solid #999;
+  background-color: #d9d9d9;
+  z-index: 1000;
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 11px;
+  color: #000;
+}
+
+#ssSwitcher label {
+  display: block;
+  padding: 5px;
+  border-top: 1px solid #fff;
+  border-left: 1px solid #fff;
+}
+
+#ssSwitcher select {
+  font-family: Arial, Hevetica, sans-serif;
+  font-size: 11px;
+  color: #000;
+}
+

Copied: sandbox/aboudreault/jx/images (from rev 1352, trunk/jx/images)

Deleted: sandbox/aboudreault/jx/images/a_pixel.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/a_pixel.png (from rev 1352, trunk/jx/images/a_pixel.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/button_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/button_bg.png (from rev 1352, trunk/jx/images/button_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/button_bg_arrow_d2.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/button_bg_arrow_d2.png (from rev 1352, trunk/jx/images/button_bg_arrow_d2.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/button_bg_arrow_r2.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/button_bg_arrow_r2.png (from rev 1352, trunk/jx/images/button_bg_arrow_r2.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/close.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/close.png (from rev 1352, trunk/jx/images/close.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/container_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/container_bg.png (from rev 1352, trunk/jx/images/container_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_bg.png (from rev 1352, trunk/jx/images/dialog_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_b.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_b.png (from rev 1352, trunk/jx/images/dialog_glow_b.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_bl.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_bl.png (from rev 1352, trunk/jx/images/dialog_glow_bl.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_br.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_br.png (from rev 1352, trunk/jx/images/dialog_glow_br.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_l.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_l.png (from rev 1352, trunk/jx/images/dialog_glow_l.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_r.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_r.png (from rev 1352, trunk/jx/images/dialog_glow_r.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_t.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_t.png (from rev 1352, trunk/jx/images/dialog_glow_t.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_tl.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_tl.png (from rev 1352, trunk/jx/images/dialog_glow_tl.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_glow_tr.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_glow_tr.png (from rev 1352, trunk/jx/images/dialog_glow_tr.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/dialog_resize.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/dialog_resize.png (from rev 1352, trunk/jx/images/dialog_resize.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/disclose.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/disclose.png (from rev 1352, trunk/jx/images/disclose.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/disclose2.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/disclose2.png (from rev 1352, trunk/jx/images/disclose2.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/disclose3.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/disclose3.png (from rev 1352, trunk/jx/images/disclose3.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/grid.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/grid.png (from rev 1352, trunk/jx/images/grid.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/help.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/help.png (from rev 1352, trunk/jx/images/help.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/help_close.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/help_close.png (from rev 1352, trunk/jx/images/help_close.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/icon_close.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/icon_close.png (from rev 1352, trunk/jx/images/icon_close.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/icon_quickhelp.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/icon_quickhelp.png (from rev 1352, trunk/jx/images/icon_quickhelp.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/maximize.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/maximize.png (from rev 1352, trunk/jx/images/maximize.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_arrow_d.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_arrow_d.png (from rev 1352, trunk/jx/images/menu_item_arrow_d.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_arrow_d2.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_arrow_d2.png (from rev 1352, trunk/jx/images/menu_item_arrow_d2.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_arrow_r.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_arrow_r.png (from rev 1352, trunk/jx/images/menu_item_arrow_r.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_arrow_r2.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_arrow_r2.png (from rev 1352, trunk/jx/images/menu_item_arrow_r2.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_check.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_check.png (from rev 1352, trunk/jx/images/menu_item_check.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/menu_item_radio.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/menu_item_radio.png (from rev 1352, trunk/jx/images/menu_item_radio.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/minimize.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/minimize.png (from rev 1352, trunk/jx/images/minimize.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/page_grid.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/page_grid.png (from rev 1352, trunk/jx/images/page_grid.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/panel_grey_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/panel_grey_bg.png (from rev 1352, trunk/jx/images/panel_grey_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/panel_white_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/panel_white_bg.png (from rev 1352, trunk/jx/images/panel_white_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/separator.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/separator.png (from rev 1352, trunk/jx/images/separator.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/snap_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/snap_bg.png (from rev 1352, trunk/jx/images/snap_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tab_bottom_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tab_bottom_bg.png (from rev 1352, trunk/jx/images/tab_bottom_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tab_left_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tab_left_bg.png (from rev 1352, trunk/jx/images/tab_left_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tab_right_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tab_right_bg.png (from rev 1352, trunk/jx/images/tab_right_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tab_top_bg.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tab_top_bg.png (from rev 1352, trunk/jx/images/tab_top_bg.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/test-text.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/test-text.png (from rev 1352, trunk/jx/images/test-text.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/toolbar_separator_h.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/toolbar_separator_h.png (from rev 1352, trunk/jx/images/toolbar_separator_h.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/toolbar_separator_v.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/toolbar_separator_v.png (from rev 1352, trunk/jx/images/toolbar_separator_v.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_folder.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_folder.png (from rev 1352, trunk/jx/images/tree_folder.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_folder_open.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_folder_open.png (from rev 1352, trunk/jx/images/tree_folder_open.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_last_node.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_last_node.png (from rev 1352, trunk/jx/images/tree_last_node.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_minus.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_minus.png (from rev 1352, trunk/jx/images/tree_minus.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_node.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_node.png (from rev 1352, trunk/jx/images/tree_node.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_none.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_none.png (from rev 1352, trunk/jx/images/tree_none.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_page.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_page.png (from rev 1352, trunk/jx/images/tree_page.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_plus.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_plus.png (from rev 1352, trunk/jx/images/tree_plus.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/jx/images/tree_vert_line.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/images/tree_vert_line.png (from rev 1352, trunk/jx/images/tree_vert_line.png)
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/jx/lib (from rev 1352, trunk/jx/lib)

Deleted: sandbox/aboudreault/jx/lib/jx_combined.css
===================================================================
--- trunk/jx/lib/jx_combined.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/lib/jx_combined.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,1105 +0,0 @@
-/*
-Copyright (c) 2006, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 0.11.0
-*/
-body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
-table{border-collapse:collapse;border-spacing:0;}
-fieldset,img{border:0;}
-address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
-ol,ul {list-style:none;}
-caption,th {text-align:left;}
-h1,h2,h3,h4,h5,h6{font-size:100%;}
-q:before,q:after{content:'';}
-/*
-DMSG additions for Jx
-*/
-a{outline:none;}
-.png24{filter:expression(Jx.applyPNGFilter(this))}
-.jxClearer{display:block;position:relative;float:none;clear:both;font-size:0;line-height:0;width:0;height:0;margin:0;padding:0;}
-.jxDisabled{opacity:0.4;-moz-opacity:0.4;filter:Alpha(opacity=40);}
-/**
- * @project         Jx
- * @revision        $Id: button.css 396 2007-09-05 01:24:59Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ============= */
-/* BUTTON STYLES */
-/* ============= */
-
-div.jxButtonContainer {
-  display: block;
-  position: relative;
-  float: left;
-}
-
-/* jxButtons consist of an A, containing a SPAN, which contains an image.
-   Buttons can use the sliding door technique with background images to horizontally
-   accomodate icons with labels. */
-
-a.jxButton {
-  display: block;
-  position: relative;
-  float: left;
-}
-
-span.jxButtonSpan {
-  /* If using background images, the SPAN contains the right side of the background */
-  /* use padding to make space between the icon and button edge */
-  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
-  display: block;
-  position: relative;
-  float: left;
-  font-size: 0px;
-  line-height: 0px;
-}
-
-img.jxButtonIcon {
-  position: relative;
-  float: left;
-}
-
-span.jxButtonLabel {
-  display: block;
-  position: relative;
-  float: left;
-  cursor: pointer;
-}
-
-span.jxButtonLabel.jxButtonEmptyLabel {
-  /* collapse empty labels */
-  padding: 0px;
-  width: 0px;
-  overflow: hidden;
-}
-
-.jxButtonMenu a span.jxButtonLabel.jxButtonEmptyLabel, 
-a.jxButtonFlyout span.jxButtonLabel.jxButtonEmptyLabel {
-  /* expand empty labels that have a menu */
-  overflow: visible;
-}
-
-span.jxButtonEmptyLabel {
-  /* collapse empty labels for FF */
-}
-
-.jxFlyout {
-    position: absolute;
-    display: block;
-    clear: both;
-    float: none;
-    top: 100%;
-    left: 0px;
-    z-index: 100;
-}
-
-.jxButtonContentTop .jxFlyout {
-  top: auto;
-  bottom: 100%;
-}
-
-.jxButtonContentLeft .jxFlyout  {
-  left: auto;
-  right: 0px;
-}
-/**
- * @project         Jx
- * @revision        $Id: color.css 404 2007-09-10 20:03:57Z fwarnock $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* =================== */
-/* COLOR PICKER STYLES */
-/* =================== */
-
-/*.jxColorPicker {
-    position: absolute;
-    display: none;
-    top: 100%;
-    width: 212px;
-    left: 0px;
-    border: 1px solid #000;
-    padding: 2px;
-    background-color: #eee;
-}*/
-
-.jxColorBar {
-    position: relative;
-}
-
-table.jxColorGrid {
-    position: relative;
-    border-collapse: collapse;
-    empty-cells: show;
-    clear:both;
-}
-
-.jxColorGrid td {
-    border: 1px solid #000;
-}
-
-.jxColorGrid td.emptyCell {
-    border: 0px solid #000;
-}
-
-.jxColorGrid td.emptyCell span {
-    display: block;
-    width: 7px;
-    height: 7px;
-    line-height: 0px;
-    font-size: 0px;
-    border: 0px solid #000;
-    padding: 1px;
-    margin: 0px;
-}
-
-.jxColorGrid a.colorSwatch {
-    display: block;
-    width: 7px;
-    height: 7px;
-    line-height: 0px;
-    font-size: 0px;
-    border: 0px solid #000;
-    margin: 0px;
-    padding: 1px;
-}
-
-.jxColorGrid a.borderWhite:hover {
-    border: 1px solid #fff;
-    padding: 0px;
-}
-
-.jxColorGrid a.borderBlack:hover {
-    border: 1px solid #000;
-    padding: 0px;
-}
-
-input.jxHexInput {
-    width: 55px;
-    vertical-align: middle;
-}
-
-input.jxAlphaInput {
-    width: 30px;
-    vertical-align: middle;
-}
-
-div.jxColorPreview {
-    float: left;
-    position: relative;
-    width: 20px;
-    height: 20px;
-    border: 1px solid #000;
-    margin: 2px;
-    vertical-align: middle;
-    background-image: url('../images/grid.png');
-}
-
-div.jxColorButtonPreview {
-    float: left;
-    width: 14px;
-    height: 14px;
-    border: 1px solid #000;
-    background-image: url('../images/grid.png');
-}
-
-div.jxColorButtonPreview div {
-    width: 14px;
-    height: 14px;
-    position: absolute;
-}
-
-div.jxColorPreview img {
-    position: absolute;
-    z-index: 0;
-}
-
-div.jxColorPreview div {
-    width: 20px;
-    height: 20px;
-    position: absolute;
-    z-index: 1;
-}
-
-
-label.jxColorLabel,
-label.jxAlphaLabel {
-    width: auto;
-    font-family: Arial, sans-serif;
-    font-size: 12px;
-    line-height: 24px;
-    padding: 2px;
-    vertical-align: middle;
-}
-
-a.jxColorClose {
-    position: absolute;
-    top: 0px;
-    right: 0px;
-    width: 20px;
-    height: 20px;
-}
-
-a.jxColorClose img {
-    width: 20px;
-    height: 20px;
-}/**
- * @project         Jx
- * @revision        $Id: dialog.css 512 2008-03-07 21:15:45Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ============= */
-/* DIALOG STYLES */
-/* ============= */
-
-.jxDialogContainer {
-    position:absolute;
-    display: block;
-    font-size: 0px;
-    line-height: 0px;
-}
-
-.jxDialog {
-    display: block;
-    z-index: 1;
-}
-
-.jxDialogModal {
-    position: absolute;
-    display: block;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-}
-
-.jxDialogBgTL, 
-.jxDialogBgT,
-.jxDialogBgTR,
-.jxDialogBgR,
-.jxDialogBgBR,
-.jxDialogBgB,
-.jxDialogBgBL,
-.jxDialogBgL {
-    position: absolute;
-}
-
-.jxDialogBgTL img,
-.jxDialogBgT img,
-.jxDialogBgTR img,
-.jxDialogBgR img,
-.jxDialogBgBR img,
-.jxDialogBgB img,
-.jxDialogBgBL img,
-.jxDialogBgL img {
-    position: relative;
-}
-
-.jxDialogTitle {
-    position: relative;
-    display: block;
-}
-
-
-/* the Dialog Help Area is likely to be depricated */
-
-.jxDialogHelp {
-    position: absolute;
-    left: 100%;
-    top: 21px;
-    width: 200px;
-    height: 100px;
-    border: 1px solid #999;
-    background-color: #fff;
-    overflow: auto;
-    padding: 0px;
-}
-
-.jxDialogHelpCloseButton {
-    position: absolute;
-    top: 2px;
-    right: 2px;
-}
-
-.jxDialogContent {
-    position:relative;
-    overflow: auto;    
-    display: block;
-}
-
-.jxDialogAction {
-    position: relative;
-    overflow: hidden;
-    display: block;
-}
-
-.jxDialogCloseButton, 
-.jxDialogHelpButton {
-    position: absolute;
-    display: block;
-}
-
-.jxDialogResize {
-    position: absolute;
-}
-
-iframe.jxDialogShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}.jxGridContainer {
-    position: absolute;
-    top: 0;
-    left: 0;
-    border-left: 0px solid #96a7b4;
-    border-top: 0px solid #96a7b4;
-    border-right: 1px solid #96a7b4;
-    border-bottom: 1px solid #96a7b4;
-    overflow: hidden;
-    font-family: Arial, Verdana, sans-serif;
-    font-size: 12px;
-    font-weight: normal;
-}
-
-.jxGridTable {
-    position: relative;
-    table-layout: fixed;
-    border-collapse: collapse;
-    border-style: none;
-    width: 0px;
-}
-
-.jxGridColHeadHide {
-    height: 0px;
-    line-height: 0px;
-    font-size: 0px;
-    background-color: #fff;
-    white-space: normal;
-}
-
-.jxGridColHeadHide p, .jxGridRowHeadHide p {
-    font-size: 0px;
-    line-height: 0px;
-    height: 0px;
-    margin: 0px;
-    padding: 0px;
-}
-
-.jxGridRowHeadHide {
-    width: 0px;
-    white-space: normal;
-}
-
-.jxGridCell {
-    border-right: 1px solid #cecece;
-    border-bottom: 1px solid #cecece;
-    overflow: hidden;
-    padding-left: 3px;
-    padding-right: 3px;
-    overflow: hidden;
-    /* can change this to normal */
-    white-space: nowrap;
-    /* only applies in IE and Safari right now */
-    text-overflow: ellipsis;
-}
-
-.jxGridColHead {
-    border-top: 0px solid  #96a7b4;
-    border-right: 1px solid #96a7b4;
-    border-bottom: 1px solid #96a7b4;
-    border-left: 0px solid  #96a7b4;
-    background-color: #ebebeb;
-    text-align: center;
-    font-weight: bold;
-    color: #45525f;
-}
-
-.jxGridRowHead {
-    border-top: 0px solid #96a7b4;
-    border-right: 1px solid #96a7b4;
-    border-bottom: 1px solid #96a7b4;
-    border-left: 0px solid #96a7b4;
-    background-color:  #ebebeb;
-    text-align: center;
-    font-weight: bold;
-    color: #45525f;
-}
-
-.jxGridRowAll {
-    background-color: #fff;
-}
-
-.jxGridRowOdd {
-    /*background-color: pink;*/
-}
-
-.jxGridRowEven {
-    /*background-color: lime;*/
-}
-
-.jxGridRowOdd td {
-    border-right: 1px solid #999;
-    border-bottom: 1px solid #999;
-}
-
-.jxGridRowEven td {
-    border-right: 1px solid #999;
-    border-bottom: 1px solid #999;
-}
-
-.jxGridRowSelected {
-    background-color: #dae6f2;
-}
-
-.jxGridColumnSelected {
-    background-color: #dae6f2;
-}
-
-.jxGridCellSelected {
-    background-color: #dae6f2;
-}
-
-.jxGridRowPrelight {
-    background-color: #f2f2f2;
-}
-
-.jxGridCellPrelight {
-    /*background-color: green;*/
-}
-
-.jxGridRowHeaderPrelight {
-    background-color: #dfdfdf;
-}
-
-.jxGridColumnHeaderPrelight {
-    background-color: #dfdfdf;
-}
-
-.jxGridRowHeaderSelected {
-    background-color: #6d7f8e;
-    color: #fff;
-}
-
-.jxGridColumnHeaderSelected {
-    background-color: #6d7f8e;
-    color: #fff;
-}/**
- * @project         Jx
- * @revision        $Id: menu.css 406 2007-09-13 14:42:18Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ============== */
-/* JX MENU STYLES */
-/* ============== */
-
-/* Jx Menus and Sub-menus are all built out of nested ULs
-   For this to work visually, the margins and padding need to be flattened
-   out, and the list marker needs to be hidden
-*/
-
-ul.jxMenu, ul.jxSubMenu {
-  /* this allows menus and submenus to be re-positioned */
-  position: absolute;
-  display: block;
-  clear: both;
-  float: none;
-  /* this allows menus and sub menus to appear above everything */
-  z-index: 100;
-  list-style-type: none;
-}
-
-ul.jxMenu {
-    top: 100%;
-    left: 0px;
-}
-
-.jxButtonContentTop ul.jxMenu {
-  top: auto;
-  bottom: 100%;
-}
-
-.jxButtonContentLeft ul.jxMenu  {
-  left: auto;
-  right: 0px;
-}
-
-li.jxMenuItem, li.jxSubMenuItem {
-  /* This is needed for IE to make sure submenus don't open space in the parent menu */
-  display: inline;
-  clear: both;
-  float: none;
-}
-
-li.jxMenuItem div.jxButtonContainer {
-  float: none;
-}
-
-ul.jxMenu a, ul.jxSubMenu a {
-  display: block;
-  text-decoration: none;
-  white-space: nowrap;
-  clear: both;
-  float: none;
-}
-
-ul.jxMenu img, ul.jxSubMenu img {
-	padding-right: 5px;
-}
-
-ul.jxMenu span, ul.jxSubMenu span {
-  display: block;
-/*  clear: both; */ /*this caused a problem where menu's with images wrapped*/
-  float: none;
-}
-
-ul.jxMenu span.jxMenuSeparator {
-	display: block;
-}
-
-iframe.jxMenuShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}/**
- * @project         Jx
- * @revision        $Id: panel.css 375 2007-08-21 14:36:10Z fwarnock $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* =============== */
-/* JX PANEL STYLES */
-/* =============== */
-
-.jxPanel {
-  position:relative;
-}
-
-/* the content panel inside a panel */
-.jxPanelContent {
-  /* position relative is required for panels to work correctly in safari */
-  position: relative;
-  display: block;
-  /* set the width to 100% to make the content resize properly when the container resizes */
-  width: 100%;
-  /* height gets set by javascript */
-  height: auto;
-  /* content gains scroll bars as needed */
-  overflow: auto;
-  border-top: 1px solid #fff;
-  border-bottom: 1px solid #999;
-  margin: 0px;
-  padding: 0px;
-  border-top: none;
-  background-color: #fff;
-  /*white-space: nowrap;*/ /* need wrapping off for trees */
-}
-
-/* ======================= */
-/* JX PANEL MANAGER STYLES */
-/* ======================= */
-
-.jxPanelTitle {
-  /* position relative is required for panel dragging to work correctly in safari */
-  position:relative;
-  width: 100%;
-  background-image: url(../images/snap_bg.png);
-  background-repeat: repeat-x;
-  background-position: left top;
-  border-top: 1px solid #fff;
-  border-bottom: 1px solid #666;
-  /* note this is hard coded into jx.js JxPanel initialize function - change there as well as here */
-  height: 22px;
-  margin: 0;
-  padding: 0;
-  /* this prevents lines from wrapping when content is resized */
-  white-space: nowrap;
-/*  -moz-box-sizing: border-box;*/
-}
-
-.jxPanelLabel {
-  /* make room for the loading spinner */
-  padding-left: 25px;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 12px;
-  font-weight: bold;
-  /* line-height vertically aligns the label in the containing div.  In the border
-     box model, this should be the containers height less padding and borders.  In
-     the content box model, it should be the height of the container.  */
-  line-height:21px;
-  /* make the text align properly with an neighbouring inline image */
-  /*vertical-align: top;*/
-  color: #000;
-}
-
-a.jxPanelMaximize, 
-a.jxPanelHelp {
-  position: absolute;
-  top: 1px;
-  padding: 0px;
-  margin: 0px; 
-  border: 0px;
-  width: 20px;
-  height: 20px;
-}
-
-.jxPanelTitle a.jxPanelHelp {
-  right: 20px;
-}
-
-.jxPanelTitle a.jxPanelMaximize {
-  right: 2px;
-}
-
-/* removed - this is a WebStudio specific style and needs to be moved there when
-   we update WebStudio */
-
-/*
-.jxPanelTitle a.jxPanelClose {
-  right: 2px;
-  z-index: 10;
-
-}
-*/
-
-a.jxPanelMaximize img,  
-a.jxPanelHelp img, 
-a.jxPanelLoading img {
-  border: 0px;
-  /* the margin needs to make up the difference between it's width/height
-     and the width/height of the parent a */
-  margin: 0px;
-  /* width/height has to be the actual image width/height */
-  width: 20px;
-  height: 20px;
-}
-
-a.jxPanelLoading img {
-  visibility:hidden;
-  position: absolute;
-  top: 1px;
-  left: 2px;
-}
-/**
- * @project         Jx
- * @revision        $Id: picker.css 516 2008-03-10 23:21:04Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ============= */
-/* PICKER STYLES */
-/* ============= */
-
-/* the jx Picker is intended to replace lists and combo boxes that require 
-   a richer set of features such as text input, images and styles in the
-   selection list and better control over the list size. */
-
-div.jxPicker {
-  position: relative;
-  display: block;
-  padding: 0px;
-  padding-right: 22px;
-  margin: 0px;
-  border: 0px;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size:11px;
-  z-index: 1;
-  line-height: 24px;
-  float: left;
-}
-
-.jxPickerDiscloser {
-  position: absolute;
-  right: 3px;
-  top: 3px;
-}
-
-.jxPickerDiscloser img {
-  width: 16px;
-  height: 16px;
-  border: 0px;
-}
-
-.jxPickerInput {
-  position: relative;
-  display: block;
-  float: left;
-  /*padding-right: 16px;*/
-  line-height: 24px;
-  height: 24px;
-  padding: 0px 10px;
-}
-
-div.jxPickerOptions {
-  position: absolute;
-  top: 100%;
-  left: 0px;
-  width: 100%;
-  height: auto;
-  background-color: #fff;
-  overflow: auto;
-  border: 1px solid #333;
-  color: #000;
-  z-index: 1;
-  display: none;
-  text-align: right;
-}
-
-div.jxPickerOptions ul {
-  position: relative;
-  display: block;
-  margin: 0px;
-  padding: 0px;
-  border: none;
-  list-style-type: none;
-}
-
-div.jxPickerOptions li {
-  position: relative;
-  display: block;
-  margin: 0px;
-  padding: 0px;
-  border: none;
-  height:20px;
-}
-
-div.jxPickerOptions a {
-  position: relative;
-  display: block;
-  text-decoration: none;
-  white-space: nowrap;
-  /* this value needs to be the height of it's parent
-     minus it's own margin, padding and border values */ 
-  line-height:20px;
-  /* height needs to be set for IE.  Same value as line height. */
-  height: 20px;
-  color: #000;
-  background-position: right top;
-  background-repeat: no-repeat;
-  padding: 0px 4px;
-}
-
-div.jxPickerOptions a:hover {
-  background-color: #E1EDFA; 
-  /*background-color: #ffffcc; */
-}
-
-div.jxPickerOptions a.selected {
-  font-weight: bold;
-  background-color: #ffffb3;
-}
-/**
- * @project         Jx
- * @revision        $Id: tabs.css 512 2008-03-07 21:15:45Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ========== */
-/* TAB STYLES */
-/* ========== */
-
-/* Note: There are some specific styles for IE in tabs_ie.css
-
-   The tabBox consists of a box containing a tabbar and the tab content areas.
-   It can be used within the body or nested within another object.
-*/
-
-.jxTabSetContainer {
-  /* This is an example of a container that can be used to hold a tabBox
-     the position need to be explicitly set, as well as the width and height. */
-  position: relative; 
-  display: block;
-
-}
-
-.jxTabSetContainer  .jxToolbarContainer {
-  z-index: auto;
-}
-
-.tabContent {
-  /* the width and height need to be set to 100% to:
-     1. fill the tab box area
-     2. allow a scrolling content area in IE */
-  display: none;
-  position: relative;
-  width:100%;
-  height: 100%;
-  overflow: auto;
-}
-
-.tabContentActive {
-  display: block;
-}
-
-/* TAB BOX MODE */
-.jxTabBoxTop,
-.jxTabBoxBottom,
-.jxTabBoxLeft,
-.jxTabBoxRight {
-  overflow: visible;
-}
-
-/* TAB BOX MODE */
-.jxTabBoxTop .jxBarTop,
-.jxTabBoxBottom .jxBarBottom,
-.jxTabBoxLeft .jxBarLeft,
-.jxTabBoxRight .jxBarRight {
-  position: absolute;
-}
-
-
-/* The tabbar is built out of a UL
-   The tab background uses the sliding door technique so tabs can expand to
-   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
-   (left/right tabs).  All parts and states of the tab BG graphics are in the 
-   same image so they can be treated like sprites.
-
-   Horizontal tabs can contain text or an image label.  Vertical tabs need an
-   image label.
-*/
-
-/**
- * @project         Jx
- * @revision        $Id: toolbar.css 369 2007-07-26 17:24:23Z fwarnock $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* ============== */
-/* TOOLBAR STYLES */
-/* ============== */
-
-/* Multiple toolbars can be housed in  the toolbar container the container will expand
-   vertically to accomodate wrapped toolbars */
-.jxToolbarContainer {
-  display: block;
-  position: relative;
-  z-index: 1;
-}
-
-/* Horizontally oriented toolbars */
-.jxBarTop, 
-.jxBarBottom {
-  width: 100%; /* fills the width, may be needed for JS style sniffing */
-  height: auto; /* since the last element clears the float, a height may not be needed */
-}
-
-/* Vertically oriented toolbars */
-.jxBarLeft, 
-.jxBarRight {
-  width: auto;
-  height: 100%;
-}
-
-/* a label can optionally be used preceeding a toolbar.
-   the line height is used to center the label relative to the toolbar. */
-.toolbarLabel {
-  display: block;
-  position: relative;
-  float: left;
-}
-
-/* The jx toolbar is built out of a UL
-   For this to work visually, the margins and padding need to be flattened
-   out, and the list markers need to be hidden 
-   UL's are floated left so multiple toolbars can be in the samae row.
-   In IE, the UL needs to have a specified width to prevent button wrapping. */
-
-ul.jxToolbar {
-  display: block;
-  position: relative;
-  float: left;
-  list-style-type: none;
-}
-
-/* LI's are floated to the left, to make a horizontal row of buttons*/
-li.jxToolItem {
-  display: block;
-  position: relative;
-  float: left;
-  font-size: 0px;
-  line-height: 0px;
-}
-
-/* Seperator height should match that of button images
-   and the margins+padding+border should add up to the same total too. */
-li.jxToolItem  .separator {
-  display: block;
-  position: relative;
-  float: left;
-  font-size: 0px;
-  line-height: 0px;
-}
-
-/* Vertically oriented toolbars need floats cleared */
-.jxBarLeft label.toolbarLabel,
-.jxBarLeft ul.jxToolbar,
-.jxBarLeft li.jxToolItem,
-.jxBarRight label.toolbarLabel,
-.jxBarRight ul.jxToolbar,
-.jxBarRight li.jxToolItem
-{
-  clear: both;
-}
-
-
-/* DEPRICATED STYLES */
-
-/* Vertically oriented toolbars do not need to fill their containers horizontally */
-.verticalToolbar {
-  width: auto;
-}
-
-/* Vertically oriented toolbars need floats cleared */
-.verticalToolbar label.toolbarLabel,
-.verticalToolbar ul.jxToolbar,
-.verticalToolbar li.jxToolItem
-{
-  clear: both;
-}
-
-/**
- * @project         Jx
- * @revision        $Id: tree.css 324 2007-06-20 19:04:54Z pspencer $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       &copy; 2006 DM Solutions Group Inc.
- */
-
-/* =========== */
-/* TREE STYLES */
-/* =========== */
-
-/* The jx tree built out of nested ULs
-   For this to work visually, the margins and padding need to be flattened
-   out, and the list marker needs to be hidden
-*/
-
-
-.jxTree, .jxTreeRoot {
-  /* relative positioning is required for IE to fix the peek-a-boo bug */
-  position:relative;
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-}
-
-.jxTreeNest {
-  list-style: none;
-  margin: 0px;
-  padding: 0px;
-  background-repeat: repeat-y;
-  background-position: left top;
-}
-
-/* Node Classes */
-
-.jxTree li, .jxTreeRoot li {
-  /* relative positioning is required for IE to fix the peek-a-boo bug */
-  position:relative;
-  margin: 0px;
-  padding: 0px;
-  background-repeat: no-repeat;
-  /* background branches may need to shift up/down according to height of the node */
-  background-position: left top;
-  white-space: nowrap;
-  width: 100%;
-}
-
-.jxTree li {
-  margin-left: 16px;
-}
-
-.jxTree li.jxDisabled, .jxTreeRoot li.jxDisabled {   
-  opacity: 0.4; /* css 3 */
-  -moz-opacity: 0.4; /* moz-specific */
-  filter: Alpha(opacity=40); /* IE only */
-}
-
-.jxTree a, .jxTreeRoot a {
-  margin: 0px;
-  padding: 0px;
-  padding-left: 2px;
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 11px;
-  color: #000;
-  text-decoration: none;
-  /* Line Height needs to be an even number so branches line up properly */
-  line-height: 20px;
-}
-
-.jxTree a:hover, .jxTreeRoot a:hover {
-  background-color: #E1EDFA; 
-  /*background-color: #ffffcc; */
-}
-
-.jxTree img, .jxTreeRoot img {
-  border: 0px;
-  width: 16px;
-  height: 16px;
-}
-
-.jxTreeNest         {background-image: url(../images/tree_vert_line.png);}
-.jxTreeNode         {background-image: url(../images/tree_node.png);}
-.jxTreeNodeLast     {background-image: url(../images/tree_last_node.png);}
-
-.jxTreeDropzone {
-  text-decoration:underline;
-  font-weight:bold;
-}
-
-.jxTreeSelectedNode {
-  background-color: #AFD4FA;
-  /*background-color: #ddffaa; */
-  font-weight:bold;
-}
-
-.jxTreeCutNode {
-  opacity: 0.4; /* css 3 */
-  -moz-opacity: 0.4; /* moz-specific */
-  filter: Alpha(opacity=40); /* IE only */
-}
-
-.jxTreeCutNode a:hover {
-  background-color: #fff; 
-}
-
-.jxTreeNode, .jxTreeNodeLast {
-/*    width: 100%;*/
-}
-
-.jxTreeNode a, .jxTreeNode img, .jxTreeNode input {
-    vertical-align: middle;
-}
-
-.jxTreeNodeLast a, .jxTreeNodeLast img, .jxTreeNodeLast input {
-    vertical-align: middle;
-}
-
-.jxTreeNodeImage {
-}
-
-.jxTreeNodeIcon {
-    margin: 0px;
-}
\ No newline at end of file

Copied: sandbox/aboudreault/jx/lib/jx_combined.css (from rev 1352, trunk/jx/lib/jx_combined.css)
===================================================================
--- sandbox/aboudreault/jx/lib/jx_combined.css	                        (rev 0)
+++ sandbox/aboudreault/jx/lib/jx_combined.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,1105 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
+table{border-collapse:collapse;border-spacing:0;}
+fieldset,img{border:0;}
+address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
+ol,ul {list-style:none;}
+caption,th {text-align:left;}
+h1,h2,h3,h4,h5,h6{font-size:100%;}
+q:before,q:after{content:'';}
+/*
+DMSG additions for Jx
+*/
+a{outline:none;}
+.png24{filter:expression(Jx.applyPNGFilter(this))}
+.jxClearer{display:block;position:relative;float:none;clear:both;font-size:0;line-height:0;width:0;height:0;margin:0;padding:0;}
+.jxDisabled{opacity:0.4;-moz-opacity:0.4;filter:Alpha(opacity=40);}
+/**
+ * @project         Jx
+ * @revision        $Id: button.css 396 2007-09-05 01:24:59Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ============= */
+/* BUTTON STYLES */
+/* ============= */
+
+div.jxButtonContainer {
+  display: block;
+  position: relative;
+  float: left;
+}
+
+/* jxButtons consist of an A, containing a SPAN, which contains an image.
+   Buttons can use the sliding door technique with background images to horizontally
+   accomodate icons with labels. */
+
+a.jxButton {
+  display: block;
+  position: relative;
+  float: left;
+}
+
+span.jxButtonSpan {
+  /* If using background images, the SPAN contains the right side of the background */
+  /* use padding to make space between the icon and button edge */
+  /* padding-left: 0px;*/ /* butts up to the left of the button bg image */
+  display: block;
+  position: relative;
+  float: left;
+  font-size: 0px;
+  line-height: 0px;
+}
+
+img.jxButtonIcon {
+  position: relative;
+  float: left;
+}
+
+span.jxButtonLabel {
+  display: block;
+  position: relative;
+  float: left;
+  cursor: pointer;
+}
+
+span.jxButtonLabel.jxButtonEmptyLabel {
+  /* collapse empty labels */
+  padding: 0px;
+  width: 0px;
+  overflow: hidden;
+}
+
+.jxButtonMenu a span.jxButtonLabel.jxButtonEmptyLabel, 
+a.jxButtonFlyout span.jxButtonLabel.jxButtonEmptyLabel {
+  /* expand empty labels that have a menu */
+  overflow: visible;
+}
+
+span.jxButtonEmptyLabel {
+  /* collapse empty labels for FF */
+}
+
+.jxFlyout {
+    position: absolute;
+    display: block;
+    clear: both;
+    float: none;
+    top: 100%;
+    left: 0px;
+    z-index: 100;
+}
+
+.jxButtonContentTop .jxFlyout {
+  top: auto;
+  bottom: 100%;
+}
+
+.jxButtonContentLeft .jxFlyout  {
+  left: auto;
+  right: 0px;
+}
+/**
+ * @project         Jx
+ * @revision        $Id: color.css 404 2007-09-10 20:03:57Z fwarnock $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* =================== */
+/* COLOR PICKER STYLES */
+/* =================== */
+
+/*.jxColorPicker {
+    position: absolute;
+    display: none;
+    top: 100%;
+    width: 212px;
+    left: 0px;
+    border: 1px solid #000;
+    padding: 2px;
+    background-color: #eee;
+}*/
+
+.jxColorBar {
+    position: relative;
+}
+
+table.jxColorGrid {
+    position: relative;
+    border-collapse: collapse;
+    empty-cells: show;
+    clear:both;
+}
+
+.jxColorGrid td {
+    border: 1px solid #000;
+}
+
+.jxColorGrid td.emptyCell {
+    border: 0px solid #000;
+}
+
+.jxColorGrid td.emptyCell span {
+    display: block;
+    width: 7px;
+    height: 7px;
+    line-height: 0px;
+    font-size: 0px;
+    border: 0px solid #000;
+    padding: 1px;
+    margin: 0px;
+}
+
+.jxColorGrid a.colorSwatch {
+    display: block;
+    width: 7px;
+    height: 7px;
+    line-height: 0px;
+    font-size: 0px;
+    border: 0px solid #000;
+    margin: 0px;
+    padding: 1px;
+}
+
+.jxColorGrid a.borderWhite:hover {
+    border: 1px solid #fff;
+    padding: 0px;
+}
+
+.jxColorGrid a.borderBlack:hover {
+    border: 1px solid #000;
+    padding: 0px;
+}
+
+input.jxHexInput {
+    width: 55px;
+    vertical-align: middle;
+}
+
+input.jxAlphaInput {
+    width: 30px;
+    vertical-align: middle;
+}
+
+div.jxColorPreview {
+    float: left;
+    position: relative;
+    width: 20px;
+    height: 20px;
+    border: 1px solid #000;
+    margin: 2px;
+    vertical-align: middle;
+    background-image: url('../images/grid.png');
+}
+
+div.jxColorButtonPreview {
+    float: left;
+    width: 14px;
+    height: 14px;
+    border: 1px solid #000;
+    background-image: url('../images/grid.png');
+}
+
+div.jxColorButtonPreview div {
+    width: 14px;
+    height: 14px;
+    position: absolute;
+}
+
+div.jxColorPreview img {
+    position: absolute;
+    z-index: 0;
+}
+
+div.jxColorPreview div {
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    z-index: 1;
+}
+
+
+label.jxColorLabel,
+label.jxAlphaLabel {
+    width: auto;
+    font-family: Arial, sans-serif;
+    font-size: 12px;
+    line-height: 24px;
+    padding: 2px;
+    vertical-align: middle;
+}
+
+a.jxColorClose {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+    width: 20px;
+    height: 20px;
+}
+
+a.jxColorClose img {
+    width: 20px;
+    height: 20px;
+}/**
+ * @project         Jx
+ * @revision        $Id: dialog.css 512 2008-03-07 21:15:45Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ============= */
+/* DIALOG STYLES */
+/* ============= */
+
+.jxDialogContainer {
+    position:absolute;
+    display: block;
+    font-size: 0px;
+    line-height: 0px;
+}
+
+.jxDialog {
+    display: block;
+    z-index: 1;
+}
+
+.jxDialogModal {
+    position: absolute;
+    display: block;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+}
+
+.jxDialogBgTL, 
+.jxDialogBgT,
+.jxDialogBgTR,
+.jxDialogBgR,
+.jxDialogBgBR,
+.jxDialogBgB,
+.jxDialogBgBL,
+.jxDialogBgL {
+    position: absolute;
+}
+
+.jxDialogBgTL img,
+.jxDialogBgT img,
+.jxDialogBgTR img,
+.jxDialogBgR img,
+.jxDialogBgBR img,
+.jxDialogBgB img,
+.jxDialogBgBL img,
+.jxDialogBgL img {
+    position: relative;
+}
+
+.jxDialogTitle {
+    position: relative;
+    display: block;
+}
+
+
+/* the Dialog Help Area is likely to be depricated */
+
+.jxDialogHelp {
+    position: absolute;
+    left: 100%;
+    top: 21px;
+    width: 200px;
+    height: 100px;
+    border: 1px solid #999;
+    background-color: #fff;
+    overflow: auto;
+    padding: 0px;
+}
+
+.jxDialogHelpCloseButton {
+    position: absolute;
+    top: 2px;
+    right: 2px;
+}
+
+.jxDialogContent {
+    position:relative;
+    overflow: auto;    
+    display: block;
+}
+
+.jxDialogAction {
+    position: relative;
+    overflow: hidden;
+    display: block;
+}
+
+.jxDialogCloseButton, 
+.jxDialogHelpButton {
+    position: absolute;
+    display: block;
+}
+
+.jxDialogResize {
+    position: absolute;
+}
+
+iframe.jxDialogShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}.jxGridContainer {
+    position: absolute;
+    top: 0;
+    left: 0;
+    border-left: 0px solid #96a7b4;
+    border-top: 0px solid #96a7b4;
+    border-right: 1px solid #96a7b4;
+    border-bottom: 1px solid #96a7b4;
+    overflow: hidden;
+    font-family: Arial, Verdana, sans-serif;
+    font-size: 12px;
+    font-weight: normal;
+}
+
+.jxGridTable {
+    position: relative;
+    table-layout: fixed;
+    border-collapse: collapse;
+    border-style: none;
+    width: 0px;
+}
+
+.jxGridColHeadHide {
+    height: 0px;
+    line-height: 0px;
+    font-size: 0px;
+    background-color: #fff;
+    white-space: normal;
+}
+
+.jxGridColHeadHide p, .jxGridRowHeadHide p {
+    font-size: 0px;
+    line-height: 0px;
+    height: 0px;
+    margin: 0px;
+    padding: 0px;
+}
+
+.jxGridRowHeadHide {
+    width: 0px;
+    white-space: normal;
+}
+
+.jxGridCell {
+    border-right: 1px solid #cecece;
+    border-bottom: 1px solid #cecece;
+    overflow: hidden;
+    padding-left: 3px;
+    padding-right: 3px;
+    overflow: hidden;
+    /* can change this to normal */
+    white-space: nowrap;
+    /* only applies in IE and Safari right now */
+    text-overflow: ellipsis;
+}
+
+.jxGridColHead {
+    border-top: 0px solid  #96a7b4;
+    border-right: 1px solid #96a7b4;
+    border-bottom: 1px solid #96a7b4;
+    border-left: 0px solid  #96a7b4;
+    background-color: #ebebeb;
+    text-align: center;
+    font-weight: bold;
+    color: #45525f;
+}
+
+.jxGridRowHead {
+    border-top: 0px solid #96a7b4;
+    border-right: 1px solid #96a7b4;
+    border-bottom: 1px solid #96a7b4;
+    border-left: 0px solid #96a7b4;
+    background-color:  #ebebeb;
+    text-align: center;
+    font-weight: bold;
+    color: #45525f;
+}
+
+.jxGridRowAll {
+    background-color: #fff;
+}
+
+.jxGridRowOdd {
+    /*background-color: pink;*/
+}
+
+.jxGridRowEven {
+    /*background-color: lime;*/
+}
+
+.jxGridRowOdd td {
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
+}
+
+.jxGridRowEven td {
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
+}
+
+.jxGridRowSelected {
+    background-color: #dae6f2;
+}
+
+.jxGridColumnSelected {
+    background-color: #dae6f2;
+}
+
+.jxGridCellSelected {
+    background-color: #dae6f2;
+}
+
+.jxGridRowPrelight {
+    background-color: #f2f2f2;
+}
+
+.jxGridCellPrelight {
+    /*background-color: green;*/
+}
+
+.jxGridRowHeaderPrelight {
+    background-color: #dfdfdf;
+}
+
+.jxGridColumnHeaderPrelight {
+    background-color: #dfdfdf;
+}
+
+.jxGridRowHeaderSelected {
+    background-color: #6d7f8e;
+    color: #fff;
+}
+
+.jxGridColumnHeaderSelected {
+    background-color: #6d7f8e;
+    color: #fff;
+}/**
+ * @project         Jx
+ * @revision        $Id: menu.css 406 2007-09-13 14:42:18Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ============== */
+/* JX MENU STYLES */
+/* ============== */
+
+/* Jx Menus and Sub-menus are all built out of nested ULs
+   For this to work visually, the margins and padding need to be flattened
+   out, and the list marker needs to be hidden
+*/
+
+ul.jxMenu, ul.jxSubMenu {
+  /* this allows menus and submenus to be re-positioned */
+  position: absolute;
+  display: block;
+  clear: both;
+  float: none;
+  /* this allows menus and sub menus to appear above everything */
+  z-index: 100;
+  list-style-type: none;
+}
+
+ul.jxMenu {
+    top: 100%;
+    left: 0px;
+}
+
+.jxButtonContentTop ul.jxMenu {
+  top: auto;
+  bottom: 100%;
+}
+
+.jxButtonContentLeft ul.jxMenu  {
+  left: auto;
+  right: 0px;
+}
+
+li.jxMenuItem, li.jxSubMenuItem {
+  /* This is needed for IE to make sure submenus don't open space in the parent menu */
+  display: inline;
+  clear: both;
+  float: none;
+}
+
+li.jxMenuItem div.jxButtonContainer {
+  float: none;
+}
+
+ul.jxMenu a, ul.jxSubMenu a {
+  display: block;
+  text-decoration: none;
+  white-space: nowrap;
+  clear: both;
+  float: none;
+}
+
+ul.jxMenu img, ul.jxSubMenu img {
+	padding-right: 5px;
+}
+
+ul.jxMenu span, ul.jxSubMenu span {
+  display: block;
+/*  clear: both; */ /*this caused a problem where menu's with images wrapped*/
+  float: none;
+}
+
+ul.jxMenu span.jxMenuSeparator {
+	display: block;
+}
+
+iframe.jxMenuShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}/**
+ * @project         Jx
+ * @revision        $Id: panel.css 375 2007-08-21 14:36:10Z fwarnock $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* =============== */
+/* JX PANEL STYLES */
+/* =============== */
+
+.jxPanel {
+  position:relative;
+}
+
+/* the content panel inside a panel */
+.jxPanelContent {
+  /* position relative is required for panels to work correctly in safari */
+  position: relative;
+  display: block;
+  /* set the width to 100% to make the content resize properly when the container resizes */
+  width: 100%;
+  /* height gets set by javascript */
+  height: auto;
+  /* content gains scroll bars as needed */
+  overflow: auto;
+  border-top: 1px solid #fff;
+  border-bottom: 1px solid #999;
+  margin: 0px;
+  padding: 0px;
+  border-top: none;
+  background-color: #fff;
+  /*white-space: nowrap;*/ /* need wrapping off for trees */
+}
+
+/* ======================= */
+/* JX PANEL MANAGER STYLES */
+/* ======================= */
+
+.jxPanelTitle {
+  /* position relative is required for panel dragging to work correctly in safari */
+  position:relative;
+  width: 100%;
+  background-image: url(../images/snap_bg.png);
+  background-repeat: repeat-x;
+  background-position: left top;
+  border-top: 1px solid #fff;
+  border-bottom: 1px solid #666;
+  /* note this is hard coded into jx.js JxPanel initialize function - change there as well as here */
+  height: 22px;
+  margin: 0;
+  padding: 0;
+  /* this prevents lines from wrapping when content is resized */
+  white-space: nowrap;
+/*  -moz-box-sizing: border-box;*/
+}
+
+.jxPanelLabel {
+  /* make room for the loading spinner */
+  padding-left: 25px;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 12px;
+  font-weight: bold;
+  /* line-height vertically aligns the label in the containing div.  In the border
+     box model, this should be the containers height less padding and borders.  In
+     the content box model, it should be the height of the container.  */
+  line-height:21px;
+  /* make the text align properly with an neighbouring inline image */
+  /*vertical-align: top;*/
+  color: #000;
+}
+
+a.jxPanelMaximize, 
+a.jxPanelHelp {
+  position: absolute;
+  top: 1px;
+  padding: 0px;
+  margin: 0px; 
+  border: 0px;
+  width: 20px;
+  height: 20px;
+}
+
+.jxPanelTitle a.jxPanelHelp {
+  right: 20px;
+}
+
+.jxPanelTitle a.jxPanelMaximize {
+  right: 2px;
+}
+
+/* removed - this is a WebStudio specific style and needs to be moved there when
+   we update WebStudio */
+
+/*
+.jxPanelTitle a.jxPanelClose {
+  right: 2px;
+  z-index: 10;
+
+}
+*/
+
+a.jxPanelMaximize img,  
+a.jxPanelHelp img, 
+a.jxPanelLoading img {
+  border: 0px;
+  /* the margin needs to make up the difference between it's width/height
+     and the width/height of the parent a */
+  margin: 0px;
+  /* width/height has to be the actual image width/height */
+  width: 20px;
+  height: 20px;
+}
+
+a.jxPanelLoading img {
+  visibility:hidden;
+  position: absolute;
+  top: 1px;
+  left: 2px;
+}
+/**
+ * @project         Jx
+ * @revision        $Id: picker.css 516 2008-03-10 23:21:04Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ============= */
+/* PICKER STYLES */
+/* ============= */
+
+/* the jx Picker is intended to replace lists and combo boxes that require 
+   a richer set of features such as text input, images and styles in the
+   selection list and better control over the list size. */
+
+div.jxPicker {
+  position: relative;
+  display: block;
+  padding: 0px;
+  padding-right: 22px;
+  margin: 0px;
+  border: 0px;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size:11px;
+  z-index: 1;
+  line-height: 24px;
+  float: left;
+}
+
+.jxPickerDiscloser {
+  position: absolute;
+  right: 3px;
+  top: 3px;
+}
+
+.jxPickerDiscloser img {
+  width: 16px;
+  height: 16px;
+  border: 0px;
+}
+
+.jxPickerInput {
+  position: relative;
+  display: block;
+  float: left;
+  /*padding-right: 16px;*/
+  line-height: 24px;
+  height: 24px;
+  padding: 0px 10px;
+}
+
+div.jxPickerOptions {
+  position: absolute;
+  top: 100%;
+  left: 0px;
+  width: 100%;
+  height: auto;
+  background-color: #fff;
+  overflow: auto;
+  border: 1px solid #333;
+  color: #000;
+  z-index: 1;
+  display: none;
+  text-align: right;
+}
+
+div.jxPickerOptions ul {
+  position: relative;
+  display: block;
+  margin: 0px;
+  padding: 0px;
+  border: none;
+  list-style-type: none;
+}
+
+div.jxPickerOptions li {
+  position: relative;
+  display: block;
+  margin: 0px;
+  padding: 0px;
+  border: none;
+  height:20px;
+}
+
+div.jxPickerOptions a {
+  position: relative;
+  display: block;
+  text-decoration: none;
+  white-space: nowrap;
+  /* this value needs to be the height of it's parent
+     minus it's own margin, padding and border values */ 
+  line-height:20px;
+  /* height needs to be set for IE.  Same value as line height. */
+  height: 20px;
+  color: #000;
+  background-position: right top;
+  background-repeat: no-repeat;
+  padding: 0px 4px;
+}
+
+div.jxPickerOptions a:hover {
+  background-color: #E1EDFA; 
+  /*background-color: #ffffcc; */
+}
+
+div.jxPickerOptions a.selected {
+  font-weight: bold;
+  background-color: #ffffb3;
+}
+/**
+ * @project         Jx
+ * @revision        $Id: tabs.css 512 2008-03-07 21:15:45Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ========== */
+/* TAB STYLES */
+/* ========== */
+
+/* Note: There are some specific styles for IE in tabs_ie.css
+
+   The tabBox consists of a box containing a tabbar and the tab content areas.
+   It can be used within the body or nested within another object.
+*/
+
+.jxTabSetContainer {
+  /* This is an example of a container that can be used to hold a tabBox
+     the position need to be explicitly set, as well as the width and height. */
+  position: relative; 
+  display: block;
+
+}
+
+.jxTabSetContainer  .jxToolbarContainer {
+  z-index: auto;
+}
+
+.tabContent {
+  /* the width and height need to be set to 100% to:
+     1. fill the tab box area
+     2. allow a scrolling content area in IE */
+  display: none;
+  position: relative;
+  width:100%;
+  height: 100%;
+  overflow: auto;
+}
+
+.tabContentActive {
+  display: block;
+}
+
+/* TAB BOX MODE */
+.jxTabBoxTop,
+.jxTabBoxBottom,
+.jxTabBoxLeft,
+.jxTabBoxRight {
+  overflow: visible;
+}
+
+/* TAB BOX MODE */
+.jxTabBoxTop .jxBarTop,
+.jxTabBoxBottom .jxBarBottom,
+.jxTabBoxLeft .jxBarLeft,
+.jxTabBoxRight .jxBarRight {
+  position: absolute;
+}
+
+
+/* The tabbar is built out of a UL
+   The tab background uses the sliding door technique so tabs can expand to
+   accomodate content up to 200 px wide (top/bottom tabs) or 200px high
+   (left/right tabs).  All parts and states of the tab BG graphics are in the 
+   same image so they can be treated like sprites.
+
+   Horizontal tabs can contain text or an image label.  Vertical tabs need an
+   image label.
+*/
+
+/**
+ * @project         Jx
+ * @revision        $Id: toolbar.css 369 2007-07-26 17:24:23Z fwarnock $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* ============== */
+/* TOOLBAR STYLES */
+/* ============== */
+
+/* Multiple toolbars can be housed in  the toolbar container the container will expand
+   vertically to accomodate wrapped toolbars */
+.jxToolbarContainer {
+  display: block;
+  position: relative;
+  z-index: 1;
+}
+
+/* Horizontally oriented toolbars */
+.jxBarTop, 
+.jxBarBottom {
+  width: 100%; /* fills the width, may be needed for JS style sniffing */
+  height: auto; /* since the last element clears the float, a height may not be needed */
+}
+
+/* Vertically oriented toolbars */
+.jxBarLeft, 
+.jxBarRight {
+  width: auto;
+  height: 100%;
+}
+
+/* a label can optionally be used preceeding a toolbar.
+   the line height is used to center the label relative to the toolbar. */
+.toolbarLabel {
+  display: block;
+  position: relative;
+  float: left;
+}
+
+/* The jx toolbar is built out of a UL
+   For this to work visually, the margins and padding need to be flattened
+   out, and the list markers need to be hidden 
+   UL's are floated left so multiple toolbars can be in the samae row.
+   In IE, the UL needs to have a specified width to prevent button wrapping. */
+
+ul.jxToolbar {
+  display: block;
+  position: relative;
+  float: left;
+  list-style-type: none;
+}
+
+/* LI's are floated to the left, to make a horizontal row of buttons*/
+li.jxToolItem {
+  display: block;
+  position: relative;
+  float: left;
+  font-size: 0px;
+  line-height: 0px;
+}
+
+/* Seperator height should match that of button images
+   and the margins+padding+border should add up to the same total too. */
+li.jxToolItem  .separator {
+  display: block;
+  position: relative;
+  float: left;
+  font-size: 0px;
+  line-height: 0px;
+}
+
+/* Vertically oriented toolbars need floats cleared */
+.jxBarLeft label.toolbarLabel,
+.jxBarLeft ul.jxToolbar,
+.jxBarLeft li.jxToolItem,
+.jxBarRight label.toolbarLabel,
+.jxBarRight ul.jxToolbar,
+.jxBarRight li.jxToolItem
+{
+  clear: both;
+}
+
+
+/* DEPRICATED STYLES */
+
+/* Vertically oriented toolbars do not need to fill their containers horizontally */
+.verticalToolbar {
+  width: auto;
+}
+
+/* Vertically oriented toolbars need floats cleared */
+.verticalToolbar label.toolbarLabel,
+.verticalToolbar ul.jxToolbar,
+.verticalToolbar li.jxToolItem
+{
+  clear: both;
+}
+
+/**
+ * @project         Jx
+ * @revision        $Id: tree.css 324 2007-06-20 19:04:54Z pspencer $
+ * @author          Fred Warnock (fwarnock at dmsolutions.ca)
+ * @copyright       &copy; 2006 DM Solutions Group Inc.
+ */
+
+/* =========== */
+/* TREE STYLES */
+/* =========== */
+
+/* The jx tree built out of nested ULs
+   For this to work visually, the margins and padding need to be flattened
+   out, and the list marker needs to be hidden
+*/
+
+
+.jxTree, .jxTreeRoot {
+  /* relative positioning is required for IE to fix the peek-a-boo bug */
+  position:relative;
+  list-style: none;
+  margin: 0px;
+  padding: 0px;
+}
+
+.jxTreeNest {
+  list-style: none;
+  margin: 0px;
+  padding: 0px;
+  background-repeat: repeat-y;
+  background-position: left top;
+}
+
+/* Node Classes */
+
+.jxTree li, .jxTreeRoot li {
+  /* relative positioning is required for IE to fix the peek-a-boo bug */
+  position:relative;
+  margin: 0px;
+  padding: 0px;
+  background-repeat: no-repeat;
+  /* background branches may need to shift up/down according to height of the node */
+  background-position: left top;
+  white-space: nowrap;
+  width: 100%;
+}
+
+.jxTree li {
+  margin-left: 16px;
+}
+
+.jxTree li.jxDisabled, .jxTreeRoot li.jxDisabled {   
+  opacity: 0.4; /* css 3 */
+  -moz-opacity: 0.4; /* moz-specific */
+  filter: Alpha(opacity=40); /* IE only */
+}
+
+.jxTree a, .jxTreeRoot a {
+  margin: 0px;
+  padding: 0px;
+  padding-left: 2px;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 11px;
+  color: #000;
+  text-decoration: none;
+  /* Line Height needs to be an even number so branches line up properly */
+  line-height: 20px;
+}
+
+.jxTree a:hover, .jxTreeRoot a:hover {
+  background-color: #E1EDFA; 
+  /*background-color: #ffffcc; */
+}
+
+.jxTree img, .jxTreeRoot img {
+  border: 0px;
+  width: 16px;
+  height: 16px;
+}
+
+.jxTreeNest         {background-image: url(../images/tree_vert_line.png);}
+.jxTreeNode         {background-image: url(../images/tree_node.png);}
+.jxTreeNodeLast     {background-image: url(../images/tree_last_node.png);}
+
+.jxTreeDropzone {
+  text-decoration:underline;
+  font-weight:bold;
+}
+
+.jxTreeSelectedNode {
+  background-color: #AFD4FA;
+  /*background-color: #ddffaa; */
+  font-weight:bold;
+}
+
+.jxTreeCutNode {
+  opacity: 0.4; /* css 3 */
+  -moz-opacity: 0.4; /* moz-specific */
+  filter: Alpha(opacity=40); /* IE only */
+}
+
+.jxTreeCutNode a:hover {
+  background-color: #fff; 
+}
+
+.jxTreeNode, .jxTreeNodeLast {
+/*    width: 100%;*/
+}
+
+.jxTreeNode a, .jxTreeNode img, .jxTreeNode input {
+    vertical-align: middle;
+}
+
+.jxTreeNodeLast a, .jxTreeNodeLast img, .jxTreeNodeLast input {
+    vertical-align: middle;
+}
+
+.jxTreeNodeImage {
+}
+
+.jxTreeNodeIcon {
+    margin: 0px;
+}
\ No newline at end of file

Deleted: sandbox/aboudreault/jx/lib/jx_combined.js
===================================================================
--- trunk/jx/lib/jx_combined.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/lib/jx_combined.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,14057 +0,0 @@
-/******************************************************************************
- *  Prototype JavaScript framework, version 1.5.0
- *  (c) 2005-2007 Sam Stephenson
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- ******************************************************************************
- * Jx UI Library, version 1.0
- * Copyright &copy; 2008, DM Solutions Group Inc.
- * Jx is freely distributable under the terms of an MIT-style license.
- *****************************************************************************/
-/*  Prototype JavaScript framework, version 1.5.0
- *  (c) 2005-2007 Sam Stephenson
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- *
-/*--------------------------------------------------------------------------*/
-
-var Prototype = {
-  Version: '1.5.0',
-  BrowserFeatures: {
-    XPath: !!document.evaluate
-  },
-
-  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
-  emptyFunction: function() {},
-  K: function(x) { return x }
-}
-
-var Class = {
-  create: function() {
-    return function() {
-      this.initialize.apply(this, arguments);
-    }
-  }
-}
-
-var Abstract = new Object();
-
-Object.extend = function(destination, source) {
-  for (var property in source) {
-    destination[property] = source[property];
-  }
-  return destination;
-}
-
-Object.extend(Object, {
-  inspect: function(object) {
-    try {
-      if (object === undefined) return 'undefined';
-      if (object === null) return 'null';
-      return object.inspect ? object.inspect() : object.toString();
-    } catch (e) {
-      if (e instanceof RangeError) return '...';
-      throw e;
-    }
-  },
-
-  keys: function(object) {
-    var keys = [];
-    for (var property in object)
-      keys.push(property);
-    return keys;
-  },
-
-  values: function(object) {
-    var values = [];
-    for (var property in object)
-      values.push(object[property]);
-    return values;
-  },
-
-  clone: function(object) {
-    return Object.extend({}, object);
-  }
-});
-
-Function.prototype.bind = function() {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function() {
-    return __method.apply(object, args.concat($A(arguments)));
-  }
-}
-
-Function.prototype.bindAsEventListener = function(object) {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function(event) {
-    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
-  }
-}
-
-Object.extend(Number.prototype, {
-  toColorPart: function() {
-    var digits = this.toString(16);
-    if (this < 16) return '0' + digits;
-    return digits;
-  },
-
-  succ: function() {
-    return this + 1;
-  },
-
-  times: function(iterator) {
-    $R(0, this, true).each(iterator);
-    return this;
-  }
-});
-
-var Try = {
-  these: function() {
-    var returnValue;
-
-    for (var i = 0, length = arguments.length; i < length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create();
-PeriodicalExecuter.prototype = {
-  initialize: function(callback, frequency) {
-    this.callback = callback;
-    this.frequency = frequency;
-    this.currentlyExecuting = false;
-
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  stop: function() {
-    if (!this.timer) return;
-    clearInterval(this.timer);
-    this.timer = null;
-  },
-
-  onTimerEvent: function() {
-    if (!this.currentlyExecuting) {
-      try {
-        this.currentlyExecuting = true;
-        this.callback(this);
-      } finally {
-        this.currentlyExecuting = false;
-      }
-    }
-  }
-}
-String.interpret = function(value){
-  return value == null ? '' : String(value);
-}
-
-Object.extend(String.prototype, {
-  gsub: function(pattern, replacement) {
-    var result = '', source = this, match;
-    replacement = arguments.callee.prepareReplacement(replacement);
-
-    while (source.length > 0) {
-      if (match = source.match(pattern)) {
-        result += source.slice(0, match.index);
-        result += String.interpret(replacement(match));
-        source  = source.slice(match.index + match[0].length);
-      } else {
-        result += source, source = '';
-      }
-    }
-    return result;
-  },
-
-  sub: function(pattern, replacement, count) {
-    replacement = this.gsub.prepareReplacement(replacement);
-    count = count === undefined ? 1 : count;
-
-    return this.gsub(pattern, function(match) {
-      if (--count < 0) return match[0];
-      return replacement(match);
-    });
-  },
-
-  scan: function(pattern, iterator) {
-    this.gsub(pattern, iterator);
-    return this;
-  },
-
-  truncate: function(length, truncation) {
-    length = length || 30;
-    truncation = truncation === undefined ? '...' : truncation;
-    return this.length > length ?
-      this.slice(0, length - truncation.length) + truncation : this;
-  },
-
-  strip: function() {
-    return this.replace(/^\s+/, '').replace(/\s+$/, '');
-  },
-
-  stripTags: function() {
-    return this.replace(/<\/?[^>]+>/gi, '');
-  },
-
-  stripScripts: function() {
-    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-  },
-
-  extractScripts: function() {
-    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
-    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
-    return (this.match(matchAll) || []).map(function(scriptTag) {
-      return (scriptTag.match(matchOne) || ['', ''])[1];
-    });
-  },
-
-  evalScripts: function() {
-    return this.extractScripts().map(function(script) { return eval(script) });
-  },
-
-  escapeHTML: function() {
-    var div = document.createElement('div');
-    var text = document.createTextNode(this);
-    div.appendChild(text);
-    return div.innerHTML;
-  },
-
-  unescapeHTML: function() {
-    var div = document.createElement('div');
-    div.innerHTML = this.stripTags();
-    return div.childNodes[0] ? (div.childNodes.length > 1 ?
-      $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
-      div.childNodes[0].nodeValue) : '';
-  },
-
-  toQueryParams: function(separator) {
-    var match = this.strip().match(/([^?#]*)(#.*)?$/);
-    if (!match) return {};
-
-    return match[1].split(separator || '&').inject({}, function(hash, pair) {
-      if ((pair = pair.split('='))[0]) {
-        var name = decodeURIComponent(pair[0]);
-        var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
-
-        if (hash[name] !== undefined) {
-          if (hash[name].constructor != Array)
-            hash[name] = [hash[name]];
-          if (value) hash[name].push(value);
-        }
-        else hash[name] = value;
-      }
-      return hash;
-    });
-  },
-
-  toArray: function() {
-    return this.split('');
-  },
-
-  succ: function() {
-    return this.slice(0, this.length - 1) +
-      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
-  },
-
-  camelize: function() {
-    var parts = this.split('-'), len = parts.length;
-    if (len == 1) return parts[0];
-
-    var camelized = this.charAt(0) == '-'
-      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
-      : parts[0];
-
-    for (var i = 1; i < len; i++)
-      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
-
-    return camelized;
-  },
-
-  capitalize: function(){
-    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
-  },
-
-  underscore: function() {
-    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
-  },
-
-  dasherize: function() {
-    return this.gsub(/_/,'-');
-  },
-
-  inspect: function(useDoubleQuotes) {
-    var escapedString = this.replace(/\\/g, '\\\\');
-    if (useDoubleQuotes)
-      return '"' + escapedString.replace(/"/g, '\\"') + '"';
-    else
-      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
-  }
-});
-
-String.prototype.gsub.prepareReplacement = function(replacement) {
-  if (typeof replacement == 'function') return replacement;
-  var template = new Template(replacement);
-  return function(match) { return template.evaluate(match) };
-}
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-var Template = Class.create();
-Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
-Template.prototype = {
-  initialize: function(template, pattern) {
-    this.template = template.toString();
-    this.pattern  = pattern || Template.Pattern;
-  },
-
-  evaluate: function(object) {
-    return this.template.gsub(this.pattern, function(match) {
-      var before = match[1];
-      if (before == '\\') return match[2];
-      return before + String.interpret(object[match[3]]);
-    });
-  }
-}
-
-var $break    = new Object();
-var $continue = new Object();
-
-var Enumerable = {
-  each: function(iterator) {
-    var index = 0;
-    try {
-      this._each(function(value) {
-        try {
-          iterator(value, index++);
-        } catch (e) {
-          if (e != $continue) throw e;
-        }
-      });
-    } catch (e) {
-      if (e != $break) throw e;
-    }
-    return this;
-  },
-
-  eachSlice: function(number, iterator) {
-    var index = -number, slices = [], array = this.toArray();
-    while ((index += number) < array.length)
-      slices.push(array.slice(index, index+number));
-    return slices.map(iterator);
-  },
-
-  all: function(iterator) {
-    var result = true;
-    this.each(function(value, index) {
-      result = result && !!(iterator || Prototype.K)(value, index);
-      if (!result) throw $break;
-    });
-    return result;
-  },
-
-  any: function(iterator) {
-    var result = false;
-    this.each(function(value, index) {
-      if (result = !!(iterator || Prototype.K)(value, index))
-        throw $break;
-    });
-    return result;
-  },
-
-  collect: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push((iterator || Prototype.K)(value, index));
-    });
-    return results;
-  },
-
-  detect: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      if (iterator(value, index)) {
-        result = value;
-        throw $break;
-      }
-    });
-    return result;
-  },
-
-  findAll: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  grep: function(pattern, iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      var stringValue = value.toString();
-      if (stringValue.match(pattern))
-        results.push((iterator || Prototype.K)(value, index));
-    })
-    return results;
-  },
-
-  include: function(object) {
-    var found = false;
-    this.each(function(value) {
-      if (value == object) {
-        found = true;
-        throw $break;
-      }
-    });
-    return found;
-  },
-
-  inGroupsOf: function(number, fillWith) {
-    fillWith = fillWith === undefined ? null : fillWith;
-    return this.eachSlice(number, function(slice) {
-      while(slice.length < number) slice.push(fillWith);
-      return slice;
-    });
-  },
-
-  inject: function(memo, iterator) {
-    this.each(function(value, index) {
-      memo = iterator(memo, value, index);
-    });
-    return memo;
-  },
-
-  invoke: function(method) {
-    var args = $A(arguments).slice(1);
-    return this.map(function(value) {
-      return value[method].apply(value, args);
-    });
-  },
-
-  max: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (result == undefined || value >= result)
-        result = value;
-    });
-    return result;
-  },
-
-  min: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (result == undefined || value < result)
-        result = value;
-    });
-    return result;
-  },
-
-  partition: function(iterator) {
-    var trues = [], falses = [];
-    this.each(function(value, index) {
-      ((iterator || Prototype.K)(value, index) ?
-        trues : falses).push(value);
-    });
-    return [trues, falses];
-  },
-
-  pluck: function(property) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push(value[property]);
-    });
-    return results;
-  },
-
-  reject: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (!iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  sortBy: function(iterator) {
-    return this.map(function(value, index) {
-      return {value: value, criteria: iterator(value, index)};
-    }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
-    }).pluck('value');
-  },
-
-  toArray: function() {
-    return this.map();
-  },
-
-  zip: function() {
-    var iterator = Prototype.K, args = $A(arguments);
-    if (typeof args.last() == 'function')
-      iterator = args.pop();
-
-    var collections = [this].concat(args).map($A);
-    return this.map(function(value, index) {
-      return iterator(collections.pluck(index));
-    });
-  },
-
-  size: function() {
-    return this.toArray().length;
-  },
-
-  inspect: function() {
-    return '#<Enumerable:' + this.toArray().inspect() + '>';
-  }
-}
-
-Object.extend(Enumerable, {
-  map:     Enumerable.collect,
-  find:    Enumerable.detect,
-  select:  Enumerable.findAll,
-  member:  Enumerable.include,
-  entries: Enumerable.toArray
-});
-var $A = Array.from = function(iterable) {
-  if (!iterable) return [];
-  if (iterable.toArray) {
-    return iterable.toArray();
-  } else {
-    var results = [];
-    for (var i = 0, length = iterable.length; i < length; i++)
-      results.push(iterable[i]);
-    return results;
-  }
-}
-
-Object.extend(Array.prototype, Enumerable);
-
-if (!Array.prototype._reverse)
-  Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
-  _each: function(iterator) {
-    for (var i = 0, length = this.length; i < length; i++)
-      iterator(this[i]);
-  },
-
-  clear: function() {
-    this.length = 0;
-    return this;
-  },
-
-  first: function() {
-    return this[0];
-  },
-
-  last: function() {
-    return this[this.length - 1];
-  },
-
-  compact: function() {
-    return this.select(function(value) {
-      return value != null;
-    });
-  },
-
-  flatten: function() {
-    return this.inject([], function(array, value) {
-      return array.concat(value && value.constructor == Array ?
-        value.flatten() : [value]);
-    });
-  },
-
-  without: function() {
-    var values = $A(arguments);
-    return this.select(function(value) {
-      return !values.include(value);
-    });
-  },
-
-  indexOf: function(object) {
-    for (var i = 0, length = this.length; i < length; i++)
-      if (this[i] == object) return i;
-    return -1;
-  },
-
-  reverse: function(inline) {
-    return (inline !== false ? this : this.toArray())._reverse();
-  },
-
-  reduce: function() {
-    return this.length > 1 ? this : this[0];
-  },
-
-  uniq: function() {
-    return this.inject([], function(array, value) {
-      return array.include(value) ? array : array.concat([value]);
-    });
-  },
-
-  clone: function() {
-    return [].concat(this);
-  },
-
-  size: function() {
-    return this.length;
-  },
-
-  inspect: function() {
-    return '[' + this.map(Object.inspect).join(', ') + ']';
-  }
-});
-
-Array.prototype.toArray = Array.prototype.clone;
-
-function $w(string){
-  string = string.strip();
-  return string ? string.split(/\s+/) : [];
-}
-
-if(window.opera){
-  Array.prototype.concat = function(){
-    var array = [];
-    for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
-    for(var i = 0, length = arguments.length; i < length; i++) {
-      if(arguments[i].constructor == Array) {
-        for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
-          array.push(arguments[i][j]);
-      } else {
-        array.push(arguments[i]);
-      }
-    }
-    return array;
-  }
-}
-var Hash = function(obj) {
-  Object.extend(this, obj || {});
-};
-
-Object.extend(Hash, {
-  toQueryString: function(obj) {
-    var parts = [];
-
-	  this.prototype._each.call(obj, function(pair) {
-      if (!pair.key) return;
-
-      if (pair.value && pair.value.constructor == Array) {
-        var values = pair.value.compact();
-        if (values.length < 2) pair.value = values.reduce();
-        else {
-        	key = encodeURIComponent(pair.key);
-          values.each(function(value) {
-            value = value != undefined ? encodeURIComponent(value) : '';
-            parts.push(key + '=' + encodeURIComponent(value));
-          });
-          return;
-        }
-      }
-      if (pair.value == undefined) pair[1] = '';
-      parts.push(pair.map(encodeURIComponent).join('='));
-	  });
-
-    return parts.join('&');
-  }
-});
-
-Object.extend(Hash.prototype, Enumerable);
-Object.extend(Hash.prototype, {
-  _each: function(iterator) {
-    for (var key in this) {
-      var value = this[key];
-      if (value && value == Hash.prototype[key]) continue;
-
-      var pair = [key, value];
-      pair.key = key;
-      pair.value = value;
-      iterator(pair);
-    }
-  },
-
-  keys: function() {
-    return this.pluck('key');
-  },
-
-  values: function() {
-    return this.pluck('value');
-  },
-
-  merge: function(hash) {
-    return $H(hash).inject(this, function(mergedHash, pair) {
-      mergedHash[pair.key] = pair.value;
-      return mergedHash;
-    });
-  },
-
-  remove: function() {
-    var result;
-    for(var i = 0, length = arguments.length; i < length; i++) {
-      var value = this[arguments[i]];
-      if (value !== undefined){
-        if (result === undefined) result = value;
-        else {
-          if (result.constructor != Array) result = [result];
-          result.push(value)
-        }
-      }
-      delete this[arguments[i]];
-    }
-    return result;
-  },
-
-  toQueryString: function() {
-    return Hash.toQueryString(this);
-  },
-
-  inspect: function() {
-    return '#<Hash:{' + this.map(function(pair) {
-      return pair.map(Object.inspect).join(': ');
-    }).join(', ') + '}>';
-  }
-});
-
-function $H(object) {
-  if (object && object.constructor == Hash) return object;
-  return new Hash(object);
-};
-ObjectRange = Class.create();
-Object.extend(ObjectRange.prototype, Enumerable);
-Object.extend(ObjectRange.prototype, {
-  initialize: function(start, end, exclusive) {
-    this.start = start;
-    this.end = end;
-    this.exclusive = exclusive;
-  },
-
-  _each: function(iterator) {
-    var value = this.start;
-    while (this.include(value)) {
-      iterator(value);
-      value = value.succ();
-    }
-  },
-
-  include: function(value) {
-    if (value < this.start)
-      return false;
-    if (this.exclusive)
-      return value < this.end;
-    return value <= this.end;
-  }
-});
-
-var $R = function(start, end, exclusive) {
-  return new ObjectRange(start, end, exclusive);
-}
-
-var Ajax = {
-  getTransport: function() {
-    return Try.these(
-      function() {return new XMLHttpRequest()},
-      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
-      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
-    ) || false;
-  },
-
-  activeRequestCount: 0
-}
-
-Ajax.Responders = {
-  responders: [],
-
-  _each: function(iterator) {
-    this.responders._each(iterator);
-  },
-
-  register: function(responder) {
-    if (!this.include(responder))
-      this.responders.push(responder);
-  },
-
-  unregister: function(responder) {
-    this.responders = this.responders.without(responder);
-  },
-
-  dispatch: function(callback, request, transport, json) {
-    this.each(function(responder) {
-      if (typeof responder[callback] == 'function') {
-        try {
-          responder[callback].apply(responder, [request, transport, json]);
-        } catch (e) {}
-      }
-    });
-  }
-};
-
-Object.extend(Ajax.Responders, Enumerable);
-
-Ajax.Responders.register({
-  onCreate: function() {
-    Ajax.activeRequestCount++;
-  },
-  onComplete: function() {
-    Ajax.activeRequestCount--;
-  }
-});
-
-Ajax.Base = function() {};
-Ajax.Base.prototype = {
-  setOptions: function(options) {
-    this.options = {
-      method:       'post',
-      asynchronous: true,
-      contentType:  'application/x-www-form-urlencoded',
-      encoding:     'UTF-8',
-      parameters:   ''
-    }
-    Object.extend(this.options, options || {});
-
-    this.options.method = this.options.method.toLowerCase();
-    if (typeof this.options.parameters == 'string')
-      this.options.parameters = this.options.parameters.toQueryParams();
-  }
-}
-
-Ajax.Request = Class.create();
-Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
-  _complete: false,
-
-  initialize: function(url, options) {
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-    this.request(url);
-  },
-
-  request: function(url) {
-    this.url = url;
-    this.method = this.options.method;
-    var params = this.options.parameters;
-
-    if (!['get', 'post'].include(this.method)) {
-      // simulate other verbs over post
-      params['_method'] = this.method;
-      this.method = 'post';
-    }
-
-    params = Hash.toQueryString(params);
-    if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
-
-    // when GET, append parameters to URL
-    if (this.method == 'get' && params)
-      this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
-
-    try {
-      Ajax.Responders.dispatch('onCreate', this, this.transport);
-
-      this.transport.open(this.method.toUpperCase(), this.url,
-        this.options.asynchronous);
-
-      if (this.options.asynchronous)
-        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
-
-      this.transport.onreadystatechange = this.onStateChange.bind(this);
-      this.setRequestHeaders();
-
-      var body = this.method == 'post' ? (this.options.postBody || params) : null;
-
-      this.transport.send(body);
-
-      /* Force Firefox to handle ready state 4 for synchronous requests */
-      if (!this.options.asynchronous && this.transport.overrideMimeType)
-        this.onStateChange();
-
-    }
-    catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  onStateChange: function() {
-    var readyState = this.transport.readyState;
-    if (readyState > 1 && !((readyState == 4) && this._complete))
-      this.respondToReadyState(this.transport.readyState);
-  },
-
-  setRequestHeaders: function() {
-    var headers = {
-      'X-Requested-With': 'XMLHttpRequest',
-      'X-Prototype-Version': Prototype.Version,
-      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
-    };
-
-    if (this.method == 'post') {
-      headers['Content-type'] = this.options.contentType +
-        (this.options.encoding ? '; charset=' + this.options.encoding : '');
-
-      /* Force "Connection: close" for older Mozilla browsers to work
-       * around a bug where XMLHttpRequest sends an incorrect
-       * Content-length header. See Mozilla Bugzilla #246651.
-       */
-      if (this.transport.overrideMimeType &&
-          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
-            headers['Connection'] = 'close';
-    }
-
-    // user-defined headers
-    if (typeof this.options.requestHeaders == 'object') {
-      var extras = this.options.requestHeaders;
-
-      if (typeof extras.push == 'function')
-        for (var i = 0, length = extras.length; i < length; i += 2)
-          headers[extras[i]] = extras[i+1];
-      else
-        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
-    }
-
-    for (var name in headers)
-      this.transport.setRequestHeader(name, headers[name]);
-  },
-
-  success: function() {
-    return !this.transport.status
-        || (this.transport.status >= 200 && this.transport.status < 300);
-  },
-
-  respondToReadyState: function(readyState) {
-    var state = Ajax.Request.Events[readyState];
-    var transport = this.transport, json = this.evalJSON();
-
-    if (state == 'Complete') {
-      try {
-        this._complete = true;
-        (this.options['on' + this.transport.status]
-         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
-         || Prototype.emptyFunction)(transport, json);
-      } catch (e) {
-        this.dispatchException(e);
-      }
-
-      if ((this.getHeader('Content-type') || 'text/javascript').strip().
-        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
-          this.evalResponse();
-    }
-
-    try {
-      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
-      Ajax.Responders.dispatch('on' + state, this, transport, json);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-
-    if (state == 'Complete') {
-      // avoid memory leak in MSIE: clean up
-      this.transport.onreadystatechange = Prototype.emptyFunction;
-    }
-  },
-
-  getHeader: function(name) {
-    try {
-      return this.transport.getResponseHeader(name);
-    } catch (e) { return null }
-  },
-
-  evalJSON: function() {
-    try {
-      var json = this.getHeader('X-JSON');
-      return json ? eval('(' + json + ')') : null;
-    } catch (e) { return null }
-  },
-
-  evalResponse: function() {
-    try {
-      return eval(this.transport.responseText);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  dispatchException: function(exception) {
-    (this.options.onException || Prototype.emptyFunction)(this, exception);
-    Ajax.Responders.dispatch('onException', this, exception);
-  }
-});
-
-Ajax.Updater = Class.create();
-
-Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
-  initialize: function(container, url, options) {
-    this.container = {
-      success: (container.success || container),
-      failure: (container.failure || (container.success ? null : container))
-    }
-
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-
-    var onComplete = this.options.onComplete || Prototype.emptyFunction;
-    this.options.onComplete = (function(transport, param) {
-      this.updateContent();
-      onComplete(transport, param);
-    }).bind(this);
-
-    this.request(url);
-  },
-
-  updateContent: function() {
-    var receiver = this.container[this.success() ? 'success' : 'failure'];
-    var response = this.transport.responseText;
-
-    if (!this.options.evalScripts) response = response.stripScripts();
-
-    if (receiver = $(receiver)) {
-      if (this.options.insertion)
-        new this.options.insertion(receiver, response);
-      else
-        receiver.update(response);
-    }
-
-    if (this.success()) {
-      if (this.onComplete)
-        setTimeout(this.onComplete.bind(this), 10);
-    }
-  }
-});
-
-Ajax.PeriodicalUpdater = Class.create();
-Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(container, url, options) {
-    this.setOptions(options);
-    this.onComplete = this.options.onComplete;
-
-    this.frequency = (this.options.frequency || 2);
-    this.decay = (this.options.decay || 1);
-
-    this.updater = {};
-    this.container = container;
-    this.url = url;
-
-    this.start();
-  },
-
-  start: function() {
-    this.options.onComplete = this.updateComplete.bind(this);
-    this.onTimerEvent();
-  },
-
-  stop: function() {
-    this.updater.options.onComplete = undefined;
-    clearTimeout(this.timer);
-    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
-  },
-
-  updateComplete: function(request) {
-    if (this.options.decay) {
-      this.decay = (request.responseText == this.lastText ?
-        this.decay * this.options.decay : 1);
-
-      this.lastText = request.responseText;
-    }
-    this.timer = setTimeout(this.onTimerEvent.bind(this),
-      this.decay * this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    this.updater = new Ajax.Updater(this.container, this.url, this.options);
-  }
-});
-function $(element) {
-  if (arguments.length > 1) {
-    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
-      elements.push($(arguments[i]));
-    return elements;
-  }
-  if (typeof element == 'string')
-    element = document.getElementById(element);
-  return Element.extend(element);
-}
-
-if (Prototype.BrowserFeatures.XPath) {
-  document._getElementsByXPath = function(expression, parentElement) {
-    var results = [];
-    var query = document.evaluate(expression, $(parentElement) || document,
-      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
-    for (var i = 0, length = query.snapshotLength; i < length; i++)
-      results.push(query.snapshotItem(i));
-    return results;
-  };
-}
-
-document.getElementsByClassName = function(className, parentElement) {
-  if (Prototype.BrowserFeatures.XPath) {
-    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
-    return document._getElementsByXPath(q, parentElement);
-  } else {
-    var children = ($(parentElement) || document.body).getElementsByTagName('*');
-    var elements = [], child;
-    for (var i = 0, length = children.length; i < length; i++) {
-      child = children[i];
-      if (Element.hasClassName(child, className))
-        elements.push(Element.extend(child));
-    }
-    return elements;
-  }
-};
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Element)
-  var Element = new Object();
-
-Element.extend = function(element) {
-  if (!element || _nativeExtensions || element.nodeType == 3) return element;
-
-  if (!element._extended && element.tagName && element != window) {
-    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
-
-    if (element.tagName == 'FORM')
-      Object.extend(methods, Form.Methods);
-    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
-      Object.extend(methods, Form.Element.Methods);
-
-    Object.extend(methods, Element.Methods.Simulated);
-
-    for (var property in methods) {
-      var value = methods[property];
-      if (typeof value == 'function' && !(property in element))
-        element[property] = cache.findOrStore(value);
-    }
-  }
-
-  element._extended = true;
-  return element;
-};
-
-Element.extend.cache = {
-  findOrStore: function(value) {
-    return this[value] = this[value] || function() {
-      return value.apply(null, [this].concat($A(arguments)));
-    }
-  }
-};
-
-Element.Methods = {
-  visible: function(element) {
-    return $(element).style.display != 'none';
-  },
-
-  toggle: function(element) {
-    element = $(element);
-    Element[Element.visible(element) ? 'hide' : 'show'](element);
-    return element;
-  },
-
-  hide: function(element) {
-    $(element).style.display = 'none';
-    return element;
-  },
-
-  show: function(element) {
-    $(element).style.display = '';
-    return element;
-  },
-
-  remove: function(element) {
-    element = $(element);
-    element.parentNode.removeChild(element);
-    return element;
-  },
-
-  update: function(element, html) {
-    html = typeof html == 'undefined' ? '' : html.toString();
-    $(element).innerHTML = html.stripScripts();
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  },
-
-  replace: function(element, html) {
-    element = $(element);
-    html = typeof html == 'undefined' ? '' : html.toString();
-    if (element.outerHTML) {
-      element.outerHTML = html.stripScripts();
-    } else {
-      var range = element.ownerDocument.createRange();
-      range.selectNodeContents(element);
-      element.parentNode.replaceChild(
-        range.createContextualFragment(html.stripScripts()), element);
-    }
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  },
-
-  inspect: function(element) {
-    element = $(element);
-    var result = '<' + element.tagName.toLowerCase();
-    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
-      var property = pair.first(), attribute = pair.last();
-      var value = (element[property] || '').toString();
-      if (value) result += ' ' + attribute + '=' + value.inspect(true);
-    });
-    return result + '>';
-  },
-
-  recursivelyCollect: function(element, property) {
-    element = $(element);
-    var elements = [];
-    while (element = element[property])
-      if (element.nodeType == 1)
-        elements.push(Element.extend(element));
-    return elements;
-  },
-
-  ancestors: function(element) {
-    return $(element).recursivelyCollect('parentNode');
-  },
-
-  descendants: function(element) {
-    return $A($(element).getElementsByTagName('*'));
-  },
-
-  immediateDescendants: function(element) {
-    if (!(element = $(element).firstChild)) return [];
-    while (element && element.nodeType != 1) element = element.nextSibling;
-    if (element) return [element].concat($(element).nextSiblings());
-    return [];
-  },
-
-  previousSiblings: function(element) {
-    return $(element).recursivelyCollect('previousSibling');
-  },
-
-  nextSiblings: function(element) {
-    return $(element).recursivelyCollect('nextSibling');
-  },
-
-  siblings: function(element) {
-    element = $(element);
-    return element.previousSiblings().reverse().concat(element.nextSiblings());
-  },
-
-  match: function(element, selector) {
-    if (typeof selector == 'string')
-      selector = new Selector(selector);
-    return selector.match($(element));
-  },
-
-  up: function(element, expression, index) {
-    return Selector.findElement($(element).ancestors(), expression, index);
-  },
-
-  down: function(element, expression, index) {
-    return Selector.findElement($(element).descendants(), expression, index);
-  },
-
-  previous: function(element, expression, index) {
-    return Selector.findElement($(element).previousSiblings(), expression, index);
-  },
-
-  next: function(element, expression, index) {
-    return Selector.findElement($(element).nextSiblings(), expression, index);
-  },
-
-  getElementsBySelector: function() {
-    var args = $A(arguments), element = $(args.shift());
-    return Selector.findChildElements(element, args);
-  },
-
-  getElementsByClassName: function(element, className) {
-    return document.getElementsByClassName(className, element);
-  },
-
-  readAttribute: function(element, name) {
-    element = $(element);
-    if (document.all && !window.opera) {
-      var t = Element._attributeTranslations;
-      if (t.values[name]) return t.values[name](element, name);
-      if (t.names[name])  name = t.names[name];
-      var attribute = element.attributes[name];
-      if(attribute) return attribute.nodeValue;
-    }
-    return element.getAttribute(name);
-  },
-
-  getHeight: function(element) {
-    return $(element).getDimensions().height;
-  },
-
-  getWidth: function(element) {
-    return $(element).getDimensions().width;
-  },
-
-  classNames: function(element) {
-    return new Element.ClassNames(element);
-  },
-
-  hasClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    var elementClassName = element.className;
-    if (elementClassName.length == 0) return false;
-    if (elementClassName == className ||
-        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
-      return true;
-    return false;
-  },
-
-  addClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    Element.classNames(element).add(className);
-    return element;
-  },
-
-  removeClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    Element.classNames(element).remove(className);
-    return element;
-  },
-
-  toggleClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
-    return element;
-  },
-
-  observe: function() {
-    Event.observe.apply(Event, arguments);
-    return $A(arguments).first();
-  },
-
-  stopObserving: function() {
-    Event.stopObserving.apply(Event, arguments);
-    return $A(arguments).first();
-  },
-
-  // removes whitespace-only text node children
-  cleanWhitespace: function(element) {
-    element = $(element);
-    var node = element.firstChild;
-    while (node) {
-      var nextNode = node.nextSibling;
-      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
-        element.removeChild(node);
-      node = nextNode;
-    }
-    return element;
-  },
-
-  empty: function(element) {
-    return $(element).innerHTML.match(/^\s*$/);
-  },
-
-  descendantOf: function(element, ancestor) {
-    element = $(element), ancestor = $(ancestor);
-    while (element = element.parentNode)
-      if (element == ancestor) return true;
-    return false;
-  },
-
-  scrollTo: function(element) {
-    element = $(element);
-    var pos = Position.cumulativeOffset(element);
-    window.scrollTo(pos[0], pos[1]);
-    return element;
-  },
-
-  getStyle: function(element, style) {
-    element = $(element);
-    if (['float','cssFloat'].include(style))
-      style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
-    style = style.camelize();
-    var value = element.style[style];
-    if (!value) {
-      if (document.defaultView && document.defaultView.getComputedStyle) {
-        var css = document.defaultView.getComputedStyle(element, null);
-        value = css ? css[style] : null;
-      } else if (element.currentStyle) {
-        value = element.currentStyle[style];
-      }
-    }
-
-    if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
-      value = element['offset'+style.capitalize()] + 'px';
-
-    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
-      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
-    if(style == 'opacity') {
-      if(value) return parseFloat(value);
-      if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
-        if(value[1]) return parseFloat(value[1]) / 100;
-      return 1.0;
-    }
-    return value == 'auto' ? null : value;
-  },
-
-  setStyle: function(element, style) {
-    element = $(element);
-    for (var name in style) {
-      var value = style[name];
-      if(name == 'opacity') {
-        if (value == 1) {
-          value = (/Gecko/.test(navigator.userAgent) &&
-            !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
-          if(/MSIE/.test(navigator.userAgent) && !window.opera)
-            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
-        } else if(value === '') {
-          if(/MSIE/.test(navigator.userAgent) && !window.opera)
-            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
-        } else {
-          if(value < 0.00001) value = 0;
-          if(/MSIE/.test(navigator.userAgent) && !window.opera)
-            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
-              'alpha(opacity='+value*100+')';
-        }
-      } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
-      element.style[name.camelize()] = value;
-    }
-    return element;
-  },
-
-  getDimensions: function(element) {
-    element = $(element);
-    var display = $(element).getStyle('display');
-    if (display != 'none' && display != null) // Safari bug
-      return {width: element.offsetWidth, height: element.offsetHeight};
-
-    // All *Width and *Height properties give 0 on elements with display none,
-    // so enable the element temporarily
-    var els = element.style;
-    var originalVisibility = els.visibility;
-    var originalPosition = els.position;
-    var originalDisplay = els.display;
-    els.visibility = 'hidden';
-    els.position = 'absolute';
-    els.display = 'block';
-    var originalWidth = element.clientWidth;
-    var originalHeight = element.clientHeight;
-    els.display = originalDisplay;
-    els.position = originalPosition;
-    els.visibility = originalVisibility;
-    return {width: originalWidth, height: originalHeight};
-  },
-
-  makePositioned: function(element) {
-    element = $(element);
-    var pos = Element.getStyle(element, 'position');
-    if (pos == 'static' || !pos) {
-      element._madePositioned = true;
-      element.style.position = 'relative';
-      // Opera returns the offset relative to the positioning context, when an
-      // element is position relative but top and left have not been defined
-      if (window.opera) {
-        element.style.top = 0;
-        element.style.left = 0;
-      }
-    }
-    return element;
-  },
-
-  undoPositioned: function(element) {
-    element = $(element);
-    if (element._madePositioned) {
-      element._madePositioned = undefined;
-      element.style.position =
-        element.style.top =
-        element.style.left =
-        element.style.bottom =
-        element.style.right = '';
-    }
-    return element;
-  },
-
-  makeClipping: function(element) {
-    element = $(element);
-    if (element._overflow) return element;
-    element._overflow = element.style.overflow || 'auto';
-    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
-      element.style.overflow = 'hidden';
-    return element;
-  },
-
-  undoClipping: function(element) {
-    element = $(element);
-    if (!element._overflow) return element;
-    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
-    element._overflow = null;
-    return element;
-  }
-};
-
-Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
-
-Element._attributeTranslations = {};
-
-Element._attributeTranslations.names = {
-  colspan:   "colSpan",
-  rowspan:   "rowSpan",
-  valign:    "vAlign",
-  datetime:  "dateTime",
-  accesskey: "accessKey",
-  tabindex:  "tabIndex",
-  enctype:   "encType",
-  maxlength: "maxLength",
-  readonly:  "readOnly",
-  longdesc:  "longDesc"
-};
-
-Element._attributeTranslations.values = {
-  _getAttr: function(element, attribute) {
-    return element.getAttribute(attribute, 2);
-  },
-
-  _flag: function(element, attribute) {
-    return $(element).hasAttribute(attribute) ? attribute : null;
-  },
-
-  style: function(element) {
-    return element.style.cssText.toLowerCase();
-  },
-
-  title: function(element) {
-    var node = element.getAttributeNode('title');
-    return node.specified ? node.nodeValue : null;
-  }
-};
-
-Object.extend(Element._attributeTranslations.values, {
-  href: Element._attributeTranslations.values._getAttr,
-  src:  Element._attributeTranslations.values._getAttr,
-  disabled: Element._attributeTranslations.values._flag,
-  checked:  Element._attributeTranslations.values._flag,
-  readonly: Element._attributeTranslations.values._flag,
-  multiple: Element._attributeTranslations.values._flag
-});
-
-Element.Methods.Simulated = {
-  hasAttribute: function(element, attribute) {
-    var t = Element._attributeTranslations;
-    attribute = t.names[attribute] || attribute;
-    return $(element).getAttributeNode(attribute).specified;
-  }
-};
-
-// IE is missing .innerHTML support for TABLE-related elements
-if (document.all && !window.opera){
-  Element.Methods.update = function(element, html) {
-    element = $(element);
-    html = typeof html == 'undefined' ? '' : html.toString();
-    var tagName = element.tagName.toUpperCase();
-    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
-      var div = document.createElement('div');
-      switch (tagName) {
-        case 'THEAD':
-        case 'TBODY':
-          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
-          depth = 2;
-          break;
-        case 'TR':
-          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
-          depth = 3;
-          break;
-        case 'TD':
-          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
-          depth = 4;
-      }
-      $A(element.childNodes).each(function(node){
-        element.removeChild(node)
-      });
-      depth.times(function(){ div = div.firstChild });
-
-      $A(div.childNodes).each(
-        function(node){ element.appendChild(node) });
-    } else {
-      element.innerHTML = html.stripScripts();
-    }
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  }
-};
-
-Object.extend(Element, Element.Methods);
-
-var _nativeExtensions = false;
-
-if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
-  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
-    var className = 'HTML' + tag + 'Element';
-    if(window[className]) return;
-    var klass = window[className] = {};
-    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
-  });
-
-Element.addMethods = function(methods) {
-  Object.extend(Element.Methods, methods || {});
-
-  function copy(methods, destination, onlyIfAbsent) {
-    onlyIfAbsent = onlyIfAbsent || false;
-    var cache = Element.extend.cache;
-    for (var property in methods) {
-      var value = methods[property];
-      if (!onlyIfAbsent || !(property in destination))
-        destination[property] = cache.findOrStore(value);
-    }
-  }
-
-  if (typeof HTMLElement != 'undefined') {
-    copy(Element.Methods, HTMLElement.prototype);
-    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
-    copy(Form.Methods, HTMLFormElement.prototype);
-    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
-      copy(Form.Element.Methods, klass.prototype);
-    });
-    _nativeExtensions = true;
-  }
-}
-
-var Toggle = new Object();
-Toggle.display = Element.toggle;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.Insertion = function(adjacency) {
-  this.adjacency = adjacency;
-}
-
-Abstract.Insertion.prototype = {
-  initialize: function(element, content) {
-    this.element = $(element);
-    this.content = content.stripScripts();
-
-    if (this.adjacency && this.element.insertAdjacentHTML) {
-      try {
-        this.element.insertAdjacentHTML(this.adjacency, this.content);
-      } catch (e) {
-        var tagName = this.element.tagName.toUpperCase();
-        if (['TBODY', 'TR'].include(tagName)) {
-          this.insertContent(this.contentFromAnonymousTable());
-        } else {
-          throw e;
-        }
-      }
-    } else {
-      this.range = this.element.ownerDocument.createRange();
-      if (this.initializeRange) this.initializeRange();
-      this.insertContent([this.range.createContextualFragment(this.content)]);
-    }
-
-    setTimeout(function() {content.evalScripts()}, 10);
-  },
-
-  contentFromAnonymousTable: function() {
-    var div = document.createElement('div');
-    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
-    return $A(div.childNodes[0].childNodes[0].childNodes);
-  }
-}
-
-var Insertion = new Object();
-
-Insertion.Before = Class.create();
-Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
-  initializeRange: function() {
-    this.range.setStartBefore(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment, this.element);
-    }).bind(this));
-  }
-});
-
-Insertion.Top = Class.create();
-Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(true);
-  },
-
-  insertContent: function(fragments) {
-    fragments.reverse(false).each((function(fragment) {
-      this.element.insertBefore(fragment, this.element.firstChild);
-    }).bind(this));
-  }
-});
-
-Insertion.Bottom = Class.create();
-Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.appendChild(fragment);
-    }).bind(this));
-  }
-});
-
-Insertion.After = Class.create();
-Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
-  initializeRange: function() {
-    this.range.setStartAfter(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment,
-        this.element.nextSibling);
-    }).bind(this));
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
-  initialize: function(element) {
-    this.element = $(element);
-  },
-
-  _each: function(iterator) {
-    this.element.className.split(/\s+/).select(function(name) {
-      return name.length > 0;
-    })._each(iterator);
-  },
-
-  set: function(className) {
-    this.element.className = className;
-  },
-
-  add: function(classNameToAdd) {
-    if (this.include(classNameToAdd)) return;
-    this.set($A(this).concat(classNameToAdd).join(' '));
-  },
-
-  remove: function(classNameToRemove) {
-    if (!this.include(classNameToRemove)) return;
-    this.set($A(this).without(classNameToRemove).join(' '));
-  },
-
-  toString: function() {
-    return $A(this).join(' ');
-  }
-};
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-var Selector = Class.create();
-Selector.prototype = {
-  initialize: function(expression) {
-    this.params = {classNames: []};
-    this.expression = expression.toString().strip();
-    this.parseExpression();
-    this.compileMatcher();
-  },
-
-  parseExpression: function() {
-    function abort(message) { throw 'Parse error in selector: ' + message; }
-
-    if (this.expression == '')  abort('empty expression');
-
-    var params = this.params, expr = this.expression, match, modifier, clause, rest;
-    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
-      params.attributes = params.attributes || [];
-      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
-      expr = match[1];
-    }
-
-    if (expr == '*') return this.params.wildcard = true;
-
-    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
-      modifier = match[1], clause = match[2], rest = match[3];
-      switch (modifier) {
-        case '#':       params.id = clause; break;
-        case '.':       params.classNames.push(clause); break;
-        case '':
-        case undefined: params.tagName = clause.toUpperCase(); break;
-        default:        abort(expr.inspect());
-      }
-      expr = rest;
-    }
-
-    if (expr.length > 0) abort(expr.inspect());
-  },
-
-  buildMatchExpression: function() {
-    var params = this.params, conditions = [], clause;
-
-    if (params.wildcard)
-      conditions.push('true');
-    if (clause = params.id)
-      conditions.push('element.readAttribute("id") == ' + clause.inspect());
-    if (clause = params.tagName)
-      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
-    if ((clause = params.classNames).length > 0)
-      for (var i = 0, length = clause.length; i < length; i++)
-        conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
-    if (clause = params.attributes) {
-      clause.each(function(attribute) {
-        var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
-        var splitValueBy = function(delimiter) {
-          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
-        }
-
-        switch (attribute.operator) {
-          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
-          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
-          case '|=':      conditions.push(
-                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
-                          ); break;
-          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
-          case '':
-          case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
-          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
-        }
-      });
-    }
-
-    return conditions.join(' && ');
-  },
-
-  compileMatcher: function() {
-    this.match = new Function('element', 'if (!element.tagName) return false; element = $(element); return ' + this.buildMatchExpression());
-  },
-
-  findElements: function(scope) {
-    var element;
-
-    if (element = $(this.params.id))
-      if (this.match(element))
-        if (!scope || Element.childOf(element, scope))
-          return [element];
-
-    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
-
-    var results = [];
-    for (var i = 0, length = scope.length; i < length; i++)
-      if (this.match(element = scope[i]))
-        results.push(Element.extend(element));
-
-    return results;
-  },
-
-  toString: function() {
-    return this.expression;
-  }
-}
-
-Object.extend(Selector, {
-  matchElements: function(elements, expression) {
-    var selector = new Selector(expression);
-    return elements.select(selector.match.bind(selector)).map(Element.extend);
-  },
-
-  findElement: function(elements, expression, index) {
-    if (typeof expression == 'number') index = expression, expression = false;
-    return Selector.matchElements(elements, expression || '*')[index || 0];
-  },
-
-  findChildElements: function(element, expressions) {
-    return expressions.map(function(expression) {
-      return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
-        var selector = new Selector(expr);
-        return results.inject([], function(elements, result) {
-          return elements.concat(selector.findElements(result || element));
-        });
-      });
-    }).flatten();
-  }
-});
-
-function $$() {
-  return Selector.findChildElements(document, $A(arguments));
-}
-var Form = {
-  reset: function(form) {
-    $(form).reset();
-    return form;
-  },
-
-  serializeElements: function(elements, getHash) {
-    var data = elements.inject({}, function(result, element) {
-      if (!element.disabled && element.name) {
-        var key = element.name, value = $(element).getValue();
-        if (value != undefined) {
-          if (result[key]) {
-            if (result[key].constructor != Array) result[key] = [result[key]];
-            result[key].push(value);
-          }
-          else result[key] = value;
-        }
-      }
-      return result;
-    });
-
-    return getHash ? data : Hash.toQueryString(data);
-  }
-};
-
-Form.Methods = {
-  serialize: function(form, getHash) {
-    return Form.serializeElements(Form.getElements(form), getHash);
-  },
-
-  getElements: function(form) {
-    return $A($(form).getElementsByTagName('*')).inject([],
-      function(elements, child) {
-        if (Form.Element.Serializers[child.tagName.toLowerCase()])
-          elements.push(Element.extend(child));
-        return elements;
-      }
-    );
-  },
-
-  getInputs: function(form, typeName, name) {
-    form = $(form);
-    var inputs = form.getElementsByTagName('input');
-
-    if (!typeName && !name) return $A(inputs).map(Element.extend);
-
-    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
-      var input = inputs[i];
-      if ((typeName && input.type != typeName) || (name && input.name != name))
-        continue;
-      matchingInputs.push(Element.extend(input));
-    }
-
-    return matchingInputs;
-  },
-
-  disable: function(form) {
-    form = $(form);
-    form.getElements().each(function(element) {
-      element.blur();
-      element.disabled = 'true';
-    });
-    return form;
-  },
-
-  enable: function(form) {
-    form = $(form);
-    form.getElements().each(function(element) {
-      element.disabled = '';
-    });
-    return form;
-  },
-
-  findFirstElement: function(form) {
-    return $(form).getElements().find(function(element) {
-      return element.type != 'hidden' && !element.disabled &&
-        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
-    });
-  },
-
-  focusFirstElement: function(form) {
-    form = $(form);
-    form.findFirstElement().activate();
-    return form;
-  }
-}
-
-Object.extend(Form, Form.Methods);
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element = {
-  focus: function(element) {
-    $(element).focus();
-    return element;
-  },
-
-  select: function(element) {
-    $(element).select();
-    return element;
-  }
-}
-
-Form.Element.Methods = {
-  serialize: function(element) {
-    element = $(element);
-    if (!element.disabled && element.name) {
-      var value = element.getValue();
-      if (value != undefined) {
-        var pair = {};
-        pair[element.name] = value;
-        return Hash.toQueryString(pair);
-      }
-    }
-    return '';
-  },
-
-  getValue: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    return Form.Element.Serializers[method](element);
-  },
-
-  clear: function(element) {
-    $(element).value = '';
-    return element;
-  },
-
-  present: function(element) {
-    return $(element).value != '';
-  },
-
-  activate: function(element) {
-    element = $(element);
-    element.focus();
-    if (element.select && ( element.tagName.toLowerCase() != 'input' ||
-      !['button', 'reset', 'submit'].include(element.type) ) )
-      element.select();
-    return element;
-  },
-
-  disable: function(element) {
-    element = $(element);
-    element.disabled = true;
-    return element;
-  },
-
-  enable: function(element) {
-    element = $(element);
-    element.blur();
-    element.disabled = false;
-    return element;
-  }
-}
-
-Object.extend(Form.Element, Form.Element.Methods);
-var Field = Form.Element;
-var $F = Form.Element.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element.Serializers = {
-  input: function(element) {
-    switch (element.type.toLowerCase()) {
-      case 'checkbox':
-      case 'radio':
-        return Form.Element.Serializers.inputSelector(element);
-      default:
-        return Form.Element.Serializers.textarea(element);
-    }
-  },
-
-  inputSelector: function(element) {
-    return element.checked ? element.value : null;
-  },
-
-  textarea: function(element) {
-    return element.value;
-  },
-
-  select: function(element) {
-    return this[element.type == 'select-one' ?
-      'selectOne' : 'selectMany'](element);
-  },
-
-  selectOne: function(element) {
-    var index = element.selectedIndex;
-    return index >= 0 ? this.optionValue(element.options[index]) : null;
-  },
-
-  selectMany: function(element) {
-    var values, length = element.length;
-    if (!length) return null;
-
-    for (var i = 0, values = []; i < length; i++) {
-      var opt = element.options[i];
-      if (opt.selected) values.push(this.optionValue(opt));
-    }
-    return values;
-  },
-
-  optionValue: function(opt) {
-    // extend element because hasAttribute may not be native
-    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = function() {}
-Abstract.TimedObserver.prototype = {
-  initialize: function(element, frequency, callback) {
-    this.frequency = frequency;
-    this.element   = $(element);
-    this.callback  = callback;
-
-    this.lastValue = this.getValue();
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    var value = this.getValue();
-    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
-      ? this.lastValue != value : String(this.lastValue) != String(value));
-    if (changed) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  }
-}
-
-Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.Observer = Class.create();
-Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = function() {}
-Abstract.EventObserver.prototype = {
-  initialize: function(element, callback) {
-    this.element  = $(element);
-    this.callback = callback;
-
-    this.lastValue = this.getValue();
-    if (this.element.tagName.toLowerCase() == 'form')
-      this.registerFormCallbacks();
-    else
-      this.registerCallback(this.element);
-  },
-
-  onElementEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  },
-
-  registerFormCallbacks: function() {
-    Form.getElements(this.element).each(this.registerCallback.bind(this));
-  },
-
-  registerCallback: function(element) {
-    if (element.type) {
-      switch (element.type.toLowerCase()) {
-        case 'checkbox':
-        case 'radio':
-          Event.observe(element, 'click', this.onElementEvent.bind(this));
-          break;
-        default:
-          Event.observe(element, 'change', this.onElementEvent.bind(this));
-          break;
-      }
-    }
-  }
-}
-
-Form.Element.EventObserver = Class.create();
-Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.EventObserver = Class.create();
-Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-if (!window.Event) {
-  var Event = new Object();
-}
-
-Object.extend(Event, {
-  KEY_BACKSPACE: 8,
-  KEY_TAB:       9,
-  KEY_RETURN:   13,
-  KEY_ESC:      27,
-  KEY_LEFT:     37,
-  KEY_UP:       38,
-  KEY_RIGHT:    39,
-  KEY_DOWN:     40,
-  KEY_DELETE:   46,
-  KEY_HOME:     36,
-  KEY_END:      35,
-  KEY_PAGEUP:   33,
-  KEY_PAGEDOWN: 34,
-
-  element: function(event) {
-    return event.target || event.srcElement;
-  },
-
-  isLeftClick: function(event) {
-    return (((event.which) && (event.which == 1)) ||
-            ((event.button) && (event.button == 1)));
-  },
-
-  pointerX: function(event) {
-    return event.pageX || (event.clientX +
-      (document.documentElement.scrollLeft || document.body.scrollLeft));
-  },
-
-  pointerY: function(event) {
-    return event.pageY || (event.clientY +
-      (document.documentElement.scrollTop || document.body.scrollTop));
-  },
-
-  stop: function(event) {
-    if (event.preventDefault) {
-      event.preventDefault();
-      event.stopPropagation();
-    } else {
-      event.returnValue = false;
-      event.cancelBubble = true;
-    }
-  },
-
-  // find the first node with the given tagName, starting from the
-  // node the event was triggered on; traverses the DOM upwards
-  findElement: function(event, tagName) {
-    var element = Event.element(event);
-    while (element.parentNode && (!element.tagName ||
-        (element.tagName.toUpperCase() != tagName.toUpperCase())))
-      element = element.parentNode;
-    return element;
-  },
-
-  observers: false,
-
-  _observeAndCache: function(element, name, observer, useCapture) {
-    if (!this.observers) this.observers = [];
-    if (element.addEventListener) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.addEventListener(name, observer, useCapture);
-    } else if (element.attachEvent) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.attachEvent('on' + name, observer);
-    }
-  },
-
-  unloadCache: function() {
-    if (!Event.observers) return;
-    for (var i = 0, length = Event.observers.length; i < length; i++) {
-      Event.stopObserving.apply(this, Event.observers[i]);
-      Event.observers[i][0] = null;
-    }
-    Event.observers = false;
-  },
-
-  observe: function(element, name, observer, useCapture) {
-    element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.attachEvent))
-      name = 'keydown';
-
-    Event._observeAndCache(element, name, observer, useCapture);
-  },
-
-  stopObserving: function(element, name, observer, useCapture) {
-    element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.detachEvent))
-      name = 'keydown';
-
-    if (element.removeEventListener) {
-      element.removeEventListener(name, observer, useCapture);
-    } else if (element.detachEvent) {
-      try {
-        element.detachEvent('on' + name, observer);
-      } catch (e) {}
-    }
-  }
-});
-
-/* prevent memory leaks in IE */
-if (navigator.appVersion.match(/\bMSIE\b/))
-  Event.observe(window, 'unload', Event.unloadCache, false);
-var Position = {
-  // set to true if needed, warning: firefox performance problems
-  // NOT neeeded for page scrolling, only if draggable contained in
-  // scrollable elements
-  includeScrollOffsets: false,
-
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
-  prepare: function() {
-    this.deltaX =  window.pageXOffset
-                || document.documentElement.scrollLeft
-                || document.body.scrollLeft
-                || 0;
-    this.deltaY =  window.pageYOffset
-                || document.documentElement.scrollTop
-                || document.body.scrollTop
-                || 0;
-  },
-
-  realOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.scrollTop  || 0;
-      valueL += element.scrollLeft || 0;
-      element = element.parentNode;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  cumulativeOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  positionedOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-      if (element) {
-        if(element.tagName=='BODY') break;
-        var p = Element.getStyle(element, 'position');
-        if (p == 'relative' || p == 'absolute') break;
-      }
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  offsetParent: function(element) {
-    if (element.offsetParent) return element.offsetParent;
-    if (element == document.body) return element;
-
-    while ((element = element.parentNode) && element != document.body)
-      if (Element.getStyle(element, 'position') != 'static')
-        return element;
-
-    return document.body;
-  },
-
-  // caches x/y coordinate pair to use with overlap
-  within: function(element, x, y) {
-    if (this.includeScrollOffsets)
-      return this.withinIncludingScrolloffsets(element, x, y);
-    this.xcomp = x;
-    this.ycomp = y;
-    this.offset = this.cumulativeOffset(element);
-
-    return (y >= this.offset[1] &&
-            y <  this.offset[1] + element.offsetHeight &&
-            x >= this.offset[0] &&
-            x <  this.offset[0] + element.offsetWidth);
-  },
-
-  withinIncludingScrolloffsets: function(element, x, y) {
-    var offsetcache = this.realOffset(element);
-
-    this.xcomp = x + offsetcache[0] - this.deltaX;
-    this.ycomp = y + offsetcache[1] - this.deltaY;
-    this.offset = this.cumulativeOffset(element);
-
-    return (this.ycomp >= this.offset[1] &&
-            this.ycomp <  this.offset[1] + element.offsetHeight &&
-            this.xcomp >= this.offset[0] &&
-            this.xcomp <  this.offset[0] + element.offsetWidth);
-  },
-
-  // within must be called directly before
-  overlap: function(mode, element) {
-    if (!mode) return 0;
-    if (mode == 'vertical')
-      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
-        element.offsetHeight;
-    if (mode == 'horizontal')
-      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
-        element.offsetWidth;
-  },
-
-  page: function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-
-      // Safari fix
-      if (element.offsetParent==document.body)
-        if (Element.getStyle(element,'position')=='absolute') break;
-
-    } while (element = element.offsetParent);
-
-    element = forElement;
-    do {
-      if (!window.opera || element.tagName=='BODY') {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-      }
-    } while (element = element.parentNode);
-
-    return [valueL, valueT];
-  },
-
-  clone: function(source, target) {
-    var options = Object.extend({
-      setLeft:    true,
-      setTop:     true,
-      setWidth:   true,
-      setHeight:  true,
-      offsetTop:  0,
-      offsetLeft: 0
-    }, arguments[2] || {})
-
-    // find page position of source
-    source = $(source);
-    var p = Position.page(source);
-
-    // find coordinate system to use
-    target = $(target);
-    var delta = [0, 0];
-    var parent = null;
-    // delta [0,0] will do fine with position: fixed elements,
-    // position:absolute needs offsetParent deltas
-    if (Element.getStyle(target,'position') == 'absolute') {
-      parent = Position.offsetParent(target);
-      delta = Position.page(parent);
-    }
-
-    // correct by body offsets (fixes Safari)
-    if (parent == document.body) {
-      delta[0] -= document.body.offsetLeft;
-      delta[1] -= document.body.offsetTop;
-    }
-
-    // set position
-    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
-    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
-    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
-    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
-  },
-
-  absolutize: function(element) {
-    element = $(element);
-    if (element.style.position == 'absolute') return;
-    Position.prepare();
-
-    var offsets = Position.positionedOffset(element);
-    var top     = offsets[1];
-    var left    = offsets[0];
-    var width   = element.clientWidth;
-    var height  = element.clientHeight;
-
-    element._originalLeft   = left - parseFloat(element.style.left  || 0);
-    element._originalTop    = top  - parseFloat(element.style.top || 0);
-    element._originalWidth  = element.style.width;
-    element._originalHeight = element.style.height;
-
-    element.style.position = 'absolute';
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.width  = width + 'px';
-    element.style.height = height + 'px';
-  },
-
-  relativize: function(element) {
-    element = $(element);
-    if (element.style.position == 'relative') return;
-    Position.prepare();
-
-    element.style.position = 'relative';
-    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
-    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.height = element._originalHeight;
-    element.style.width  = element._originalWidth;
-  }
-}
-
-// Safari returns margins on body which is incorrect if the child is absolutely
-// positioned.  For performance reasons, redefine Position.cumulativeOffset for
-// KHTML/WebKit only.
-if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
-  Position.cumulativeOffset = function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      if (element.offsetParent == document.body)
-        if (Element.getStyle(element, 'position') == 'absolute') break;
-
-      element = element.offsetParent;
-    } while (element);
-
-    return [valueL, valueT];
-  }
-}
-
-Element.addMethods();// script.aculo.us builder.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-var Builder = {
-  NODEMAP: {
-    AREA: 'map',
-    CAPTION: 'table',
-    COL: 'table',
-    COLGROUP: 'table',
-    LEGEND: 'fieldset',
-    OPTGROUP: 'select',
-    OPTION: 'select',
-    PARAM: 'object',
-    TBODY: 'table',
-    TD: 'table',
-    TFOOT: 'table',
-    TH: 'table',
-    THEAD: 'table',
-    TR: 'table'
-  },
-  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
-  //       due to a Firefox bug
-  node: function(elementName) {
-    elementName = elementName.toUpperCase();
-    
-    // try innerHTML approach
-    var parentTag = this.NODEMAP[elementName] || 'div';
-    var parentElement = document.createElement(parentTag);
-    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
-      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
-    } catch(e) {}
-    var element = parentElement.firstChild || null;
-      
-    // see if browser added wrapping tags
-    if(element && (element.tagName.toUpperCase() != elementName))
-      element = element.getElementsByTagName(elementName)[0];
-    
-    // fallback to createElement approach
-    if(!element) element = document.createElement(elementName);
-    
-    // abort if nothing could be created
-    if(!element) return;
-
-    // attributes (or text)
-    if(arguments[1])
-      if(this._isStringOrNumber(arguments[1]) ||
-        (arguments[1] instanceof Array)) {
-          this._children(element, arguments[1]);
-        } else {
-          var attrs = this._attributes(arguments[1]);
-          if(attrs.length) {
-            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
-              parentElement.innerHTML = "<" +elementName + " " +
-                attrs + "></" + elementName + ">";
-            } catch(e) {}
-            element = parentElement.firstChild || null;
-            // workaround firefox 1.0.X bug
-            if(!element) {
-              element = document.createElement(elementName);
-              for(attr in arguments[1]) 
-                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
-            }
-            if(element.tagName.toUpperCase() != elementName)
-              element = parentElement.getElementsByTagName(elementName)[0];
-            }
-        } 
-
-    // text, or array of children
-    if(arguments[2])
-      this._children(element, arguments[2]);
-
-     return element;
-  },
-  _text: function(text) {
-     return document.createTextNode(text);
-  },
-
-  ATTR_MAP: {
-    'className': 'class',
-    'htmlFor': 'for'
-  },
-
-  _attributes: function(attributes) {
-    var attrs = [];
-    for(attribute in attributes)
-      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
-          '="' + attributes[attribute].toString().escapeHTML() + '"');
-    return attrs.join(" ");
-  },
-  _children: function(element, children) {
-    if(typeof children=='object') { // array can hold nodes and text
-      children.flatten().each( function(e) {
-        if(typeof e=='object')
-          element.appendChild(e)
-        else
-          if(Builder._isStringOrNumber(e))
-            element.appendChild(Builder._text(e));
-      });
-    } else
-      if(Builder._isStringOrNumber(children)) 
-         element.appendChild(Builder._text(children));
-  },
-  _isStringOrNumber: function(param) {
-    return(typeof param=='string' || typeof param=='number');
-  },
-  build: function(html) {
-    var element = this.node('div');
-    $(element).update(html.strip());
-    return element.down();
-  },
-  dump: function(scope) { 
-    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
-  
-    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
-      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
-      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
-      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
-      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
-      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
-  
-    tags.each( function(tag){ 
-      scope[tag] = function() { 
-        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
-      } 
-    });
-  }
-}
-// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// Contributors:
-//  Justin Palmer (http://encytemedia.com/)
-//  Mark Pilgrim (http://diveintomark.org/)
-//  Martin Bialasinki
-// 
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/ 
-
-// converts rgb() and #xxx to #xxxxxx format,  
-// returns self (or first argument) if not convertable  
-String.prototype.parseColor = function() {  
-  var color = '#';
-  if(this.slice(0,4) == 'rgb(') {  
-    var cols = this.slice(4,this.length-1).split(',');  
-    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
-  } else {  
-    if(this.slice(0,1) == '#') {  
-      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
-      if(this.length==7) color = this.toLowerCase();  
-    }  
-  }  
-  return(color.length==7 ? color : (arguments[0] || this));  
-}
-
-/*--------------------------------------------------------------------------*/
-
-Element.collectTextNodes = function(element) {  
-  return $A($(element).childNodes).collect( function(node) {
-    return (node.nodeType==3 ? node.nodeValue : 
-      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
-  }).flatten().join('');
-}
-
-Element.collectTextNodesIgnoreClass = function(element, className) {  
-  return $A($(element).childNodes).collect( function(node) {
-    return (node.nodeType==3 ? node.nodeValue : 
-      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
-        Element.collectTextNodesIgnoreClass(node, className) : ''));
-  }).flatten().join('');
-}
-
-Element.setContentZoom = function(element, percent) {
-  element = $(element);  
-  element.setStyle({fontSize: (percent/100) + 'em'});   
-  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-  return element;
-}
-
-Element.getOpacity = function(element){
-  return $(element).getStyle('opacity');
-}
-
-Element.setOpacity = function(element, value){
-  return $(element).setStyle({opacity:value});
-}
-
-Element.getInlineOpacity = function(element){
-  return $(element).style.opacity || '';
-}
-
-Element.forceRerendering = function(element) {
-  try {
-    element = $(element);
-    var n = document.createTextNode(' ');
-    element.appendChild(n);
-    element.removeChild(n);
-  } catch(e) { }
-};
-
-/*--------------------------------------------------------------------------*/
-
-Array.prototype.call = function() {
-  var args = arguments;
-  this.each(function(f){ f.apply(this, args) });
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Effect = {
-  _elementDoesNotExistError: {
-    name: 'ElementDoesNotExistError',
-    message: 'The specified DOM element does not exist, but is required for this effect to operate'
-  },
-  tagifyText: function(element) {
-    if(typeof Builder == 'undefined')
-      throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
-      
-    var tagifyStyle = 'position:relative';
-    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
-    
-    element = $(element);
-    $A(element.childNodes).each( function(child) {
-      if(child.nodeType==3) {
-        child.nodeValue.toArray().each( function(character) {
-          element.insertBefore(
-            Builder.node('span',{style: tagifyStyle},
-              character == ' ' ? String.fromCharCode(160) : character), 
-              child);
-        });
-        Element.remove(child);
-      }
-    });
-  },
-  multiple: function(element, effect) {
-    var elements;
-    if(((typeof element == 'object') || 
-        (typeof element == 'function')) && 
-       (element.length))
-      elements = element;
-    else
-      elements = $(element).childNodes;
-      
-    var options = Object.extend({
-      speed: 0.1,
-      delay: 0.0
-    }, arguments[2] || {});
-    var masterDelay = options.delay;
-
-    $A(elements).each( function(element, index) {
-      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
-    });
-  },
-  PAIRS: {
-    'slide':  ['SlideDown','SlideUp'],
-    'blind':  ['BlindDown','BlindUp'],
-    'appear': ['Appear','Fade']
-  },
-  toggle: function(element, effect) {
-    element = $(element);
-    effect = (effect || 'appear').toLowerCase();
-    var options = Object.extend({
-      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
-    }, arguments[2] || {});
-    Effect[element.visible() ? 
-      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
-  }
-};
-
-var Effect2 = Effect; // deprecated
-
-/* ------------- transitions ------------- */
-
-Effect.Transitions = {
-  linear: Prototype.K,
-  sinoidal: function(pos) {
-    return (-Math.cos(pos*Math.PI)/2) + 0.5;
-  },
-  reverse: function(pos) {
-    return 1-pos;
-  },
-  flicker: function(pos) {
-    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
-  },
-  wobble: function(pos) {
-    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
-  },
-  pulse: function(pos, pulses) { 
-    pulses = pulses || 5; 
-    return (
-      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
-            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
-        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
-      );
-  },
-  none: function(pos) {
-    return 0;
-  },
-  full: function(pos) {
-    return 1;
-  }
-};
-
-/* ------------- core effects ------------- */
-
-Effect.ScopedQueue = Class.create();
-Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
-  initialize: function() {
-    this.effects  = [];
-    this.interval = null;
-  },
-  _each: function(iterator) {
-    this.effects._each(iterator);
-  },
-  add: function(effect) {
-    var timestamp = new Date().getTime();
-    
-    var position = (typeof effect.options.queue == 'string') ? 
-      effect.options.queue : effect.options.queue.position;
-    
-    switch(position) {
-      case 'front':
-        // move unstarted effects after this effect  
-        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
-            e.startOn  += effect.finishOn;
-            e.finishOn += effect.finishOn;
-          });
-        break;
-      case 'with-last':
-        timestamp = this.effects.pluck('startOn').max() || timestamp;
-        break;
-      case 'end':
-        // start effect after last queued effect has finished
-        timestamp = this.effects.pluck('finishOn').max() || timestamp;
-        break;
-    }
-    
-    effect.startOn  += timestamp;
-    effect.finishOn += timestamp;
-
-    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
-      this.effects.push(effect);
-    
-    if(!this.interval) 
-      this.interval = setInterval(this.loop.bind(this), 15);
-  },
-  remove: function(effect) {
-    this.effects = this.effects.reject(function(e) { return e==effect });
-    if(this.effects.length == 0) {
-      clearInterval(this.interval);
-      this.interval = null;
-    }
-  },
-  loop: function() {
-    var timePos = new Date().getTime();
-    for(var i=0, len=this.effects.length;i<len;i++) 
-      if(this.effects[i]) this.effects[i].loop(timePos);
-  }
-});
-
-Effect.Queues = {
-  instances: $H(),
-  get: function(queueName) {
-    if(typeof queueName != 'string') return queueName;
-    
-    if(!this.instances[queueName])
-      this.instances[queueName] = new Effect.ScopedQueue();
-      
-    return this.instances[queueName];
-  }
-}
-Effect.Queue = Effect.Queues.get('global');
-
-Effect.DefaultOptions = {
-  transition: Effect.Transitions.sinoidal,
-  duration:   1.0,   // seconds
-  fps:        60.0,  // max. 60fps due to Effect.Queue implementation
-  sync:       false, // true for combining
-  from:       0.0,
-  to:         1.0,
-  delay:      0.0,
-  queue:      'parallel'
-}
-
-Effect.Base = function() {};
-Effect.Base.prototype = {
-  position: null,
-  start: function(options) {
-    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
-    this.currentFrame = 0;
-    this.state        = 'idle';
-    this.startOn      = this.options.delay*1000;
-    this.finishOn     = this.startOn + (this.options.duration*1000);
-    this.event('beforeStart');
-    if(!this.options.sync)
-      Effect.Queues.get(typeof this.options.queue == 'string' ? 
-        'global' : this.options.queue.scope).add(this);
-  },
-  loop: function(timePos) {
-    if(timePos >= this.startOn) {
-      if(timePos >= this.finishOn) {
-        this.render(1.0);
-        this.cancel();
-        this.event('beforeFinish');
-        if(this.finish) this.finish(); 
-        this.event('afterFinish');
-        return;  
-      }
-      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
-      var frame = Math.round(pos * this.options.fps * this.options.duration);
-      if(frame > this.currentFrame) {
-        this.render(pos);
-        this.currentFrame = frame;
-      }
-    }
-  },
-  render: function(pos) {
-    if(this.state == 'idle') {
-      this.state = 'running';
-      this.event('beforeSetup');
-      if(this.setup) this.setup();
-      this.event('afterSetup');
-    }
-    if(this.state == 'running') {
-      if(this.options.transition) pos = this.options.transition(pos);
-      pos *= (this.options.to-this.options.from);
-      pos += this.options.from;
-      this.position = pos;
-      this.event('beforeUpdate');
-      if(this.update) this.update(pos);
-      this.event('afterUpdate');
-    }
-  },
-  cancel: function() {
-    if(!this.options.sync)
-      Effect.Queues.get(typeof this.options.queue == 'string' ? 
-        'global' : this.options.queue.scope).remove(this);
-    this.state = 'finished';
-  },
-  event: function(eventName) {
-    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
-    if(this.options[eventName]) this.options[eventName](this);
-  },
-  inspect: function() {
-    var data = $H();
-    for(property in this)
-      if(typeof this[property] != 'function') data[property] = this[property];
-    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
-  }
-}
-
-Effect.Parallel = Class.create();
-Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
-  initialize: function(effects) {
-    this.effects = effects || [];
-    this.start(arguments[1]);
-  },
-  update: function(position) {
-    this.effects.invoke('render', position);
-  },
-  finish: function(position) {
-    this.effects.each( function(effect) {
-      effect.render(1.0);
-      effect.cancel();
-      effect.event('beforeFinish');
-      if(effect.finish) effect.finish(position);
-      effect.event('afterFinish');
-    });
-  }
-});
-
-Effect.Event = Class.create();
-Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
-  initialize: function() {
-    var options = Object.extend({
-      duration: 0
-    }, arguments[0] || {});
-    this.start(options);
-  },
-  update: Prototype.emptyFunction
-});
-
-Effect.Opacity = Class.create();
-Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
-  initialize: function(element) {
-    this.element = $(element);
-    if(!this.element) throw(Effect._elementDoesNotExistError);
-    // make this work on IE on elements without 'layout'
-    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
-      this.element.setStyle({zoom: 1});
-    var options = Object.extend({
-      from: this.element.getOpacity() || 0.0,
-      to:   1.0
-    }, arguments[1] || {});
-    this.start(options);
-  },
-  update: function(position) {
-    this.element.setOpacity(position);
-  }
-});
-
-Effect.Move = Class.create();
-Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
-  initialize: function(element) {
-    this.element = $(element);
-    if(!this.element) throw(Effect._elementDoesNotExistError);
-    var options = Object.extend({
-      x:    0,
-      y:    0,
-      mode: 'relative'
-    }, arguments[1] || {});
-    this.start(options);
-  },
-  setup: function() {
-    // Bug in Opera: Opera returns the "real" position of a static element or
-    // relative element that does not have top/left explicitly set.
-    // ==> Always set top and left for position relative elements in your stylesheets 
-    // (to 0 if you do not need them) 
-    this.element.makePositioned();
-    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
-    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
-    if(this.options.mode == 'absolute') {
-      // absolute movement, so we need to calc deltaX and deltaY
-      this.options.x = this.options.x - this.originalLeft;
-      this.options.y = this.options.y - this.originalTop;
-    }
-  },
-  update: function(position) {
-    this.element.setStyle({
-      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
-      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
-    });
-  }
-});
-
-// for backwards compatibility
-Effect.MoveBy = function(element, toTop, toLeft) {
-  return new Effect.Move(element, 
-    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
-};
-
-Effect.Scale = Class.create();
-Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
-  initialize: function(element, percent) {
-    this.element = $(element);
-    if(!this.element) throw(Effect._elementDoesNotExistError);
-    var options = Object.extend({
-      scaleX: true,
-      scaleY: true,
-      scaleContent: true,
-      scaleFromCenter: false,
-      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
-      scaleFrom: 100.0,
-      scaleTo:   percent
-    }, arguments[2] || {});
-    this.start(options);
-  },
-  setup: function() {
-    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
-    this.elementPositioning = this.element.getStyle('position');
-    
-    this.originalStyle = {};
-    ['top','left','width','height','fontSize'].each( function(k) {
-      this.originalStyle[k] = this.element.style[k];
-    }.bind(this));
-      
-    this.originalTop  = this.element.offsetTop;
-    this.originalLeft = this.element.offsetLeft;
-    
-    var fontSize = this.element.getStyle('font-size') || '100%';
-    ['em','px','%','pt'].each( function(fontSizeType) {
-      if(fontSize.indexOf(fontSizeType)>0) {
-        this.fontSize     = parseFloat(fontSize);
-        this.fontSizeType = fontSizeType;
-      }
-    }.bind(this));
-    
-    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
-    
-    this.dims = null;
-    if(this.options.scaleMode=='box')
-      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
-    if(/^content/.test(this.options.scaleMode))
-      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
-    if(!this.dims)
-      this.dims = [this.options.scaleMode.originalHeight,
-                   this.options.scaleMode.originalWidth];
-  },
-  update: function(position) {
-    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
-    if(this.options.scaleContent && this.fontSize)
-      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
-    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
-  },
-  finish: function(position) {
-    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
-  },
-  setDimensions: function(height, width) {
-    var d = {};
-    if(this.options.scaleX) d.width = Math.round(width) + 'px';
-    if(this.options.scaleY) d.height = Math.round(height) + 'px';
-    if(this.options.scaleFromCenter) {
-      var topd  = (height - this.dims[0])/2;
-      var leftd = (width  - this.dims[1])/2;
-      if(this.elementPositioning == 'absolute') {
-        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
-        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
-      } else {
-        if(this.options.scaleY) d.top = -topd + 'px';
-        if(this.options.scaleX) d.left = -leftd + 'px';
-      }
-    }
-    this.element.setStyle(d);
-  }
-});
-
-Effect.Highlight = Class.create();
-Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
-  initialize: function(element) {
-    this.element = $(element);
-    if(!this.element) throw(Effect._elementDoesNotExistError);
-    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
-    this.start(options);
-  },
-  setup: function() {
-    // Prevent executing on elements not in the layout flow
-    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
-    // Disable background image during the effect
-    this.oldStyle = {};
-    if (!this.options.keepBackgroundImage) {
-      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
-      this.element.setStyle({backgroundImage: 'none'});
-    }
-    if(!this.options.endcolor)
-      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
-    if(!this.options.restorecolor)
-      this.options.restorecolor = this.element.getStyle('background-color');
-    // init color calculations
-    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
-    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
-  },
-  update: function(position) {
-    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
-      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
-  },
-  finish: function() {
-    this.element.setStyle(Object.extend(this.oldStyle, {
-      backgroundColor: this.options.restorecolor
-    }));
-  }
-});
-
-Effect.ScrollTo = Class.create();
-Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
-  initialize: function(element) {
-    this.element = $(element);
-    this.start(arguments[1] || {});
-  },
-  setup: function() {
-    Position.prepare();
-    var offsets = Position.cumulativeOffset(this.element);
-    if(this.options.offset) offsets[1] += this.options.offset;
-    var max = window.innerHeight ? 
-      window.height - window.innerHeight :
-      document.body.scrollHeight - 
-        (document.documentElement.clientHeight ? 
-          document.documentElement.clientHeight : document.body.clientHeight);
-    this.scrollStart = Position.deltaY;
-    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
-  },
-  update: function(position) {
-    Position.prepare();
-    window.scrollTo(Position.deltaX, 
-      this.scrollStart + (position*this.delta));
-  }
-});
-
-/* ------------- combination effects ------------- */
-
-Effect.Fade = function(element) {
-  element = $(element);
-  var oldOpacity = element.getInlineOpacity();
-  var options = Object.extend({
-  from: element.getOpacity() || 1.0,
-  to:   0.0,
-  afterFinishInternal: function(effect) { 
-    if(effect.options.to!=0) return;
-    effect.element.hide().setStyle({opacity: oldOpacity}); 
-  }}, arguments[1] || {});
-  return new Effect.Opacity(element,options);
-}
-
-Effect.Appear = function(element) {
-  element = $(element);
-  var options = Object.extend({
-  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
-  to:   1.0,
-  // force Safari to render floated elements properly
-  afterFinishInternal: function(effect) {
-    effect.element.forceRerendering();
-  },
-  beforeSetup: function(effect) {
-    effect.element.setOpacity(effect.options.from).show(); 
-  }}, arguments[1] || {});
-  return new Effect.Opacity(element,options);
-}
-
-Effect.Puff = function(element) {
-  element = $(element);
-  var oldStyle = { 
-    opacity: element.getInlineOpacity(), 
-    position: element.getStyle('position'),
-    top:  element.style.top,
-    left: element.style.left,
-    width: element.style.width,
-    height: element.style.height
-  };
-  return new Effect.Parallel(
-   [ new Effect.Scale(element, 200, 
-      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
-     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
-     Object.extend({ duration: 1.0, 
-      beforeSetupInternal: function(effect) {
-        Position.absolutize(effect.effects[0].element)
-      },
-      afterFinishInternal: function(effect) {
-         effect.effects[0].element.hide().setStyle(oldStyle); }
-     }, arguments[1] || {})
-   );
-}
-
-Effect.BlindUp = function(element) {
-  element = $(element);
-  element.makeClipping();
-  return new Effect.Scale(element, 0,
-    Object.extend({ scaleContent: false, 
-      scaleX: false, 
-      restoreAfterFinish: true,
-      afterFinishInternal: function(effect) {
-        effect.element.hide().undoClipping();
-      } 
-    }, arguments[1] || {})
-  );
-}
-
-Effect.BlindDown = function(element) {
-  element = $(element);
-  var elementDimensions = element.getDimensions();
-  return new Effect.Scale(element, 100, Object.extend({ 
-    scaleContent: false, 
-    scaleX: false,
-    scaleFrom: 0,
-    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
-    restoreAfterFinish: true,
-    afterSetup: function(effect) {
-      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
-    },  
-    afterFinishInternal: function(effect) {
-      effect.element.undoClipping();
-    }
-  }, arguments[1] || {}));
-}
-
-Effect.SwitchOff = function(element) {
-  element = $(element);
-  var oldOpacity = element.getInlineOpacity();
-  return new Effect.Appear(element, Object.extend({
-    duration: 0.4,
-    from: 0,
-    transition: Effect.Transitions.flicker,
-    afterFinishInternal: function(effect) {
-      new Effect.Scale(effect.element, 1, { 
-        duration: 0.3, scaleFromCenter: true,
-        scaleX: false, scaleContent: false, restoreAfterFinish: true,
-        beforeSetup: function(effect) { 
-          effect.element.makePositioned().makeClipping();
-        },
-        afterFinishInternal: function(effect) {
-          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
-        }
-      })
-    }
-  }, arguments[1] || {}));
-}
-
-Effect.DropOut = function(element) {
-  element = $(element);
-  var oldStyle = {
-    top: element.getStyle('top'),
-    left: element.getStyle('left'),
-    opacity: element.getInlineOpacity() };
-  return new Effect.Parallel(
-    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
-      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
-    Object.extend(
-      { duration: 0.5,
-        beforeSetup: function(effect) {
-          effect.effects[0].element.makePositioned(); 
-        },
-        afterFinishInternal: function(effect) {
-          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
-        } 
-      }, arguments[1] || {}));
-}
-
-Effect.Shake = function(element) {
-  element = $(element);
-  var oldStyle = {
-    top: element.getStyle('top'),
-    left: element.getStyle('left') };
-    return new Effect.Move(element, 
-      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
-    new Effect.Move(effect.element,
-      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
-    new Effect.Move(effect.element,
-      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
-    new Effect.Move(effect.element,
-      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
-    new Effect.Move(effect.element,
-      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
-    new Effect.Move(effect.element,
-      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
-        effect.element.undoPositioned().setStyle(oldStyle);
-  }}) }}) }}) }}) }}) }});
-}
-
-Effect.SlideDown = function(element) {
-  element = $(element).cleanWhitespace();
-  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
-  var oldInnerBottom = element.down().getStyle('bottom');
-  var elementDimensions = element.getDimensions();
-  return new Effect.Scale(element, 100, Object.extend({ 
-    scaleContent: false, 
-    scaleX: false, 
-    scaleFrom: window.opera ? 0 : 1,
-    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
-    restoreAfterFinish: true,
-    afterSetup: function(effect) {
-      effect.element.makePositioned();
-      effect.element.down().makePositioned();
-      if(window.opera) effect.element.setStyle({top: ''});
-      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
-    },
-    afterUpdateInternal: function(effect) {
-      effect.element.down().setStyle({bottom:
-        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
-    },
-    afterFinishInternal: function(effect) {
-      effect.element.undoClipping().undoPositioned();
-      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
-    }, arguments[1] || {})
-  );
-}
-
-Effect.SlideUp = function(element) {
-  element = $(element).cleanWhitespace();
-  var oldInnerBottom = element.down().getStyle('bottom');
-  return new Effect.Scale(element, window.opera ? 0 : 1,
-   Object.extend({ scaleContent: false, 
-    scaleX: false, 
-    scaleMode: 'box',
-    scaleFrom: 100,
-    restoreAfterFinish: true,
-    beforeStartInternal: function(effect) {
-      effect.element.makePositioned();
-      effect.element.down().makePositioned();
-      if(window.opera) effect.element.setStyle({top: ''});
-      effect.element.makeClipping().show();
-    },  
-    afterUpdateInternal: function(effect) {
-      effect.element.down().setStyle({bottom:
-        (effect.dims[0] - effect.element.clientHeight) + 'px' });
-    },
-    afterFinishInternal: function(effect) {
-      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
-      effect.element.down().undoPositioned();
-    }
-   }, arguments[1] || {})
-  );
-}
-
-// Bug in opera makes the TD containing this element expand for a instance after finish 
-Effect.Squish = function(element) {
-  return new Effect.Scale(element, window.opera ? 1 : 0, { 
-    restoreAfterFinish: true,
-    beforeSetup: function(effect) {
-      effect.element.makeClipping(); 
-    },  
-    afterFinishInternal: function(effect) {
-      effect.element.hide().undoClipping(); 
-    }
-  });
-}
-
-Effect.Grow = function(element) {
-  element = $(element);
-  var options = Object.extend({
-    direction: 'center',
-    moveTransition: Effect.Transitions.sinoidal,
-    scaleTransition: Effect.Transitions.sinoidal,
-    opacityTransition: Effect.Transitions.full
-  }, arguments[1] || {});
-  var oldStyle = {
-    top: element.style.top,
-    left: element.style.left,
-    height: element.style.height,
-    width: element.style.width,
-    opacity: element.getInlineOpacity() };
-
-  var dims = element.getDimensions();    
-  var initialMoveX, initialMoveY;
-  var moveX, moveY;
-  
-  switch (options.direction) {
-    case 'top-left':
-      initialMoveX = initialMoveY = moveX = moveY = 0; 
-      break;
-    case 'top-right':
-      initialMoveX = dims.width;
-      initialMoveY = moveY = 0;
-      moveX = -dims.width;
-      break;
-    case 'bottom-left':
-      initialMoveX = moveX = 0;
-      initialMoveY = dims.height;
-      moveY = -dims.height;
-      break;
-    case 'bottom-right':
-      initialMoveX = dims.width;
-      initialMoveY = dims.height;
-      moveX = -dims.width;
-      moveY = -dims.height;
-      break;
-    case 'center':
-      initialMoveX = dims.width / 2;
-      initialMoveY = dims.height / 2;
-      moveX = -dims.width / 2;
-      moveY = -dims.height / 2;
-      break;
-  }
-  
-  return new Effect.Move(element, {
-    x: initialMoveX,
-    y: initialMoveY,
-    duration: 0.01, 
-    beforeSetup: function(effect) {
-      effect.element.hide().makeClipping().makePositioned();
-    },
-    afterFinishInternal: function(effect) {
-      new Effect.Parallel(
-        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
-          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
-          new Effect.Scale(effect.element, 100, {
-            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
-            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
-        ], Object.extend({
-             beforeSetup: function(effect) {
-               effect.effects[0].element.setStyle({height: '0px'}).show(); 
-             },
-             afterFinishInternal: function(effect) {
-               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
-             }
-           }, options)
-      )
-    }
-  });
-}
-
-Effect.Shrink = function(element) {
-  element = $(element);
-  var options = Object.extend({
-    direction: 'center',
-    moveTransition: Effect.Transitions.sinoidal,
-    scaleTransition: Effect.Transitions.sinoidal,
-    opacityTransition: Effect.Transitions.none
-  }, arguments[1] || {});
-  var oldStyle = {
-    top: element.style.top,
-    left: element.style.left,
-    height: element.style.height,
-    width: element.style.width,
-    opacity: element.getInlineOpacity() };
-
-  var dims = element.getDimensions();
-  var moveX, moveY;
-  
-  switch (options.direction) {
-    case 'top-left':
-      moveX = moveY = 0;
-      break;
-    case 'top-right':
-      moveX = dims.width;
-      moveY = 0;
-      break;
-    case 'bottom-left':
-      moveX = 0;
-      moveY = dims.height;
-      break;
-    case 'bottom-right':
-      moveX = dims.width;
-      moveY = dims.height;
-      break;
-    case 'center':  
-      moveX = dims.width / 2;
-      moveY = dims.height / 2;
-      break;
-  }
-  
-  return new Effect.Parallel(
-    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
-      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
-      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
-    ], Object.extend({            
-         beforeStartInternal: function(effect) {
-           effect.effects[0].element.makePositioned().makeClipping(); 
-         },
-         afterFinishInternal: function(effect) {
-           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
-       }, options)
-  );
-}
-
-Effect.Pulsate = function(element) {
-  element = $(element);
-  var options    = arguments[1] || {};
-  var oldOpacity = element.getInlineOpacity();
-  var transition = options.transition || Effect.Transitions.sinoidal;
-  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
-  reverser.bind(transition);
-  return new Effect.Opacity(element, 
-    Object.extend(Object.extend({  duration: 2.0, from: 0,
-      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
-    }, options), {transition: reverser}));
-}
-
-Effect.Fold = function(element) {
-  element = $(element);
-  var oldStyle = {
-    top: element.style.top,
-    left: element.style.left,
-    width: element.style.width,
-    height: element.style.height };
-  element.makeClipping();
-  return new Effect.Scale(element, 5, Object.extend({   
-    scaleContent: false,
-    scaleX: false,
-    afterFinishInternal: function(effect) {
-    new Effect.Scale(element, 1, { 
-      scaleContent: false, 
-      scaleY: false,
-      afterFinishInternal: function(effect) {
-        effect.element.hide().undoClipping().setStyle(oldStyle);
-      } });
-  }}, arguments[1] || {}));
-};
-
-Effect.Morph = Class.create();
-Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
-  initialize: function(element) {
-    this.element = $(element);
-    if(!this.element) throw(Effect._elementDoesNotExistError);
-    var options = Object.extend({
-      style: {}
-    }, arguments[1] || {});
-    if (typeof options.style == 'string') {
-      if(options.style.indexOf(':') == -1) {
-        var cssText = '', selector = '.' + options.style;
-        $A(document.styleSheets).reverse().each(function(styleSheet) {
-          if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
-          else if (styleSheet.rules) cssRules = styleSheet.rules;
-          $A(cssRules).reverse().each(function(rule) {
-            if (selector == rule.selectorText) {
-              cssText = rule.style.cssText;
-              throw $break;
-            }
-          });
-          if (cssText) throw $break;
-        });
-        this.style = cssText.parseStyle();
-        options.afterFinishInternal = function(effect){
-          effect.element.addClassName(effect.options.style);
-          effect.transforms.each(function(transform) {
-            if(transform.style != 'opacity')
-              effect.element.style[transform.style.camelize()] = '';
-          });
-        }
-      } else this.style = options.style.parseStyle();
-    } else this.style = $H(options.style)
-    this.start(options);
-  },
-  setup: function(){
-    function parseColor(color){
-      if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
-      color = color.parseColor();
-      return $R(0,2).map(function(i){
-        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
-      });
-    }
-    this.transforms = this.style.map(function(pair){
-      var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
-
-      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
-        value = value.parseColor();
-        unit  = 'color';
-      } else if(property == 'opacity') {
-        value = parseFloat(value);
-        if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
-          this.element.setStyle({zoom: 1});
-      } else if(Element.CSS_LENGTH.test(value)) 
-        var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
-          value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
-
-      var originalValue = this.element.getStyle(property);
-      return $H({ 
-        style: property, 
-        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
-        targetValue: unit=='color' ? parseColor(value) : value,
-        unit: unit
-      });
-    }.bind(this)).reject(function(transform){
-      return (
-        (transform.originalValue == transform.targetValue) ||
-        (
-          transform.unit != 'color' &&
-          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
-        )
-      )
-    });
-  },
-  update: function(position) {
-    var style = $H(), value = null;
-    this.transforms.each(function(transform){
-      value = transform.unit=='color' ?
-        $R(0,2).inject('#',function(m,v,i){
-          return m+(Math.round(transform.originalValue[i]+
-            (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : 
-        transform.originalValue + Math.round(
-          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
-      style[transform.style] = value;
-    });
-    this.element.setStyle(style);
-  }
-});
-
-Effect.Transform = Class.create();
-Object.extend(Effect.Transform.prototype, {
-  initialize: function(tracks){
-    this.tracks  = [];
-    this.options = arguments[1] || {};
-    this.addTracks(tracks);
-  },
-  addTracks: function(tracks){
-    tracks.each(function(track){
-      var data = $H(track).values().first();
-      this.tracks.push($H({
-        ids:     $H(track).keys().first(),
-        effect:  Effect.Morph,
-        options: { style: data }
-      }));
-    }.bind(this));
-    return this;
-  },
-  play: function(){
-    return new Effect.Parallel(
-      this.tracks.map(function(track){
-        var elements = [$(track.ids) || $$(track.ids)].flatten();
-        return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
-      }).flatten(),
-      this.options
-    );
-  }
-});
-
-Element.CSS_PROPERTIES = $w(
-  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
-  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
-  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
-  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
-  'fontSize fontWeight height left letterSpacing lineHeight ' +
-  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
-  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
-  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
-  'right textIndent top width wordSpacing zIndex');
-  
-Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
-
-String.prototype.parseStyle = function(){
-  var element = Element.extend(document.createElement('div'));
-  element.innerHTML = '<div style="' + this + '"></div>';
-  var style = element.down().style, styleRules = $H();
-  
-  Element.CSS_PROPERTIES.each(function(property){
-    if(style[property]) styleRules[property] = style[property]; 
-  });
-  if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
-    styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
-  }
-  return styleRules;
-};
-
-Element.morph = function(element, style) {
-  new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
-  return element;
-};
-
-['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
- 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
-  function(f) { Element.Methods[f] = Element[f]; }
-);
-
-Element.Methods.visualEffect = function(element, effect, options) {
-  s = effect.gsub(/_/, '-').camelize();
-  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
-  new Effect[effect_class](element, options);
-  return $(element);
-};
-
-Element.addMethods();// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-//           (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi at oriontransfer.co.nz)
-// 
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-if(typeof Effect == 'undefined')
-  throw("dragdrop.js requires including script.aculo.us' effects.js library");
-
-var Droppables = {
-  drops: [],
-
-  remove: function(element) {
-    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
-  },
-
-  add: function(element) {
-    element = $(element);
-    var options = Object.extend({
-      greedy:     true,
-      hoverclass: null,
-      tree:       false
-    }, arguments[1] || {});
-
-    // cache containers
-    if(options.containment) {
-      options._containers = [];
-      var containment = options.containment;
-      if((typeof containment == 'object') && 
-        (containment.constructor == Array)) {
-        containment.each( function(c) { options._containers.push($(c)) });
-      } else {
-        options._containers.push($(containment));
-      }
-    }
-    
-    if(options.accept) options.accept = [options.accept].flatten();
-
-    Element.makePositioned(element); // fix IE
-    options.element = element;
-
-    this.drops.push(options);
-  },
-  
-  findDeepestChild: function(drops) {
-    deepest = drops[0];
-      
-    for (i = 1; i < drops.length; ++i)
-      if (Element.isParent(drops[i].element, deepest.element))
-        deepest = drops[i];
-    
-    return deepest;
-  },
-
-  isContained: function(element, drop) {
-    var containmentNode;
-    if(drop.tree) {
-      containmentNode = element.treeNode; 
-    } else {
-      containmentNode = element.parentNode;
-    }
-    return drop._containers.detect(function(c) { return containmentNode == c });
-  },
-  
-  isAffected: function(point, element, drop) {
-    return (
-      (drop.element!=element) &&
-      ((!drop._containers) ||
-        this.isContained(element, drop)) &&
-      ((!drop.accept) ||
-        (Element.classNames(element).detect( 
-          function(v) { return drop.accept.include(v) } ) )) &&
-      Position.within(drop.element, point[0], point[1]) );
-  },
-
-  deactivate: function(drop) {
-    if(drop.hoverclass)
-      Element.removeClassName(drop.element, drop.hoverclass);
-    this.last_active = null;
-  },
-
-  activate: function(drop) {
-    if(drop.hoverclass)
-      Element.addClassName(drop.element, drop.hoverclass);
-    this.last_active = drop;
-  },
-
-  show: function(point, element) {
-    if(!this.drops.length) return;
-    var affected = [];
-    
-    if(this.last_active) this.deactivate(this.last_active);
-    this.drops.each( function(drop) {
-      if(Droppables.isAffected(point, element, drop))
-        affected.push(drop);
-    });
-        
-    if(affected.length>0) {
-      drop = Droppables.findDeepestChild(affected);
-      Position.within(drop.element, point[0], point[1]);
-      if(drop.onHover)
-        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
-      
-      Droppables.activate(drop);
-    }
-  },
-
-  fire: function(event, element) {
-    if(!this.last_active) return;
-    Position.prepare();
-
-    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
-      if (this.last_active.onDrop) 
-        this.last_active.onDrop(element, this.last_active.element, event);
-  },
-
-  reset: function() {
-    if(this.last_active)
-      this.deactivate(this.last_active);
-  }
-}
-
-var Draggables = {
-  drags: [],
-  observers: [],
-  
-  register: function(draggable) {
-    if(this.drags.length == 0) {
-      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
-      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
-      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
-      
-      Event.observe(document, "mouseup", this.eventMouseUp);
-      Event.observe(document, "mousemove", this.eventMouseMove);
-      Event.observe(document, "keypress", this.eventKeypress);
-    }
-    this.drags.push(draggable);
-  },
-  
-  unregister: function(draggable) {
-    this.drags = this.drags.reject(function(d) { return d==draggable });
-    if(this.drags.length == 0) {
-      Event.stopObserving(document, "mouseup", this.eventMouseUp);
-      Event.stopObserving(document, "mousemove", this.eventMouseMove);
-      Event.stopObserving(document, "keypress", this.eventKeypress);
-    }
-  },
-  
-  activate: function(draggable) {
-    if(draggable.options.delay) { 
-      this._timeout = setTimeout(function() { 
-        Draggables._timeout = null; 
-        window.focus(); 
-        Draggables.activeDraggable = draggable; 
-      }.bind(this), draggable.options.delay); 
-    } else {
-      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
-      this.activeDraggable = draggable;
-    }
-  },
-  
-  deactivate: function() {
-    this.activeDraggable = null;
-  },
-  
-  updateDrag: function(event) {
-    if(!this.activeDraggable) return;
-    var pointer = [Event.pointerX(event), Event.pointerY(event)];
-    // Mozilla-based browsers fire successive mousemove events with
-    // the same coordinates, prevent needless redrawing (moz bug?)
-    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
-    this._lastPointer = pointer;
-    
-    this.activeDraggable.updateDrag(event, pointer);
-  },
-  
-  endDrag: function(event) {
-    if(this._timeout) { 
-      clearTimeout(this._timeout); 
-      this._timeout = null; 
-    }
-    if(!this.activeDraggable) return;
-    this._lastPointer = null;
-    this.activeDraggable.endDrag(event);
-    this.activeDraggable = null;
-  },
-  
-  keyPress: function(event) {
-    if(this.activeDraggable)
-      this.activeDraggable.keyPress(event);
-  },
-  
-  addObserver: function(observer) {
-    this.observers.push(observer);
-    this._cacheObserverCallbacks();
-  },
-  
-  removeObserver: function(element) {  // element instead of observer fixes mem leaks
-    this.observers = this.observers.reject( function(o) { return o.element==element });
-    this._cacheObserverCallbacks();
-  },
-  
-  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
-    if(this[eventName+'Count'] > 0)
-      this.observers.each( function(o) {
-        if(o[eventName]) o[eventName](eventName, draggable, event);
-      });
-    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
-  },
-  
-  _cacheObserverCallbacks: function() {
-    ['onStart','onEnd','onDrag'].each( function(eventName) {
-      Draggables[eventName+'Count'] = Draggables.observers.select(
-        function(o) { return o[eventName]; }
-      ).length;
-    });
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Draggable = Class.create();
-Draggable._dragging    = {};
-
-Draggable.prototype = {
-  initialize: function(element) {
-    var defaults = {
-      handle: false,
-      reverteffect: function(element, top_offset, left_offset) {
-        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
-        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
-          queue: {scope:'_draggable', position:'end'}
-        });
-      },
-      endeffect: function(element) {
-        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
-        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
-          queue: {scope:'_draggable', position:'end'},
-          afterFinish: function(){ 
-            Draggable._dragging[element] = false 
-          }
-        }); 
-      },
-      zindex: 1000,
-      revert: false,
-      scroll: false,
-      scrollSensitivity: 20,
-      scrollSpeed: 15,
-      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
-      delay: 0
-    };
-    
-    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
-      Object.extend(defaults, {
-        starteffect: function(element) {
-          element._opacity = Element.getOpacity(element);
-          Draggable._dragging[element] = true;
-          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
-        }
-      });
-    
-    var options = Object.extend(defaults, arguments[1] || {});
-
-    this.element = $(element);
-    
-    if(options.handle && (typeof options.handle == 'string'))
-      this.handle = this.element.down('.'+options.handle, 0);
-    
-    if(!this.handle) this.handle = $(options.handle);
-    if(!this.handle) this.handle = this.element;
-    
-    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
-      options.scroll = $(options.scroll);
-      this._isScrollChild = Element.childOf(this.element, options.scroll);
-    }
-
-    Element.makePositioned(this.element); // fix IE    
-
-    this.delta    = this.currentDelta();
-    this.options  = options;
-    this.dragging = false;   
-
-    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
-    Event.observe(this.handle, "mousedown", this.eventMouseDown);
-    
-    Draggables.register(this);
-  },
-  
-  destroy: function() {
-    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
-    Draggables.unregister(this);
-  },
-  
-  currentDelta: function() {
-    return([
-      parseInt(Element.getStyle(this.element,'left') || '0'),
-      parseInt(Element.getStyle(this.element,'top') || '0')]);
-  },
-  
-  initDrag: function(event) {
-    if(typeof Draggable._dragging[this.element] != 'undefined' &&
-      Draggable._dragging[this.element]) return;
-    if(Event.isLeftClick(event)) {    
-      // abort on form elements, fixes a Firefox issue
-      var src = Event.element(event);
-      if((tag_name = src.tagName.toUpperCase()) && (
-        tag_name=='INPUT' ||
-        tag_name=='SELECT' ||
-        tag_name=='OPTION' ||
-        tag_name=='BUTTON' ||
-        tag_name=='TEXTAREA')) return;
-        
-      var pointer = [Event.pointerX(event), Event.pointerY(event)];
-      var pos     = Position.cumulativeOffset(this.element);
-      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
-      
-      Draggables.activate(this);
-      Event.stop(event);
-    }
-  },
-  
-  startDrag: function(event) {
-    this.dragging = true;
-    
-    if(this.options.zindex) {
-      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
-      this.element.style.zIndex = this.options.zindex;
-    }
-    
-    if(this.options.ghosting) {
-      this._clone = this.element.cloneNode(true);
-      Position.absolutize(this.element);
-      this.element.parentNode.insertBefore(this._clone, this.element);
-    }
-    
-    if(this.options.scroll) {
-      if (this.options.scroll == window) {
-        var where = this._getWindowScroll(this.options.scroll);
-        this.originalScrollLeft = where.left;
-        this.originalScrollTop = where.top;
-      } else {
-        this.originalScrollLeft = this.options.scroll.scrollLeft;
-        this.originalScrollTop = this.options.scroll.scrollTop;
-      }
-    }
-    
-    Draggables.notify('onStart', this, event);
-        
-    if(this.options.starteffect) this.options.starteffect(this.element);
-  },
-  
-  updateDrag: function(event, pointer) {
-    if(!this.dragging) this.startDrag(event);
-    Position.prepare();
-    Droppables.show(pointer, this.element);
-    Draggables.notify('onDrag', this, event);
-    
-    this.draw(pointer);
-    if(this.options.change) this.options.change(this);
-    
-    if(this.options.scroll) {
-      this.stopScrolling();
-      
-      var p;
-      if (this.options.scroll == window) {
-        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
-      } else {
-        p = Position.page(this.options.scroll);
-        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
-        p[1] += this.options.scroll.scrollTop + Position.deltaY;
-        p.push(p[0]+this.options.scroll.offsetWidth);
-        p.push(p[1]+this.options.scroll.offsetHeight);
-      }
-      var speed = [0,0];
-      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
-      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
-      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
-      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
-      this.startScrolling(speed);
-    }
-    
-    // fix AppleWebKit rendering
-    if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-    
-    Event.stop(event);
-  },
-  
-  finishDrag: function(event, success) {
-    this.dragging = false;
-
-    if(this.options.ghosting) {
-      Position.relativize(this.element);
-      Element.remove(this._clone);
-      this._clone = null;
-    }
-
-    if(success) Droppables.fire(event, this.element);
-    Draggables.notify('onEnd', this, event);
-
-    var revert = this.options.revert;
-    if(revert && typeof revert == 'function') revert = revert(this.element);
-    
-    var d = this.currentDelta();
-    if(revert && this.options.reverteffect) {
-      this.options.reverteffect(this.element, 
-        d[1]-this.delta[1], d[0]-this.delta[0]);
-    } else {
-      this.delta = d;
-    }
-
-    if(this.options.zindex)
-      this.element.style.zIndex = this.originalZ;
-
-    if(this.options.endeffect) 
-      this.options.endeffect(this.element);
-      
-    Draggables.deactivate(this);
-    Droppables.reset();
-  },
-  
-  keyPress: function(event) {
-    if(event.keyCode!=Event.KEY_ESC) return;
-    this.finishDrag(event, false);
-    Event.stop(event);
-  },
-  
-  endDrag: function(event) {
-    if(!this.dragging) return;
-    this.stopScrolling();
-    this.finishDrag(event, true);
-    Event.stop(event);
-  },
-  
-  draw: function(point) {
-    var pos = Position.cumulativeOffset(this.element);
-    if(this.options.ghosting) {
-      var r   = Position.realOffset(this.element);
-      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
-    }
-    
-    var d = this.currentDelta();
-    pos[0] -= d[0]; pos[1] -= d[1];
-    
-    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
-      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
-      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
-    }
-    
-    var p = [0,1].map(function(i){ 
-      return (point[i]-pos[i]-this.offset[i]) 
-    }.bind(this));
-    
-    if(this.options.snap) {
-      if(typeof this.options.snap == 'function') {
-        p = this.options.snap(p[0],p[1],this);
-      } else {
-      if(this.options.snap instanceof Array) {
-        p = p.map( function(v, i) {
-          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
-      } else {
-        p = p.map( function(v) {
-          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
-      }
-    }}
-    
-    var style = this.element.style;
-    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
-      style.left = p[0] + "px";
-    if((!this.options.constraint) || (this.options.constraint=='vertical'))
-      style.top  = p[1] + "px";
-    
-    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
-  },
-  
-  stopScrolling: function() {
-    if(this.scrollInterval) {
-      clearInterval(this.scrollInterval);
-      this.scrollInterval = null;
-      Draggables._lastScrollPointer = null;
-    }
-  },
-  
-  startScrolling: function(speed) {
-    if(!(speed[0] || speed[1])) return;
-    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
-    this.lastScrolled = new Date();
-    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
-  },
-  
-  scroll: function() {
-    var current = new Date();
-    var delta = current - this.lastScrolled;
-    this.lastScrolled = current;
-    if(this.options.scroll == window) {
-      with (this._getWindowScroll(this.options.scroll)) {
-        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
-          var d = delta / 1000;
-          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
-        }
-      }
-    } else {
-      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
-      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
-    }
-    
-    Position.prepare();
-    Droppables.show(Draggables._lastPointer, this.element);
-    Draggables.notify('onDrag', this);
-    if (this._isScrollChild) {
-      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
-      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
-      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
-      if (Draggables._lastScrollPointer[0] < 0)
-        Draggables._lastScrollPointer[0] = 0;
-      if (Draggables._lastScrollPointer[1] < 0)
-        Draggables._lastScrollPointer[1] = 0;
-      this.draw(Draggables._lastScrollPointer);
-    }
-    
-    if(this.options.change) this.options.change(this);
-  },
-  
-  _getWindowScroll: function(w) {
-    var T, L, W, H;
-    with (w.document) {
-      if (w.document.documentElement && documentElement.scrollTop) {
-        T = documentElement.scrollTop;
-        L = documentElement.scrollLeft;
-      } else if (w.document.body) {
-        T = body.scrollTop;
-        L = body.scrollLeft;
-      }
-      if (w.innerWidth) {
-        W = w.innerWidth;
-        H = w.innerHeight;
-      } else if (w.document.documentElement && documentElement.clientWidth) {
-        W = documentElement.clientWidth;
-        H = documentElement.clientHeight;
-      } else {
-        W = body.offsetWidth;
-        H = body.offsetHeight
-      }
-    }
-    return { top: T, left: L, width: W, height: H };
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var SortableObserver = Class.create();
-SortableObserver.prototype = {
-  initialize: function(element, observer) {
-    this.element   = $(element);
-    this.observer  = observer;
-    this.lastValue = Sortable.serialize(this.element);
-  },
-  
-  onStart: function() {
-    this.lastValue = Sortable.serialize(this.element);
-  },
-  
-  onEnd: function() {
-    Sortable.unmark();
-    if(this.lastValue != Sortable.serialize(this.element))
-      this.observer(this.element)
-  }
-}
-
-var Sortable = {
-  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
-  
-  sortables: {},
-  
-  _findRootElement: function(element) {
-    while (element.tagName.toUpperCase() != "BODY") {  
-      if(element.id && Sortable.sortables[element.id]) return element;
-      element = element.parentNode;
-    }
-  },
-
-  options: function(element) {
-    element = Sortable._findRootElement($(element));
-    if(!element) return;
-    return Sortable.sortables[element.id];
-  },
-  
-  destroy: function(element){
-    var s = Sortable.options(element);
-    
-    if(s) {
-      Draggables.removeObserver(s.element);
-      s.droppables.each(function(d){ Droppables.remove(d) });
-      s.draggables.invoke('destroy');
-      
-      delete Sortable.sortables[s.element.id];
-    }
-  },
-
-  create: function(element) {
-    element = $(element);
-    var options = Object.extend({ 
-      element:     element,
-      tag:         'li',       // assumes li children, override with tag: 'tagname'
-      dropOnEmpty: false,
-      tree:        false,
-      treeTag:     'ul',
-      overlap:     'vertical', // one of 'vertical', 'horizontal'
-      constraint:  'vertical', // one of 'vertical', 'horizontal', false
-      containment: element,    // also takes array of elements (or id's); or false
-      handle:      false,      // or a CSS class
-      only:        false,
-      delay:       0,
-      hoverclass:  null,
-      ghosting:    false,
-      scroll:      false,
-      scrollSensitivity: 20,
-      scrollSpeed: 15,
-      format:      this.SERIALIZE_RULE,
-      onChange:    Prototype.emptyFunction,
-      onUpdate:    Prototype.emptyFunction
-    }, arguments[1] || {});
-
-    // clear any old sortable with same element
-    this.destroy(element);
-
-    // build options for the draggables
-    var options_for_draggable = {
-      revert:      true,
-      scroll:      options.scroll,
-      scrollSpeed: options.scrollSpeed,
-      scrollSensitivity: options.scrollSensitivity,
-      delay:       options.delay,
-      ghosting:    options.ghosting,
-      constraint:  options.constraint,
-      handle:      options.handle };
-
-    if(options.starteffect)
-      options_for_draggable.starteffect = options.starteffect;
-
-    if(options.reverteffect)
-      options_for_draggable.reverteffect = options.reverteffect;
-    else
-      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
-        element.style.top  = 0;
-        element.style.left = 0;
-      };
-
-    if(options.endeffect)
-      options_for_draggable.endeffect = options.endeffect;
-
-    if(options.zindex)
-      options_for_draggable.zindex = options.zindex;
-
-    // build options for the droppables  
-    var options_for_droppable = {
-      overlap:     options.overlap,
-      containment: options.containment,
-      tree:        options.tree,
-      hoverclass:  options.hoverclass,
-      onHover:     Sortable.onHover
-    }
-    
-    var options_for_tree = {
-      onHover:      Sortable.onEmptyHover,
-      overlap:      options.overlap,
-      containment:  options.containment,
-      hoverclass:   options.hoverclass
-    }
-
-    // fix for gecko engine
-    Element.cleanWhitespace(element); 
-
-    options.draggables = [];
-    options.droppables = [];
-
-    // drop on empty handling
-    if(options.dropOnEmpty || options.tree) {
-      Droppables.add(element, options_for_tree);
-      options.droppables.push(element);
-    }
-
-    (this.findElements(element, options) || []).each( function(e) {
-      // handles are per-draggable
-      var handle = options.handle ? 
-        $(e).down('.'+options.handle,0) : e;    
-      options.draggables.push(
-        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
-      Droppables.add(e, options_for_droppable);
-      if(options.tree) e.treeNode = element;
-      options.droppables.push(e);      
-    });
-    
-    if(options.tree) {
-      (Sortable.findTreeElements(element, options) || []).each( function(e) {
-        Droppables.add(e, options_for_tree);
-        e.treeNode = element;
-        options.droppables.push(e);
-      });
-    }
-
-    // keep reference
-    this.sortables[element.id] = options;
-
-    // for onupdate
-    Draggables.addObserver(new SortableObserver(element, options.onUpdate));
-
-  },
-
-  // return all suitable-for-sortable elements in a guaranteed order
-  findElements: function(element, options) {
-    return Element.findChildren(
-      element, options.only, options.tree ? true : false, options.tag);
-  },
-  
-  findTreeElements: function(element, options) {
-    return Element.findChildren(
-      element, options.only, options.tree ? true : false, options.treeTag);
-  },
-
-  onHover: function(element, dropon, overlap) {
-    if(Element.isParent(dropon, element)) return;
-
-    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
-      return;
-    } else if(overlap>0.5) {
-      Sortable.mark(dropon, 'before');
-      if(dropon.previousSibling != element) {
-        var oldParentNode = element.parentNode;
-        element.style.visibility = "hidden"; // fix gecko rendering
-        dropon.parentNode.insertBefore(element, dropon);
-        if(dropon.parentNode!=oldParentNode) 
-          Sortable.options(oldParentNode).onChange(element);
-        Sortable.options(dropon.parentNode).onChange(element);
-      }
-    } else {
-      Sortable.mark(dropon, 'after');
-      var nextElement = dropon.nextSibling || null;
-      if(nextElement != element) {
-        var oldParentNode = element.parentNode;
-        element.style.visibility = "hidden"; // fix gecko rendering
-        dropon.parentNode.insertBefore(element, nextElement);
-        if(dropon.parentNode!=oldParentNode) 
-          Sortable.options(oldParentNode).onChange(element);
-        Sortable.options(dropon.parentNode).onChange(element);
-      }
-    }
-  },
-  
-  onEmptyHover: function(element, dropon, overlap) {
-    var oldParentNode = element.parentNode;
-    var droponOptions = Sortable.options(dropon);
-        
-    if(!Element.isParent(dropon, element)) {
-      var index;
-      
-      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
-      var child = null;
-            
-      if(children) {
-        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
-        
-        for (index = 0; index < children.length; index += 1) {
-          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
-            offset -= Element.offsetSize (children[index], droponOptions.overlap);
-          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
-            child = index + 1 < children.length ? children[index + 1] : null;
-            break;
-          } else {
-            child = children[index];
-            break;
-          }
-        }
-      }
-      
-      dropon.insertBefore(element, child);
-      
-      Sortable.options(oldParentNode).onChange(element);
-      droponOptions.onChange(element);
-    }
-  },
-
-  unmark: function() {
-    if(Sortable._marker) Sortable._marker.hide();
-  },
-
-  mark: function(dropon, position) {
-    // mark on ghosting only
-    var sortable = Sortable.options(dropon.parentNode);
-    if(sortable && !sortable.ghosting) return; 
-
-    if(!Sortable._marker) {
-      Sortable._marker = 
-        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
-          hide().addClassName('dropmarker').setStyle({position:'absolute'});
-      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
-    }    
-    var offsets = Position.cumulativeOffset(dropon);
-    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
-    
-    if(position=='after')
-      if(sortable.overlap == 'horizontal') 
-        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
-      else
-        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
-    
-    Sortable._marker.show();
-  },
-  
-  _tree: function(element, options, parent) {
-    var children = Sortable.findElements(element, options) || [];
-  
-    for (var i = 0; i < children.length; ++i) {
-      var match = children[i].id.match(options.format);
-
-      if (!match) continue;
-      
-      var child = {
-        id: encodeURIComponent(match ? match[1] : null),
-        element: element,
-        parent: parent,
-        children: [],
-        position: parent.children.length,
-        container: $(children[i]).down(options.treeTag)
-      }
-      
-      /* Get the element containing the children and recurse over it */
-      if (child.container)
-        this._tree(child.container, options, child)
-      
-      parent.children.push (child);
-    }
-
-    return parent; 
-  },
-
-  tree: function(element) {
-    element = $(element);
-    var sortableOptions = this.options(element);
-    var options = Object.extend({
-      tag: sortableOptions.tag,
-      treeTag: sortableOptions.treeTag,
-      only: sortableOptions.only,
-      name: element.id,
-      format: sortableOptions.format
-    }, arguments[1] || {});
-    
-    var root = {
-      id: null,
-      parent: null,
-      children: [],
-      container: element,
-      position: 0
-    }
-    
-    return Sortable._tree(element, options, root);
-  },
-
-  /* Construct a [i] index for a particular node */
-  _constructIndex: function(node) {
-    var index = '';
-    do {
-      if (node.id) index = '[' + node.position + ']' + index;
-    } while ((node = node.parent) != null);
-    return index;
-  },
-
-  sequence: function(element) {
-    element = $(element);
-    var options = Object.extend(this.options(element), arguments[1] || {});
-    
-    return $(this.findElements(element, options) || []).map( function(item) {
-      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
-    });
-  },
-
-  setSequence: function(element, new_sequence) {
-    element = $(element);
-    var options = Object.extend(this.options(element), arguments[2] || {});
-    
-    var nodeMap = {};
-    this.findElements(element, options).each( function(n) {
-        if (n.id.match(options.format))
-            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
-        n.parentNode.removeChild(n);
-    });
-   
-    new_sequence.each(function(ident) {
-      var n = nodeMap[ident];
-      if (n) {
-        n[1].appendChild(n[0]);
-        delete nodeMap[ident];
-      }
-    });
-  },
-  
-  serialize: function(element) {
-    element = $(element);
-    var options = Object.extend(Sortable.options(element), arguments[1] || {});
-    var name = encodeURIComponent(
-      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
-    
-    if (options.tree) {
-      return Sortable.tree(element, arguments[1]).children.map( function (item) {
-        return [name + Sortable._constructIndex(item) + "[id]=" + 
-                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
-      }).flatten().join('&');
-    } else {
-      return Sortable.sequence(element, arguments[1]).map( function(item) {
-        return name + "[]=" + encodeURIComponent(item);
-      }).join('&');
-    }
-  }
-}
-
-// Returns true if child is contained within element
-Element.isParent = function(child, element) {
-  if (!child.parentNode || child == element) return false;
-  if (child.parentNode == element) return true;
-  return Element.isParent(child.parentNode, element);
-}
-
-Element.findChildren = function(element, only, recursive, tagName) {    
-  if(!element.hasChildNodes()) return null;
-  tagName = tagName.toUpperCase();
-  if(only) only = [only].flatten();
-  var elements = [];
-  $A(element.childNodes).each( function(e) {
-    if(e.tagName && e.tagName.toUpperCase()==tagName &&
-      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
-        elements.push(e);
-    if(recursive) {
-      var grandchildren = Element.findChildren(e, only, recursive, tagName);
-      if(grandchildren) elements.push(grandchildren);
-    }
-  });
-
-  return (elements.length>0 ? elements.flatten() : []);
-}
-
-Element.offsetSize = function (element, type) {
-  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
-}
-// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-//           (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
-//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
-// Contributors:
-//  Richard Livsey
-//  Rahul Bhargava
-//  Rob Wills
-// 
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-// Autocompleter.Base handles all the autocompletion functionality 
-// that's independent of the data source for autocompletion. This
-// includes drawing the autocompletion menu, observing keyboard
-// and mouse events, and similar.
-//
-// Specific autocompleters need to provide, at the very least, 
-// a getUpdatedChoices function that will be invoked every time
-// the text inside the monitored textbox changes. This method 
-// should get the text for which to provide autocompletion by
-// invoking this.getToken(), NOT by directly accessing
-// this.element.value. This is to allow incremental tokenized
-// autocompletion. Specific auto-completion logic (AJAX, etc)
-// belongs in getUpdatedChoices.
-//
-// Tokenized incremental autocompletion is enabled automatically
-// when an autocompleter is instantiated with the 'tokens' option
-// in the options parameter, e.g.:
-// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
-// will incrementally autocomplete with a comma as the token.
-// Additionally, ',' in the above example can be replaced with
-// a token array, e.g. { tokens: [',', '\n'] } which
-// enables autocompletion on multiple tokens. This is most 
-// useful when one of the tokens is \n (a newline), as it 
-// allows smart autocompletion after linebreaks.
-
-if(typeof Effect == 'undefined')
-  throw("controls.js requires including script.aculo.us' effects.js library");
-
-var Autocompleter = {}
-Autocompleter.Base = function() {};
-Autocompleter.Base.prototype = {
-  baseInitialize: function(element, update, options) {
-    this.element     = $(element); 
-    this.update      = $(update);  
-    this.hasFocus    = false; 
-    this.changed     = false; 
-    this.active      = false; 
-    this.index       = 0;     
-    this.entryCount  = 0;
-
-    if(this.setOptions)
-      this.setOptions(options);
-    else
-      this.options = options || {};
-
-    this.options.paramName    = this.options.paramName || this.element.name;
-    this.options.tokens       = this.options.tokens || [];
-    this.options.frequency    = this.options.frequency || 0.4;
-    this.options.minChars     = this.options.minChars || 1;
-    this.options.onShow       = this.options.onShow || 
-      function(element, update){ 
-        if(!update.style.position || update.style.position=='absolute') {
-          update.style.position = 'absolute';
-          Position.clone(element, update, {
-            setHeight: false, 
-            offsetTop: element.offsetHeight
-          });
-        }
-        Effect.Appear(update,{duration:0.15});
-      };
-    this.options.onHide = this.options.onHide || 
-      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
-
-    if(typeof(this.options.tokens) == 'string') 
-      this.options.tokens = new Array(this.options.tokens);
-
-    this.observer = null;
-    
-    this.element.setAttribute('autocomplete','off');
-
-    Element.hide(this.update);
-
-    Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
-    Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
-  },
-
-  show: function() {
-    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
-    if(!this.iefix && 
-      (navigator.appVersion.indexOf('MSIE')>0) &&
-      (navigator.userAgent.indexOf('Opera')<0) &&
-      (Element.getStyle(this.update, 'position')=='absolute')) {
-      new Insertion.After(this.update, 
-       '<iframe id="' + this.update.id + '_iefix" '+
-       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
-       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
-      this.iefix = $(this.update.id+'_iefix');
-    }
-    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
-  },
-  
-  fixIEOverlapping: function() {
-    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
-    this.iefix.style.zIndex = 1;
-    this.update.style.zIndex = 2;
-    Element.show(this.iefix);
-  },
-
-  hide: function() {
-    this.stopIndicator();
-    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
-    if(this.iefix) Element.hide(this.iefix);
-  },
-
-  startIndicator: function() {
-    if(this.options.indicator) Element.show(this.options.indicator);
-  },
-
-  stopIndicator: function() {
-    if(this.options.indicator) Element.hide(this.options.indicator);
-  },
-
-  onKeyPress: function(event) {
-    if(this.active)
-      switch(event.keyCode) {
-       case Event.KEY_TAB:
-       case Event.KEY_RETURN:
-         this.selectEntry();
-         Event.stop(event);
-       case Event.KEY_ESC:
-         this.hide();
-         this.active = false;
-         Event.stop(event);
-         return;
-       case Event.KEY_LEFT:
-       case Event.KEY_RIGHT:
-         return;
-       case Event.KEY_UP:
-         this.markPrevious();
-         this.render();
-         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
-         return;
-       case Event.KEY_DOWN:
-         this.markNext();
-         this.render();
-         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
-         return;
-      }
-     else 
-       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
-         (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
-
-    this.changed = true;
-    this.hasFocus = true;
-
-    if(this.observer) clearTimeout(this.observer);
-      this.observer = 
-        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
-  },
-
-  activate: function() {
-    this.changed = false;
-    this.hasFocus = true;
-    this.getUpdatedChoices();
-  },
-
-  onHover: function(event) {
-    var element = Event.findElement(event, 'LI');
-    if(this.index != element.autocompleteIndex) 
-    {
-        this.index = element.autocompleteIndex;
-        this.render();
-    }
-    Event.stop(event);
-  },
-  
-  onClick: function(event) {
-    var element = Event.findElement(event, 'LI');
-    this.index = element.autocompleteIndex;
-    this.selectEntry();
-    this.hide();
-  },
-  
-  onBlur: function(event) {
-    // needed to make click events working
-    setTimeout(this.hide.bind(this), 250);
-    this.hasFocus = false;
-    this.active = false;     
-  }, 
-  
-  render: function() {
-    if(this.entryCount > 0) {
-      for (var i = 0; i < this.entryCount; i++)
-        this.index==i ? 
-          Element.addClassName(this.getEntry(i),"selected") : 
-          Element.removeClassName(this.getEntry(i),"selected");
-        
-      if(this.hasFocus) { 
-        this.show();
-        this.active = true;
-      }
-    } else {
-      this.active = false;
-      this.hide();
-    }
-  },
-  
-  markPrevious: function() {
-    if(this.index > 0) this.index--
-      else this.index = this.entryCount-1;
-    this.getEntry(this.index).scrollIntoView(true);
-  },
-  
-  markNext: function() {
-    if(this.index < this.entryCount-1) this.index++
-      else this.index = 0;
-    this.getEntry(this.index).scrollIntoView(false);
-  },
-  
-  getEntry: function(index) {
-    return this.update.firstChild.childNodes[index];
-  },
-  
-  getCurrentEntry: function() {
-    return this.getEntry(this.index);
-  },
-  
-  selectEntry: function() {
-    this.active = false;
-    this.updateElement(this.getCurrentEntry());
-  },
-
-  updateElement: function(selectedElement) {
-    if (this.options.updateElement) {
-      this.options.updateElement(selectedElement);
-      return;
-    }
-    var value = '';
-    if (this.options.select) {
-      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
-      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
-    } else
-      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
-    
-    var lastTokenPos = this.findLastToken();
-    if (lastTokenPos != -1) {
-      var newValue = this.element.value.substr(0, lastTokenPos + 1);
-      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
-      if (whitespace)
-        newValue += whitespace[0];
-      this.element.value = newValue + value;
-    } else {
-      this.element.value = value;
-    }
-    this.element.focus();
-    
-    if (this.options.afterUpdateElement)
-      this.options.afterUpdateElement(this.element, selectedElement);
-  },
-
-  updateChoices: function(choices) {
-    if(!this.changed && this.hasFocus) {
-      this.update.innerHTML = choices;
-      Element.cleanWhitespace(this.update);
-      Element.cleanWhitespace(this.update.down());
-
-      if(this.update.firstChild && this.update.down().childNodes) {
-        this.entryCount = 
-          this.update.down().childNodes.length;
-        for (var i = 0; i < this.entryCount; i++) {
-          var entry = this.getEntry(i);
-          entry.autocompleteIndex = i;
-          this.addObservers(entry);
-        }
-      } else { 
-        this.entryCount = 0;
-      }
-
-      this.stopIndicator();
-      this.index = 0;
-      
-      if(this.entryCount==1 && this.options.autoSelect) {
-        this.selectEntry();
-        this.hide();
-      } else {
-        this.render();
-      }
-    }
-  },
-
-  addObservers: function(element) {
-    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
-    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
-  },
-
-  onObserverEvent: function() {
-    this.changed = false;   
-    if(this.getToken().length>=this.options.minChars) {
-      this.startIndicator();
-      this.getUpdatedChoices();
-    } else {
-      this.active = false;
-      this.hide();
-    }
-  },
-
-  getToken: function() {
-    var tokenPos = this.findLastToken();
-    if (tokenPos != -1)
-      var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
-    else
-      var ret = this.element.value;
-
-    return /\n/.test(ret) ? '' : ret;
-  },
-
-  findLastToken: function() {
-    var lastTokenPos = -1;
-
-    for (var i=0; i<this.options.tokens.length; i++) {
-      var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
-      if (thisTokenPos > lastTokenPos)
-        lastTokenPos = thisTokenPos;
-    }
-    return lastTokenPos;
-  }
-}
-
-Ajax.Autocompleter = Class.create();
-Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
-  initialize: function(element, update, url, options) {
-    this.baseInitialize(element, update, options);
-    this.options.asynchronous  = true;
-    this.options.onComplete    = this.onComplete.bind(this);
-    this.options.defaultParams = this.options.parameters || null;
-    this.url                   = url;
-  },
-
-  getUpdatedChoices: function() {
-    entry = encodeURIComponent(this.options.paramName) + '=' + 
-      encodeURIComponent(this.getToken());
-
-    this.options.parameters = this.options.callback ?
-      this.options.callback(this.element, entry) : entry;
-
-    if(this.options.defaultParams) 
-      this.options.parameters += '&' + this.options.defaultParams;
-
-    new Ajax.Request(this.url, this.options);
-  },
-
-  onComplete: function(request) {
-    this.updateChoices(request.responseText);
-  }
-
-});
-
-// The local array autocompleter. Used when you'd prefer to
-// inject an array of autocompletion options into the page, rather
-// than sending out Ajax queries, which can be quite slow sometimes.
-//
-// The constructor takes four parameters. The first two are, as usual,
-// the id of the monitored textbox, and id of the autocompletion menu.
-// The third is the array you want to autocomplete from, and the fourth
-// is the options block.
-//
-// Extra local autocompletion options:
-// - choices - How many autocompletion choices to offer
-//
-// - partialSearch - If false, the autocompleter will match entered
-//                    text only at the beginning of strings in the 
-//                    autocomplete array. Defaults to true, which will
-//                    match text at the beginning of any *word* in the
-//                    strings in the autocomplete array. If you want to
-//                    search anywhere in the string, additionally set
-//                    the option fullSearch to true (default: off).
-//
-// - fullSsearch - Search anywhere in autocomplete array strings.
-//
-// - partialChars - How many characters to enter before triggering
-//                   a partial match (unlike minChars, which defines
-//                   how many characters are required to do any match
-//                   at all). Defaults to 2.
-//
-// - ignoreCase - Whether to ignore case when autocompleting.
-//                 Defaults to true.
-//
-// It's possible to pass in a custom function as the 'selector' 
-// option, if you prefer to write your own autocompletion logic.
-// In that case, the other options above will not apply unless
-// you support them.
-
-Autocompleter.Local = Class.create();
-Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
-  initialize: function(element, update, array, options) {
-    this.baseInitialize(element, update, options);
-    this.options.array = array;
-  },
-
-  getUpdatedChoices: function() {
-    this.updateChoices(this.options.selector(this));
-  },
-
-  setOptions: function(options) {
-    this.options = Object.extend({
-      choices: 10,
-      partialSearch: true,
-      partialChars: 2,
-      ignoreCase: true,
-      fullSearch: false,
-      selector: function(instance) {
-        var ret       = []; // Beginning matches
-        var partial   = []; // Inside matches
-        var entry     = instance.getToken();
-        var count     = 0;
-
-        for (var i = 0; i < instance.options.array.length &&  
-          ret.length < instance.options.choices ; i++) { 
-
-          var elem = instance.options.array[i];
-          var foundPos = instance.options.ignoreCase ? 
-            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
-            elem.indexOf(entry);
-
-          while (foundPos != -1) {
-            if (foundPos == 0 && elem.length != entry.length) { 
-              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
-                elem.substr(entry.length) + "</li>");
-              break;
-            } else if (entry.length >= instance.options.partialChars && 
-              instance.options.partialSearch && foundPos != -1) {
-              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
-                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
-                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
-                  foundPos + entry.length) + "</li>");
-                break;
-              }
-            }
-
-            foundPos = instance.options.ignoreCase ? 
-              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
-              elem.indexOf(entry, foundPos + 1);
-
-          }
-        }
-        if (partial.length)
-          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
-        return "<ul>" + ret.join('') + "</ul>";
-      }
-    }, options || {});
-  }
-});
-
-// AJAX in-place editor
-//
-// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
-
-// Use this if you notice weird scrolling problems on some browsers,
-// the DOM might be a bit confused when this gets called so do this
-// waits 1 ms (with setTimeout) until it does the activation
-Field.scrollFreeActivate = function(field) {
-  setTimeout(function() {
-    Field.activate(field);
-  }, 1);
-}
-
-Ajax.InPlaceEditor = Class.create();
-Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
-Ajax.InPlaceEditor.prototype = {
-  initialize: function(element, url, options) {
-    this.url = url;
-    this.element = $(element);
-
-    this.options = Object.extend({
-      paramName: "value",
-      okButton: true,
-      okText: "ok",
-      cancelLink: true,
-      cancelText: "cancel",
-      savingText: "Saving...",
-      clickToEditText: "Click to edit",
-      okText: "ok",
-      rows: 1,
-      onComplete: function(transport, element) {
-        new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
-      },
-      onFailure: function(transport) {
-        alert("Error communicating with the server: " + transport.responseText.stripTags());
-      },
-      callback: function(form) {
-        return Form.serialize(form);
-      },
-      handleLineBreaks: true,
-      loadingText: 'Loading...',
-      savingClassName: 'inplaceeditor-saving',
-      loadingClassName: 'inplaceeditor-loading',
-      formClassName: 'inplaceeditor-form',
-      highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
-      highlightendcolor: "#FFFFFF",
-      externalControl: null,
-      submitOnBlur: false,
-      ajaxOptions: {},
-      evalScripts: false
-    }, options || {});
-
-    if(!this.options.formId && this.element.id) {
-      this.options.formId = this.element.id + "-inplaceeditor";
-      if ($(this.options.formId)) {
-        // there's already a form with that name, don't specify an id
-        this.options.formId = null;
-      }
-    }
-    
-    if (this.options.externalControl) {
-      this.options.externalControl = $(this.options.externalControl);
-    }
-    
-    this.originalBackground = Element.getStyle(this.element, 'background-color');
-    if (!this.originalBackground) {
-      this.originalBackground = "transparent";
-    }
-    
-    this.element.title = this.options.clickToEditText;
-    
-    this.onclickListener = this.enterEditMode.bindAsEventListener(this);
-    this.mouseoverListener = this.enterHover.bindAsEventListener(this);
-    this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
-    Event.observe(this.element, 'click', this.onclickListener);
-    Event.observe(this.element, 'mouseover', this.mouseoverListener);
-    Event.observe(this.element, 'mouseout', this.mouseoutListener);
-    if (this.options.externalControl) {
-      Event.observe(this.options.externalControl, 'click', this.onclickListener);
-      Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
-      Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
-    }
-  },
-  enterEditMode: function(evt) {
-    if (this.saving) return;
-    if (this.editing) return;
-    this.editing = true;
-    this.onEnterEditMode();
-    if (this.options.externalControl) {
-      Element.hide(this.options.externalControl);
-    }
-    Element.hide(this.element);
-    this.createForm();
-    this.element.parentNode.insertBefore(this.form, this.element);
-    if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
-    // stop the event to avoid a page refresh in Safari
-    if (evt) {
-      Event.stop(evt);
-    }
-    return false;
-  },
-  createForm: function() {
-    this.form = document.createElement("form");
-    this.form.id = this.options.formId;
-    Element.addClassName(this.form, this.options.formClassName)
-    this.form.onsubmit = this.onSubmit.bind(this);
-
-    this.createEditField();
-
-    if (this.options.textarea) {
-      var br = document.createElement("br");
-      this.form.appendChild(br);
-    }
-
-    if (this.options.okButton) {
-      okButton = document.createElement("input");
-      okButton.type = "submit";
-      okButton.value = this.options.okText;
-      okButton.className = 'editor_ok_button';
-      this.form.appendChild(okButton);
-    }
-
-    if (this.options.cancelLink) {
-      cancelLink = document.createElement("a");
-      cancelLink.href = "javascript:void(0)";
-      cancelLink.appendChild(document.createTextNode(this.options.cancelText));
-      cancelLink.onclick = this.onclickCancel.bind(this);
-      cancelLink.className = 'editor_cancel';      
-      this.form.appendChild(cancelLink);
-    }
-  },
-  hasHTMLLineBreaks: function(string) {
-    if (!this.options.handleLineBreaks) return false;
-    return string.match(/<br/i) || string.match(/<p>/i);
-  },
-  convertHTMLLineBreaks: function(string) {
-    return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
-  },
-  createEditField: function() {
-    var text;
-    if(this.options.loadTextURL) {
-      text = this.options.loadingText;
-    } else {
-      text = this.getText();
-    }
-
-    var obj = this;
-    
-    if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
-      this.options.textarea = false;
-      var textField = document.createElement("input");
-      textField.obj = this;
-      textField.type = "text";
-      textField.name = this.options.paramName;
-      textField.value = text;
-      textField.style.backgroundColor = this.options.highlightcolor;
-      textField.className = 'editor_field';
-      var size = this.options.size || this.options.cols || 0;
-      if (size != 0) textField.size = size;
-      if (this.options.submitOnBlur)
-        textField.onblur = this.onSubmit.bind(this);
-      this.editField = textField;
-    } else {
-      this.options.textarea = true;
-      var textArea = document.createElement("textarea");
-      textArea.obj = this;
-      textArea.name = this.options.paramName;
-      textArea.value = this.convertHTMLLineBreaks(text);
-      textArea.rows = this.options.rows;
-      textArea.cols = this.options.cols || 40;
-      textArea.className = 'editor_field';      
-      if (this.options.submitOnBlur)
-        textArea.onblur = this.onSubmit.bind(this);
-      this.editField = textArea;
-    }
-    
-    if(this.options.loadTextURL) {
-      this.loadExternalText();
-    }
-    this.form.appendChild(this.editField);
-  },
-  getText: function() {
-    return this.element.innerHTML;
-  },
-  loadExternalText: function() {
-    Element.addClassName(this.form, this.options.loadingClassName);
-    this.editField.disabled = true;
-    new Ajax.Request(
-      this.options.loadTextURL,
-      Object.extend({
-        asynchronous: true,
-        onComplete: this.onLoadedExternalText.bind(this)
-      }, this.options.ajaxOptions)
-    );
-  },
-  onLoadedExternalText: function(transport) {
-    Element.removeClassName(this.form, this.options.loadingClassName);
-    this.editField.disabled = false;
-    this.editField.value = transport.responseText.stripTags();
-    Field.scrollFreeActivate(this.editField);
-  },
-  onclickCancel: function() {
-    this.onComplete();
-    this.leaveEditMode();
-    return false;
-  },
-  onFailure: function(transport) {
-    this.options.onFailure(transport);
-    if (this.oldInnerHTML) {
-      this.element.innerHTML = this.oldInnerHTML;
-      this.oldInnerHTML = null;
-    }
-    return false;
-  },
-  onSubmit: function() {
-    // onLoading resets these so we need to save them away for the Ajax call
-    var form = this.form;
-    var value = this.editField.value;
-    
-    // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
-    // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
-    // to be displayed indefinitely
-    this.onLoading();
-    
-    if (this.options.evalScripts) {
-      new Ajax.Request(
-        this.url, Object.extend({
-          parameters: this.options.callback(form, value),
-          onComplete: this.onComplete.bind(this),
-          onFailure: this.onFailure.bind(this),
-          asynchronous:true, 
-          evalScripts:true
-        }, this.options.ajaxOptions));
-    } else  {
-      new Ajax.Updater(
-        { success: this.element,
-          // don't update on failure (this could be an option)
-          failure: null }, 
-        this.url, Object.extend({
-          parameters: this.options.callback(form, value),
-          onComplete: this.onComplete.bind(this),
-          onFailure: this.onFailure.bind(this)
-        }, this.options.ajaxOptions));
-    }
-    // stop the event to avoid a page refresh in Safari
-    if (arguments.length > 1) {
-      Event.stop(arguments[0]);
-    }
-    return false;
-  },
-  onLoading: function() {
-    this.saving = true;
-    this.removeForm();
-    this.leaveHover();
-    this.showSaving();
-  },
-  showSaving: function() {
-    this.oldInnerHTML = this.element.innerHTML;
-    this.element.innerHTML = this.options.savingText;
-    Element.addClassName(this.element, this.options.savingClassName);
-    this.element.style.backgroundColor = this.originalBackground;
-    Element.show(this.element);
-  },
-  removeForm: function() {
-    if(this.form) {
-      if (this.form.parentNode) Element.remove(this.form);
-      this.form = null;
-    }
-  },
-  enterHover: function() {
-    if (this.saving) return;
-    this.element.style.backgroundColor = this.options.highlightcolor;
-    if (this.effect) {
-      this.effect.cancel();
-    }
-    Element.addClassName(this.element, this.options.hoverClassName)
-  },
-  leaveHover: function() {
-    if (this.options.backgroundColor) {
-      this.element.style.backgroundColor = this.oldBackground;
-    }
-    Element.removeClassName(this.element, this.options.hoverClassName)
-    if (this.saving) return;
-    this.effect = new Effect.Highlight(this.element, {
-      startcolor: this.options.highlightcolor,
-      endcolor: this.options.highlightendcolor,
-      restorecolor: this.originalBackground
-    });
-  },
-  leaveEditMode: function() {
-    Element.removeClassName(this.element, this.options.savingClassName);
-    this.removeForm();
-    this.leaveHover();
-    this.element.style.backgroundColor = this.originalBackground;
-    Element.show(this.element);
-    if (this.options.externalControl) {
-      Element.show(this.options.externalControl);
-    }
-    this.editing = false;
-    this.saving = false;
-    this.oldInnerHTML = null;
-    this.onLeaveEditMode();
-  },
-  onComplete: function(transport) {
-    this.leaveEditMode();
-    this.options.onComplete.bind(this)(transport, this.element);
-  },
-  onEnterEditMode: function() {},
-  onLeaveEditMode: function() {},
-  dispose: function() {
-    if (this.oldInnerHTML) {
-      this.element.innerHTML = this.oldInnerHTML;
-    }
-    this.leaveEditMode();
-    Event.stopObserving(this.element, 'click', this.onclickListener);
-    Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
-    Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
-    if (this.options.externalControl) {
-      Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
-      Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
-      Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
-    }
-  }
-};
-
-Ajax.InPlaceCollectionEditor = Class.create();
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
-Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
-  createEditField: function() {
-    if (!this.cached_selectTag) {
-      var selectTag = document.createElement("select");
-      var collection = this.options.collection || [];
-      var optionTag;
-      collection.each(function(e,i) {
-        optionTag = document.createElement("option");
-        optionTag.value = (e instanceof Array) ? e[0] : e;
-        if((typeof this.options.value == 'undefined') && 
-          ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
-        if(this.options.value==optionTag.value) optionTag.selected = true;
-        optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
-        selectTag.appendChild(optionTag);
-      }.bind(this));
-      this.cached_selectTag = selectTag;
-    }
-
-    this.editField = this.cached_selectTag;
-    if(this.options.loadTextURL) this.loadExternalText();
-    this.form.appendChild(this.editField);
-    this.options.callback = function(form, value) {
-      return "value=" + encodeURIComponent(value);
-    }
-  }
-});
-
-// Delayed observer, like Form.Element.Observer, 
-// but waits for delay after last key input
-// Ideal for live-search fields
-
-Form.Element.DelayedObserver = Class.create();
-Form.Element.DelayedObserver.prototype = {
-  initialize: function(element, delay, callback) {
-    this.delay     = delay || 0.5;
-    this.element   = $(element);
-    this.callback  = callback;
-    this.timer     = null;
-    this.lastValue = $F(this.element); 
-    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
-  },
-  delayedListener: function(event) {
-    if(this.lastValue == $F(this.element)) return;
-    if(this.timer) clearTimeout(this.timer);
-    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
-    this.lastValue = $F(this.element);
-  },
-  onTimerEvent: function() {
-    this.timer = null;
-    this.callback(this.element, $F(this.element));
-  }
-};
-// script.aculo.us slider.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
-
-// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs 
-//
-// script.aculo.us is freely distributable under the terms of an MIT-style license.
-// For details, see the script.aculo.us web site: http://script.aculo.us/
-
-if(!Control) var Control = {};
-Control.Slider = Class.create();
-
-// options:
-//  axis: 'vertical', or 'horizontal' (default)
-//
-// callbacks:
-//  onChange(value)
-//  onSlide(value)
-Control.Slider.prototype = {
-  initialize: function(handle, track, options) {
-    var slider = this;
-    
-    if(handle instanceof Array) {
-      this.handles = handle.collect( function(e) { return $(e) });
-    } else {
-      this.handles = [$(handle)];
-    }
-    
-    this.track   = $(track);
-    this.options = options || {};
-
-    this.axis      = this.options.axis || 'horizontal';
-    this.increment = this.options.increment || 1;
-    this.step      = parseInt(this.options.step || '1');
-    this.range     = this.options.range || $R(0,1);
-    
-    this.value     = 0; // assure backwards compat
-    this.values    = this.handles.map( function() { return 0 });
-    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
-    this.options.startSpan = $(this.options.startSpan || null);
-    this.options.endSpan   = $(this.options.endSpan || null);
-
-    this.restricted = this.options.restricted || false;
-
-    this.maximum   = this.options.maximum || this.range.end;
-    this.minimum   = this.options.minimum || this.range.start;
-
-    // Will be used to align the handle onto the track, if necessary
-    this.alignX = parseInt(this.options.alignX || '0');
-    this.alignY = parseInt(this.options.alignY || '0');
-    
-    this.trackLength = this.maximumOffset() - this.minimumOffset();
-
-    this.handleLength = this.isVertical() ? 
-      (this.handles[0].offsetHeight != 0 ? 
-        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
-      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
-        this.handles[0].style.width.replace(/px$/,""));
-
-    this.active   = false;
-    this.dragging = false;
-    this.disabled = false;
-
-    if(this.options.disabled) this.setDisabled();
-
-    // Allowed values array
-    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
-    if(this.allowedValues) {
-      this.minimum = this.allowedValues.min();
-      this.maximum = this.allowedValues.max();
-    }
-
-    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
-    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
-    this.eventMouseMove = this.update.bindAsEventListener(this);
-
-    // Initialize handles in reverse (make sure first handle is active)
-    this.handles.each( function(h,i) {
-      i = slider.handles.length-1-i;
-      slider.setValue(parseFloat(
-        (slider.options.sliderValue instanceof Array ? 
-          slider.options.sliderValue[i] : slider.options.sliderValue) || 
-         slider.range.start), i);
-      Element.makePositioned(h); // fix IE
-      Event.observe(h, "mousedown", slider.eventMouseDown);
-    });
-    
-    Event.observe(this.track, "mousedown", this.eventMouseDown);
-    Event.observe(document, "mouseup", this.eventMouseUp);
-    Event.observe(document, "mousemove", this.eventMouseMove);
-    
-    this.initialized = true;
-  },
-  dispose: function() {
-    var slider = this;    
-    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
-    Event.stopObserving(document, "mouseup", this.eventMouseUp);
-    Event.stopObserving(document, "mousemove", this.eventMouseMove);
-    this.handles.each( function(h) {
-      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
-    });
-  },
-  setDisabled: function(){
-    this.disabled = true;
-  },
-  setEnabled: function(){
-    this.disabled = false;
-  },  
-  getNearestValue: function(value){
-    if(this.allowedValues){
-      if(value >= this.allowedValues.max()) return(this.allowedValues.max());
-      if(value <= this.allowedValues.min()) return(this.allowedValues.min());
-      
-      var offset = Math.abs(this.allowedValues[0] - value);
-      var newValue = this.allowedValues[0];
-      this.allowedValues.each( function(v) {
-        var currentOffset = Math.abs(v - value);
-        if(currentOffset <= offset){
-          newValue = v;
-          offset = currentOffset;
-        } 
-      });
-      return newValue;
-    }
-    if(value > this.range.end) return this.range.end;
-    if(value < this.range.start) return this.range.start;
-    return value;
-  },
-  setValue: function(sliderValue, handleIdx){
-    if(!this.active) {
-      this.activeHandleIdx = handleIdx || 0;
-      this.activeHandle    = this.handles[this.activeHandleIdx];
-      this.updateStyles();
-    }
-    handleIdx = handleIdx || this.activeHandleIdx || 0;
-    if(this.initialized && this.restricted) {
-      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
-        sliderValue = this.values[handleIdx-1];
-      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
-        sliderValue = this.values[handleIdx+1];
-    }
-    sliderValue = this.getNearestValue(sliderValue);
-    this.values[handleIdx] = sliderValue;
-    this.value = this.values[0]; // assure backwards compat
-    
-    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
-      this.translateToPx(sliderValue);
-    
-    this.drawSpans();
-    if(!this.dragging || !this.event) this.updateFinished();
-  },
-  setValueBy: function(delta, handleIdx) {
-    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
-      handleIdx || this.activeHandleIdx || 0);
-  },
-  translateToPx: function(value) {
-    return Math.round(
-      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
-      (value - this.range.start)) + "px";
-  },
-  translateToValue: function(offset) {
-    return ((offset/(this.trackLength-this.handleLength) * 
-      (this.range.end-this.range.start)) + this.range.start);
-  },
-  getRange: function(range) {
-    var v = this.values.sortBy(Prototype.K); 
-    range = range || 0;
-    return $R(v[range],v[range+1]);
-  },
-  minimumOffset: function(){
-    return(this.isVertical() ? this.alignY : this.alignX);
-  },
-  maximumOffset: function(){
-    return(this.isVertical() ? 
-      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
-        this.track.style.height.replace(/px$/,"")) - this.alignY : 
-      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
-        this.track.style.width.replace(/px$/,"")) - this.alignY);
-  },  
-  isVertical:  function(){
-    return (this.axis == 'vertical');
-  },
-  drawSpans: function() {
-    var slider = this;
-    if(this.spans)
-      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
-    if(this.options.startSpan)
-      this.setSpan(this.options.startSpan,
-        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
-    if(this.options.endSpan)
-      this.setSpan(this.options.endSpan, 
-        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
-  },
-  setSpan: function(span, range) {
-    if(this.isVertical()) {
-      span.style.top = this.translateToPx(range.start);
-      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
-    } else {
-      span.style.left = this.translateToPx(range.start);
-      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
-    }
-  },
-  updateStyles: function() {
-    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
-    Element.addClassName(this.activeHandle, 'selected');
-  },
-  startDrag: function(event) {
-    if(Event.isLeftClick(event)) {
-      if(!this.disabled){
-        this.active = true;
-        
-        var handle = Event.element(event);
-        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
-        var track = handle;
-        if(track==this.track) {
-          var offsets  = Position.cumulativeOffset(this.track); 
-          this.event = event;
-          this.setValue(this.translateToValue( 
-           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
-          ));
-          var offsets  = Position.cumulativeOffset(this.activeHandle);
-          this.offsetX = (pointer[0] - offsets[0]);
-          this.offsetY = (pointer[1] - offsets[1]);
-        } else {
-          // find the handle (prevents issues with Safari)
-          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
-            handle = handle.parentNode;
-            
-          if(this.handles.indexOf(handle)!=-1) {
-            this.activeHandle    = handle;
-            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
-            this.updateStyles();
-            
-            var offsets  = Position.cumulativeOffset(this.activeHandle);
-            this.offsetX = (pointer[0] - offsets[0]);
-            this.offsetY = (pointer[1] - offsets[1]);
-          }
-        }
-      }
-      Event.stop(event);
-    }
-  },
-  update: function(event) {
-   if(this.active) {
-      if(!this.dragging) this.dragging = true;
-      this.draw(event);
-      // fix AppleWebKit rendering
-      if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-      Event.stop(event);
-   }
-  },
-  draw: function(event) {
-    var pointer = [Event.pointerX(event), Event.pointerY(event)];
-    var offsets = Position.cumulativeOffset(this.track);
-    pointer[0] -= this.offsetX + offsets[0];
-    pointer[1] -= this.offsetY + offsets[1];
-    this.event = event;
-    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
-    if(this.initialized && this.options.onSlide)
-      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
-  },
-  endDrag: function(event) {
-    if(this.active && this.dragging) {
-      this.finishDrag(event, true);
-      Event.stop(event);
-    }
-    this.active = false;
-    this.dragging = false;
-  },  
-  finishDrag: function(event, success) {
-    this.active = false;
-    this.dragging = false;
-    this.updateFinished();
-  },
-  updateFinished: function() {
-    if(this.initialized && this.options.onChange) 
-      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
-    this.event = null;
-  }
-}/**
- * $Id: jxcore.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx Core
- *
- * Purpose: 
- * Implementation of core and base classes for Jx components.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/ 
-/**
- * Class: Jx
- * Jx is a global singleton object that contains the entire Jx library
- * within it.  All Jx functions, attributes and classes are accessed
- * through the global Jx object.  Jx should not create any other
- * global variables, if you discover that it does then please report
- * it as a bug
- */
- 
-/* LEAVE THIS SEMI-COLON, IT PREVENTS PROBLEMS WITH COMPRESSION */
-;
-
-/* firebug console supressor for IE/Safari/Opera */
-if (!("console" in window) || !("firebug" in console)) {
-    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
-    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
-
-    window.console = {};
-    for (var i = 0; i < names.length; ++i) {
-        window.console[names[i]] = function() {};
-    }
-}
-/* inspired by extjs, removes css image flicker and related problems in IE 6 */
-var ua = navigator.userAgent.toLowerCase();
-var isIE = ua.indexOf("msie") > -1,
-    isIE7 = ua.indexOf("msie 7") > -1;
-if(isIE && !isIE7) {
-    try {
-        document.execCommand("BackgroundImageCache", false, true);
-    } catch(e) {}
-}
-
-/* Setup global namespace
- * If jxcore is loaded by jx.js, then the namespace and baseURL are
- * already established
- */
-if (typeof Jx == 'undefined') {
-    var Jx = {};
-    /**
-     * Property: {Boolean} COMBINED_CSS
-     * controls whether Jx uses a single, combined CSS file or
-     * individual ones.  The combined version is used automatically
-     * if the combined or compressed version of Jx is used,
-     * otherwise separate ones are used.
-     */ 
-    Jx.COMBINED_CSS = true;
-    var aScripts = document.getElementsByTagName('SCRIPT');
-    for (var i=0; i<aScripts.length; i++) {
-        var s = aScripts[i].src;
-        //only check for lib/jx because we were loaded by 
-        var n = s.indexOf('lib/jx');
-        if (n != -1) {
-            /**
-             * Property: {String} baseURL
-             * This is the URL that Jx was loaded from, it is 
-             * automatically calculated from the script tag
-             * src property that included Jx.
-             */ 
-            Jx.baseURL = s.substring(0,n);
-            break;
-        }
-    }
-} 
-
-/**
- * Property: {Object} importRules
- *
- * an object containing a list of CSS files to be included
- * to make the loaded Jx components function correctly
- */
-Jx.importRules = {};
-/**
- * Property: {Object} importRules
- *
- * an object containing a list of CSS files to be included
- * to make the loaded Jx components function correctly
- */
-Jx.importRulesIE = {};
-
-/**
- * Method: addStyleSheet
- *
- * Individual components of Jx call this function to get their
- * style sheets imported at run time.
- *
- * Parameters:
- *
- *   styleSheet {String} the relative path to the CSS file (relative
- *              to <Jx.baseURL>).
- *
- *   ieOnly {Boolean} if true, then the style sheet is only loaded 
- *          if the browser is Internet Explorer.
- */
-Jx.addStyleSheet = function(styleSheet, ieOnly) { 
-    if (ieOnly) {
-        this.importRulesIE[styleSheet] = styleSheet; 
-    } else {
-        this.importRules[styleSheet] = styleSheet; 
-    }
-};
-
-/* everything needs reset.css */
-Jx.addStyleSheet('reset.css');
-
-/**
- * Method: applyPNGFilter
- *
- * Static method that applies the PNG Filter Hack for IE browsers
- * when showing 24bit PNG's.  Used automatically for img tags with
- * a class of png24.
- *
- * The filter is applied using a nifty feature of IE that allows javascript to
- * be executed as part of a CSS style rule - this ensures that the hack only
- * gets applied on IE browsers.
- *
- * Parameters:
- *
- *   object {Object} the object (img) to which the filter needs to be applied.
- */
-Jx.applyPNGFilter = function(o)  {
-   var t=Jx.baseURL + "images/a_pixel.png";
-   if( o.src != t ) {
-       var s=o.src;
-       o.src = t;
-       o.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";
-   }
-};
-
-Jx.imgQueue = [];   //The queue of images to be loaded
-Jx.imgLoaded = {};  //a hash table of images that have been loaded and cached
-Jx.imagesLoading = 0; //counter for number of concurrent image loads 
-
-/**
- * Method: addToImgQueue
- *
- * request that an image be set to a DOM IMG element src attribute.  This puts 
- * the image into a queue and there are private methods to manage that queue
- * and limit image loading to 2 at a time.
- */
-Jx.addToImgQueue = function(obj) {
-    if (Jx.imgLoaded[obj.src]) {
-        //if this image was already requested (i.e. it's in cache) just set it directly
-        obj.domElement.src = obj.src;
-    } else {
-        //otherwise stick it in te queue
-        Jx.imgQueue.push(obj);
-        Jx.imgLoaded[obj.src] = true;
-    }
-    //start the queue management process
-    Jx.checkImgQueue();
-};
-
-/**
- * Method: checkImgQueue
- *
- * An internal method that ensures no more than 2 images are loading at a time.
- */
-Jx.checkImgQueue = function() {
-    //console.log(this.imgQueue.length+":"+this.imagesLoading);
-    while (Jx.imagesLoading < 2 && Jx.imgQueue.length > 0) {
-        Jx.loadNextImg();
-    }
-};
-
-/**
- * Method: loadNextImg
- *
- * An internal method actually populate the DOM element with the image source.
- */
-Jx.loadNextImg = function() {
-    var obj = Jx.imgQueue.shift();
-    if (obj) {
-        ++Jx.imagesLoading;
-        obj.domElement.onload = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
-        obj.domElement.onerror = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
-        obj.domElement.src = obj.src;
-    }
-}; 
-
-
-/**
-  * Class: Jx.Listener
- *
- * Jx.Listener is a mix-in class that performs common listener functions
- * for objects that support listeners.  It is intended to be added to
- * existing classes using the following syntax:
- *
- * (code)
- * Object.extends( MyClass.prototype, Jx.Listener.prototype)
- * (end)
- *
- * The Jx.Listener class functions provide support for managing a list of
- * listeners (add, remove) and dispatching events to listeners (processEvent).
- */
-Jx.Listener = Class.create();
-Jx.Listener.prototype = {
-    /**
-     * Method: addListener
-     *
-     * add a listener to the provided list.
-     *
-     * Parameters:
-     *
-     *   list {Array} the array of listeners to add the listener to.
-     *
-     *   object {Object} the object to add as a listener.
-     */
-    addListener: function (list,obj) {list.push(obj);},
-    /**
-     * Method: removeListener
-     *
-     * remove a listener from the provided list.
-     *
-     * Parameters:
-     *
-     * list {Array} the array of listeners to remove the listener from.
-     *
-     * obj {Object} the object to remove as a listener.
-     */
-    removeListener: function(list,obj) {
-        for(var i=0;i<list.length;i++) {if (list[i] == obj) {list.splice(i,1); break;}}},
-    /**
-     * Method: processEvent
-     *
-     * call each listener with a given method and event.
-     *
-     * Parameters:
-     *
-     *   list {Array} the array of listeners to call.
-     *
-     *   fnName {String} the name of a function to call on each listener.
-     *
-     *   obj {Object} an object to pass to each listener.
-     */
-    processEvent: function(list,fnName,obj){list.each(function(o){if (o[fnName]) {o[fnName](obj);}});}
-};
-
-/**
- * Class: Jx.UniqueId
- *
- * Jx.UniqueId is used to assign unique ids to selected elements
- * This is used to solve a problem where multiple external html
- * fragments are loaded into the DOM via ajax at runtime.  It is
- * not always possible to ensure that every element has a unique
- * id.  This is not a problem if you are using id for CSS styling
- * but if you are using it to access elements using $() then
- * you may get unexpected results.
- *
- * Jx.UniqueId is a mix-in class.  Extend an existing class to
- * enable it to handle unique ids.  Register the ids that you
- * want to be unique and then get a reference to those objects
- * through the interface exposed by this class.
- *
- * The class retrieves the elements by id by walking a dom object
- * and retains references to each of the actual DOM objects
- * you have registered.
- */
-Jx.UniqueId = Class.create();
-Jx.UniqueId.prototype = {
-    /**
-     * Property: {Array} uniqueIdRefs
-     *
-     * an array of references obtained from by registering ids
-     */
-    uniqueIdRefs: null,
-    /**
-     * Method: initUniqueId
-     * 
-     * initialize the UniqueId object.  This must be called prior to
-     * calling the <registerIds> function.  Typically, it is called
-     * in the constructor of an object that includes Jx.UniqueId.
-     */
-    initUniqueId: function() { 
-        this.uniqueIdRefs = [];
-    },
-    /**
-     * Method: deregisterIds
-     *
-     * removes all registered ids
-     */
-    deregisterIds: function() {
-        this.uniqueIdRefs.length = 0;
-    },
-    /**
-     * Method: registerIds
-     *
-     * searches the domObj for each of the ids passed in and
-     * obtains a unique reference to them so that subsequent
-     * calls to <getObj> will return the right object.
-     *
-     * Parameters:
-     *
-     * aIds {Array} an array of strings containing ids of DOM elements
-     *      to register.
-     *
-     * domObj {Object} an HTML element reference to search for unique
-     *        ids within
-     */
-    registerIds: function (aIds, domObj) {
-        if (aIds.indexOf(domObj.id) != -1) {
-            this.uniqueIdRefs[domObj.id] = domObj;
-        }
-        for (var i=0; i<domObj.childNodes.length; i++) {
-            this.registerIds(aIds, domObj.childNodes[i]);
-        }
-    },
-    /**
-     * Method: getObj
-     *
-     * return an object by id if it was previously registered
-     *
-     * Parameters:
-     * 
-     * id {String} the original registered id to get the DOM object for
-     *
-     * Returns:
-     *
-     * {Object} returns an object or null if the requested id did not
-     * exist in the original DOM object or if the id was not registered.
-     */
-    getObj: function(id) {
-        return this.uniqueIdRefs[id] || null;
-    }
-};
-
-/**
- * Class: Jx.Action
- *
- * Jx.Action is a utility class that provides a mechanism to separate
- * the user interface code from the implementation code for a particular
- * piece of functionality.  A Jx.Action is used primarily as the basis for
- * clickable UI elements such as Jx.Button and Jx.MenuItem that need to
- * execute a particular function when the user clicks them.  The Jx.Action
- * includes a mechanism for controlling the state of the action, allowing
- * an application to enable or disable an action at any time.  A single
- * Jx.Action may be used with multiple buttons and menu items, allowing 
- * the application to easily keep various user interface elements
- * synchronized without having to explicitly maintain all of them.
- *
- * A new instance of Jx.Action is created by passing a function object
- * to the constructor.  The function object may be a function name or
- * the result of using the Prototype bind() function.
- *
- * For example:
- *
- * (code)
- * //Example 1:
- * //use a function reference directly
- * function myFunction() { alert('my function'); }
- * var action = new Jx.Action(myFunction);
- *
- * //Example 2:
- * //use a function bound to an object through bind()
- * var myClass = Class.create();
- * myClass.prototype = { 
- *   initialize: function() {this.x = 1;}, 
- *   getX: function() {alert(this.x); }
- * };
- *
- * var myInstance = new myClass();
- * var action = new Jx.Action(myInstance.getX.bind(myInstance));
- *
- * (end)
- *
- * To enable or disable a Jx.Action (and consequently update any associated
- * buttons or menu items), use the setEnabled([true|false]) method.
- *
- * For example:
- *
- * (code)
- * //disable an action
- * action.setEnabled(false);
- * (end)
- */
-Jx.Action = Class.create();
-Jx.Action.prototype = {
-    /**
-     * Property: {Array} pcl
-     * an array of property change listeners attached to this action
-     */
-    pcl: null,
-    /**
-     * Property: {Boolean} enabled
-     *
-     * whether the action (and its associated interface object) is
-     * currently enabled or not.  This is controlled through the
-     * setEnabled function
-     */
-    enabled : null,
-    /**
-     * Constructor: Jx.Action
-     * 
-     * construct a new instance of Jx.Action that invokes a function
-     * when activated
-     *
-     * Parameters: 
-     *
-     * f - {Function} the function that this action triggers
-     */
-    initialize: function(f) {
-        this.pcl = [];
-        this.enabled = true;
-        this.actionPerformed = f;
-    },
-    /**
-     * Method: addPropertyChangeListener
-     *
-     * add a property change listener to this action.  When the enabled
-     * state of the action changes, all property change listeners are
-     * notified through their propertyChanged method.
-     *
-     * Parameters: 
-     *
-     * obj - {Object} the object to notify of property changes
-     */
-    addPropertyChangeListener: function(obj){this.addListener(this.pcl, obj);},
-    /**
-     * Method: removePropertyChangeListener
-     *
-     * remove a property change listener from this action.
-     *
-     * Parameters: 
-     *
-     * obj - {Object} the property change listener to remove.
-     */
-    removePropertyChangeListener: function(obj) {
-        this.removeListener(this.pcl, obj);
-    },
-    /**
-     * Method: isEnabled
-     * 
-     * return whether the action is currently enabled or not.
-     *
-     * Return: {Boolean}
-     */
-    isEnabled: function() {return this.enabled;},
-    /**
-     * Method: setEnabled
-     *
-     * set the state of this action.
-     *
-     * Parameters: 
-     *
-     * b - {Boolean} a boolean value to set enabled state of this action to.
-     */
-    setEnabled: function(b){
-        /* prevent unnecessary propogation of propertyChanged */
-        if (this.enabled == b) {
-            return;
-        }
-        this.enabled = b;
-        this.processEvent(this.pcl,'propertyChanged',this);
-    },
-    /**
-     * Method: bindTo
-     *
-     * convenience function to bind an item to this action.  This
-     * adds the item as a property change listener to the action
-     * and adds the action as an ActionListener to the item.
-     *
-     * Parameters: 
-     *
-     * item - {Object} the object to bind the action to.
-     */
-    bindTo : function( item ) {
-        this.addPropertyChangeListener(item);
-        item.addActionListener(this);
-    },
-    /**
-     * Method: unbindFrom
-     *
-     * convenience function to undo a binding between an object and
-     * this action.
-     *
-     * Parameters: 
-     *
-     * item - {Object} the object to unbind from this action.
-     */
-    unbindFrom: function(item) {
-        this.removePropertyChangeListener(item);
-        item.removeActionListener(this);
-    },
-    /**
-     * Method: actionPerformed
-     *
-     * placeholder function to conform to the ActionListener interface.
-     *
-     * Parameters: 
-     *
-     * obj - {Object} the object that performed the action.
-     */
-    actionPerformed : function(obj) { alert('actionPerformed'); }
-};
-Object.extend(Jx.Action.prototype, Jx.Listener.prototype);
-
-/**
- * Class: Element
- *
- * Element is a global object provided by the prototype.js library.  The
- * functions documented here are extensions to the Element object provided
- * by Jx to make cross-browser compatibility easier to achieve.
- */
-Object.extend( Element, {
-    /**
-     * Method: getBoxSizing
-     *
-     * return the box sizing of an element, one of 'content-box' or 
-     *'border-box'.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to get the box sizing of.
-     *
-     * Return: {String} the box sizing of the element.
-     */
-    getBoxSizing : function(elem) {
-      var result = 'content-box';
-      elem = $(elem);
-      if (elem.currentStyle || window.opera) { 
-          var cm = document["compatMode"];
-          if (cm == "BackCompat" || cm == "QuirksMode") { 
-              result = 'border-box'; 
-          } else {
-              result = 'content-box'; 
-        }
-      } else {
-          if (arguments.length == 0) {
-              node = document.documentElement; 
-          }
-          var sizing = Element.getStyle(elem, "-moz-box-sizing");
-          if (!sizing) { 
-              sizing = Element.getStyle(elem, "box-sizing"); 
-          }
-          result = (sizing ? sizing : 'content-box');
-      }
-      return result;
-    },
-    /**
-     * Method: getContentBoxSize
-     *
-     * return the size of the content area of an element.  This is the size of
-     * the element less margins, padding, and borders.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to get the content size of.
-     *
-     * Return: {Object} an object with two properties, width and height, that
-     * are the size of the content area of the measured element.
-     */
-    getContentBoxSize : function(elem) {
-      elem = $(elem);
-      Element.toggleMeasurable(elem);
-      var w = elem.offsetWidth;
-      var h = elem.offsetHeight;
-      var padding = Element.getPaddingSize(elem);
-      var border = Element.getBorderSize(elem);
-      Element.toggleMeasurable(elem);
-      w = w - padding.left - padding.right - border.left - border.right;
-      h = h - padding.bottom - padding.top - border.bottom - border.top;
-      return {width: w, height: h};
-    },
-    /**
-     * Method: getBorderBoxSize
-     *
-     * return the size of the border area of an element.  This is the size of
-     * the element less margins.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to get the border sizing of.
-     *
-     * Return: {Object} an object with two properties, width and height, that
-     * are the size of the border area of the measured element.
-     */
-    getBorderBoxSize: function(elem) {
-      elem = $(elem);
-      Element.toggleMeasurable(elem);
-      var w = elem.offsetWidth;
-      var h = elem.offsetHeight;
-      Element.toggleMeasurable(elem);
-      return {width: w, height: h}; 
-    },
-    /**
-     * Method: setContentBoxSize
-     *
-     * set either or both of the width and height of an element to
-     * the provided size.  This function ensures that the content
-     * area of the element is the requested size and the resulting
-     * size of the element may be larger depending on padding and
-     * borders.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to set the content area of.
-     *
-     * size - {Object} an object with a width and/or height property that is the size to set
-     * the content area of the element to.
-     */
-    setContentBoxSize : function(elem, size) {
-        elem = $(elem);
-        if (Element.getBoxSizing(elem) == 'border-box') {
-            var padding = Element.getPaddingSize(elem);
-            var border = Element.getBorderSize(elem);
-            if (typeof size.width != 'undefined') {
-                var width = (size.width + padding.left + padding.right + border.left + border.right);
-                if (width < 0) {
-                    width = 0;
-                }
-                elem.style.width = width + 'px';
-            }
-            if (typeof size.height != 'undefined') {
-                var height = (size.height + padding.top + padding.bottom + border.top + border.bottom);
-                if (height < 0) {
-                    height = 0;
-                }
-                elem.style.height = height + 'px';
-            }
-        } else {
-            if (typeof size.width != 'undefined') {
-                elem.style.width = size.width + 'px';
-            }
-            if (typeof size.height != 'undefined') {
-                elem.style.height = size.height + 'px';
-            }
-        }
-    },
-    /**
-     * Method: setBorderBoxSize
-     *
-     * set either or both of the width and height of an element to
-     * the provided size.  This function ensures that the border
-     * size of the element is the requested size and the resulting
-     * content areaof the element may be larger depending on padding and
-     * borders.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to set the border size of.
-     *
-     * size - {Object} an object with a width and/or height property that is the size to set
-     * the content area of the element to.
-     */
-    setBorderBoxSize : function(elem, size) {
-      elem = $(elem);
-      if (Element.getBoxSizing(elem) == 'content-box') {
-        var padding = Element.getPaddingSize(elem);
-        var border = Element.getBorderSize(elem);
-        var margin = Element.getMarginSize(elem);
-        if (typeof size.width != 'undefined') {
-          var width = (size.width - padding.left - padding.right - border.left - border.right - margin.left - margin.right);
-          if (width < 0) {
-            width = 0;
-          }
-          elem.style.width = width + 'px';
-        }
-        if (typeof size.height != 'undefined') {
-          var height = (size.height - padding.top - padding.bottom - border.top - border.bottom - margin.top - margin.bottom);
-          if (height < 0) {
-            height = 0;
-          }
-          elem.style.height = height + 'px';
-        }
-      } else {
-        if (typeof size.width != 'undefined' && size.width >= 0) {
-          elem.style.width = size.width + 'px';
-        }
-        if (typeof size.height != 'undefined' && size.height >= 0) {
-          elem.style.height = size.height + 'px';
-        }
-      }
-    },
-    /**
-     * Method: getPaddingSize
-     *
-     * returns the padding for each edge of an element
-     *
-     * Parameters: 
-     *
-     * elem - {Object} The element to get the padding for.
-     *
-     * Return: {Object} an object with properties left, top, right and bottom
-     * that contain the associated padding values.
-     */
-    getPaddingSize : function (elem) {
-      elem = $(elem);
-      Element.toggleMeasurable(elem);
-      var l = Element.getNumber(Element.getStyle(elem, 'padding-left'));
-      var t = Element.getNumber(Element.getStyle(elem, 'padding-top'));
-      var r = Element.getNumber(Element.getStyle(elem, 'padding-right'));
-      var b = Element.getNumber(Element.getStyle(elem, 'padding-bottom'));
-      Element.toggleMeasurable(elem);
-      return {left:l, top:t, right: r, bottom: b};
-    },
-    /**
-     * Method: getBorderSize
-     *
-     * returns the border size for each edge of an element
-     *
-     * Parameters: 
-     *
-     * elem - {Object} The element to get the borders for.
-     *
-     * Return: {Object} an object with properties left, top, right and bottom
-     * that contain the associated border values.
-     */
-    getBorderSize : function(elem) {
-      elem = $(elem);
-      Element.toggleMeasurable(elem);
-      var l = Element.getNumber(Element.getStyle(elem, 'border-left-width'));
-      var t = Element.getNumber(Element.getStyle(elem, 'border-top-width'));
-      var r = Element.getNumber(Element.getStyle(elem, 'border-right-width'));
-      var b = Element.getNumber(Element.getStyle(elem, 'border-bottom-width'));
-      Element.toggleMeasurable(elem);
-      return {left:l, top:t, right: r, bottom: b};
-    },
-    /**
-     * Method: getMarginSize
-     *
-     * returns the margin size for each edge of an element
-     *
-     * Parameters: 
-     *
-     * elem - {Object} The element to get the margins for.
-     *
-     * Return: {Object} an object with properties left, top, right and bottom
-     * that contain the associated margin values.
-     */
-    getMarginSize : function(elem) {
-      elem = $(elem);
-      Element.toggleMeasurable(elem);
-      var l = Element.getNumber(Element.getStyle(elem, 'margin-left'));
-      var t = Element.getNumber(Element.getStyle(elem, 'margin-top'));
-      var r = Element.getNumber(Element.getStyle(elem, 'margin-right'));
-      var b = Element.getNumber(Element.getStyle(elem, 'margin-bottom'));
-      Element.toggleMeasurable(elem);
-      return {left:l, top:t, right: r, bottom: b};
-    },
-    /**
-     * Method: getNumber
-     *
-     * safely parse a number and return its integer value.  A NaN value 
-     * returns 0.  CSS size values are also parsed correctly.
-     *
-     * Parameters: 
-     *
-     * n - {Mixed} the string or object to parse.
-     *
-     * Return: {Integer} the integer value that the parameter represents
-     */
-    getNumber: function(n) {
-      var result = n==null||isNaN(parseInt(n))?0:parseInt(n);
-      return result;
-    },
-    /**
-     * Method: getPageDimensions
-     *
-     * return the dimensions of the browser client area.
-     *
-     * Return: {Object} an object containing a width and height property 
-     * that represent the width and height of the browser client area.
-     */
-    getPageDimensions: function() {
-        return {width: Element.getInsideWindowWidth(), height: Element.getInsideWindowHeight()};
-    },
-    /**
-     * Method: getInsideWindowWidth
-     *
-     * returns the width of the browser client area
-     *
-     * Return: {Integer} the width of the browser client area
-     */
-    getInsideWindowWidth: function() {
-        if (window.innerWidth) {
-            return window.innerWidth;
-        } else if (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) {
-            // measure the html element's clientWidth
-            return document.body.parentElement.clientWidth;
-        } else if (document.body && document.body.clientWidth) {
-            return document.body.clientWidth;
-        }
-        return 0; 
-    },
-    /**
-     * Method: getInsideWindowHeight
-     *
-     * returns the height of the browser client area
-     *
-     * Return: {Integer} the height of the browser client area
-     */
-    getInsideWindowHeight: function() {
-        if (window.innerHeight) {
-            return window.innerHeight;
-        } else if (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) {
-            // measure the html element's clientHeight
-            return document.body.parentElement.clientHeight;
-        } else if (document.body && document.body.clientHeight) {
-            return document.body.clientHeight;
-        }
-        return 0; 
-    },
-    /**
-     * Method: toggleMeasurable
-     *
-     * toggles an element's display style property so it can be
-     * measured.  If the element has display: none, it is
-     * changed to display: block and made temporarily visible
-     * so that it can be measured.  Calling this function
-     * a second time with the same element will revert the
-     * changes.  This allows an element to be measured in
-     * various ways.
-     *
-     * Parameters: 
-     *
-     * elem - {Object} the element to measure.
-     */
-    toggleMeasurable: function(elem) {
-        if (Element.getStyle(elem, 'display') == 'none') {
-            elem.old = {};
-            elem.old.display = elem.style.display;
-            elem.old.visibility = elem.style.visibility;
-            elem.old.position = elem.style.position;
-            elem.style.position = 'absolute';
-            elem.style.visibility = 'hidden';
-            elem.style.display = 'block';
-        } else {
-            if (elem.old) {
-                elem.style.display = elem.old.display;
-                elem.style.visibility = elem.old.visibility;
-                elem.style.position = elem.old.position;
-                elem.old = null;
-            }
-        }
-    }
-} );
-
-/**
- * Class: Jx.ContentLoader
- * 
- * ContentLoader is a mix-in class that provides a consistent
- * mechanism for other Jx controls to load content in one of
- * four different ways:
- *
- * o using an existing element, by id
- *
- * o using an existing element, by object reference
- *
- * o using an HTML string
- *
- * o using a URL to get the content remotely
- */
-Jx.ContentLoader = Class.create();
-Jx.ContentLoader.prototype = {
-    /**
-     * Property: bContentLoaded
-     *
-     * tracks the load state of the content, specifically useful
-     * in the case of remote content.
-     */ 
-    bContentLoaded: false,
-    /**
-     * Method: contentLoaded
-     * 
-     * callback function that handles remote content
-     *
-     * Parameters: 
-     *
-     * element - {Object} the element to put the content into
-     *
-     * options - {Object} the options that were passed to loadContent originally, only
-     * used to get the optional onContentLoaded callback function.
-     *
-     * r - {XmlHttpRequest} the XmlHttpRequest object that has the content.
-     */
-    contentLoaded: function(element, options, r) { 
-        element.innerHTML = r.responseText;
-        this.bContentLoaded = true;
-        if (options.onContentLoaded) {
-            options.onContentLoaded();
-        }
-    },
-    /**
-     * Method: contentLoadFailed
-     * 
-     * callback function that handles failure to load remote content
-     *
-     * Parameters: 
-     *
-     * options - {Object} the options that were passed to loadContent originally, only
-     * used to get the optional onContentLoadedFailed callback function.
-     *
-     * r - {XmlHttpRequest} the XmlHttpRequest object that has the failure code
-     */
-    contentLoadFailed: function(options, r) {
-        this.bContentLoaded = false;
-        if (options.onContentLoadFailed) {
-            options.onContentLoadFailed();
-        }
-    },
-    /**
-     * Method: loadContent
-     *
-     * triggers loading of content based on parameters passed in the
-     * options parameter.  The options parameter can have the following
-     * attributes:
-     *
-     * Parameters: 
-     * element - {Object} the element to insert the content into
-     * options - {Object} an object containing the attributes indicating what 
-     * content to load.
-     *
-     * Options:
-     * content - {HTMLElement} an HTML element that becomes the content
-     * contentID - {String} the id of an element to use as the content
-     * contentURL - {String} URL to get the content remotely
-     * contentHTML - {String} some HTML to use as the innerHTML of the content
-     *      area.
-     * onContentLoaded - {Function} a function to call when the content is 
-     *      loaded.
-     * onContentLoadFailed - a function object that is called if the content
-     *      fails to load, primarily useful when using the contentURL method of
-     *      loading content.
-     */     
-    loadContent: function(element, options) {
-        options = options || {};
-        element = $(element);
-        if (options.content) {
-            element.appendChild(options.content);
-            this.bContentLoaded = true;
-        } else if (options.contentID) {
-            var c = $(options.contentID);
-            if (c) {
-                element.appendChild(c);
-                this.bContentLoaded = true;                
-            }
-        } else if (options.contentURL) {
-            this.bContentLoaded = false;
-            var ts = '';//'ts=' + (new Date()).getTime();
-            var a = new Ajax.Request( options.contentURL, 
-                Object.extend({method:'get',
-                               onSuccess:this.contentLoaded.bind(this, element, options), 
-                               onFailure: this.contentLoadFailed.bind(this, options),
-                               requestHeaders: ['If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT'],
-                               parameters: ts}));
-        } else if (options.contentHTML) {
-            element.innerHTML = options.contentHTML;
-            this.bContentLoaded = true;
-        } else {
-            this.bContentLoaded = true;
-        }
-        if (this.bContentLoaded && options.onContentLoaded) {
-            options.onContentLoaded();
-        }
-    }
-};/**
- * $Id: jxbutton.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Button
- *
- * Purpose: 
- * Implementation of a generic button widget and several
- * useful subclasses.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-/**
- * Class: Jx.Button
- *
- * Jx.Button creates a clickable element in the application that is hooked
- * to an instance of Jx.Action.  When the button is clicked, it activates
- * its associated Jx.Action instance.  When the Jx.Action associated with
- * the button is enabled or disabled, the Jx.Button updates its visual
- * appearance to reflect the current state of the Jx.Action.
- *
- * Visually, a Jx.Button consists of an <A> tag that may contain either
- * an image, a label, or both (the label appears to the right of the button
- * if both are present).  The default styles for Jx.Button expect the
- * image to be 16 x 16 pixels, with a padding of 4px and a border of 1px
- * which results in an element that is 26 pixels high.  The width of the
- * button automatically accomodates the image and label as required.
- *
- * When you construct a new instance of Jx.Button, the button does not
- * automatically get inserted into the application.  Typically a button
- * is used as part of building another capability such as a Jx.Toolbar.
- * However, if you want to manually insert the button into your
- * application, you may use the domObj property of the Jx.Button instance.
- * In this case, you will use one of the DOM manipulation functions such
- * as appendChild, and pass button.domObj.  For example:
- *
- * (code)
- * var button = new Jx.Button(myAction, options);
- * var li = $('myListItem'); //obtain a reference to a DOM element
- * li.appendChild(button.domObj);
- * (end)
- *
- * To use a Jx.Button in an application, you must first create an instance
- * of Jx.Action and then pass it as the first parameter to the Jx.Button
- * constructor.  The second argument to a Jx.Button constructor is an options 
- * object allows configuring the button.
- *
- * (code)
- * Example:
- * function myFunc() { alert('you clicked me'); }
- * var action = new Jx.Action(myFunc);
- * var options = {
- *     imgPath: 'images/mybutton.png',
- *     tooltip: 'click me!',
- *     label: 'click me'
- * }
- * var button = new Jx.Button(action, options);
- * (end)
- */
- 
-Jx.addStyleSheet('button/button.css');
-
-Jx.Button = Class.create();
-Object.extend(Jx.Button.prototype, Jx.Listener.prototype);
-Object.extend(Jx.Button.prototype, {
-    /**
-     * Property: {Array} al
-     * an array of action listeners that are attached to the button.
-     */
-    al: null,
-    /**
-     * Property: {Object} domObj
-     * the HTML element that is inserted into the DOM for this button
-     */
-    domObj: null,
-    /**
-     * Property: {Boolean} enabled
-     * whether the button is enabled or not.  This is controlled by
-     * the Action object that the button is associated with.
-     */
-    enabled:null,
-    /**
-     * Constructor: Jx.Button
-     * create a new button.
-     *
-     * Parameters:
-     * action - {Object} the action to trigger for this button.
-     * options - {Object} an object containing optional properties for this
-     * button as below.
-     *
-     * Options:
-     * image - optional.  A string value that is the url to load the image to
-     *      display in this button.  The default styles size this image to 16 x 16.
-     *      If not provided, then the button will have no icon.
-     * tooltip - optional.  A string value to use as the alt/title attribute of
-     *      the <A> tag that wraps the button, resulting in a tooltip that appears 
-     *      when the user hovers the mouse over a button in most browsers.  If 
-     *      not provided, the button will have no tooltip.
-     * label - optional.  A string value that is used as a label on the button.
-     * disabledClass - optional.  A string value that is the name of a CSS class
-     *      to put on the <A> tag if the button is in a disabled state. If not 
-     *      provided, the default class jxDisabled is used. You may provide 
-     *      your own class or override jxDisabled.
-     * imgClass - optional.  A string value that is the name of a CSS class to
-     *      put on the <IMG> element.  The default value is jxButtonIcon.
-     */
-    initialize : function( action, options ) {
-        options = options || {};
-        this.al = [];
-        this.action = action; //TODO move action into options
-        
-        var imgPath = (options.imgPath || options.image) || '';
-        var tooltip = options.tooltip || '';
-        var label = options.label || '';
-        this.disabledClass = options.disabledClass || 'jxDisabled';
-        
-        this.domA = document.createElement('a');
-        this.domA.className = 'jxButton';
-        this.domA.href='javascript:void(0)'; //make hover effects work in IE
-        this.domA.onclick = this.onclick.bindAsEventListener(this);
-        this.domA.title = tooltip;
-        this.domA.alt = tooltip;
-        
-        var span = document.createElement('span');
-        span.className = 'jxButtonSpan';
-        this.domA.appendChild(span);
-        
-        
-        // if (imgPath != '') {
-        //             this.domImg = document.createElement('span');
-        //             this.domImg.className = 'jxButtonIcon';
-        //             if (options.imageClass && options.imageClass != '') {
-        //                 Element.addClassName(this.domImg, options.imageClass);
-        //             }
-        //             this.domImg.style.backgroundImage = "url("+imgPath+")";
-        //             this.domImg.innerHTML = '&nbsp;&nbsp;';
-        //             span.appendChild(this.domImg);
-        //         }
-        
-        this.domLabel = document.createElement('span');
-        this.domLabel.className = 'jxButtonContent';
-        //this.domLabel.className = label != '' ? 'jxButtonLabel' : ''; //jxButtonLabel jxButtonEmptyLabel';
-        this.domLabel.innerHTML = label != '' ? label : '&nbsp;';
-        span.appendChild(this.domLabel);
-
-        if (label != '') {
-            Element.addClassName(this.domLabel, 'jxButtonLabel');
-        }
-        
-        if (imgPath != '') {
-            Element.addClassName(this.domLabel, 'jxButtonIcon');
-            this.domLabel.style.backgroundImage = "url("+imgPath+")";
-        }
-        
-        /* if this is an action button, then hook to the action */
-        if (this.action) {
-            this.action.bindTo(this);
-            this.propertyChanged(this.action);            
-        }
-        
-        this.domObj = document.createElement('div');
-        this.domObj.className = 'jxButtonContainer';
-        this.domObj.appendChild(this.domA);
-        
-        if (options.halign && options.halign == 'left') {
-                Element.addClassName(this.domObj, 'jxButtonContentLeft');                
-        }
-        if (options.valign && options.valign == 'top') {
-            Element.addClassName(this.domObj, 'jxButtonContentTop');
-        }
-    },
-    /**
-     * Method: onclick
-     * triggered when the user clicks the button, processes the
-     * actionPerformed event
-     */
-    onclick : function() {
-        if (this.enabled) {
-            this.processEvent(this.al, 'actionPerformed', this);
-        }
-        return false;
-    },
-    /**
-     * Method: addActionListener
-     * add an action listener to the button
-     *
-     * Parameters: 
-     * obj - {Object} the object to add as an action listener
-     */
-    addActionListener: function(obj) { 
-        this.addListener(this.al,obj); 
-    },
-    /**
-     * Method: removeActionListener
-     * remove an action listener from the button
-     *
-     * Parameters: 
-     * obj - {Object} the object to remove.
-     */
-    removeActionListener : function(obj) { 
-        this.removeListener(this.al, obj);
-    },
-    /**
-     * Method: propertyChanged
-     * implements the PropertyChangeListener interface
-     * for handling the enabled state changing on the action
-     * associated with this button
-     *
-     * Parameters:
-     * obj - {Object} the action that is changing state
-     */
-    propertyChanged: function(obj) {
-        this.enabled = obj.isEnabled();
-        if (this.enabled) {
-            Element.removeClassName( this.domObj, this.disabledClass );
-        } else {
-            Element.addClassName( this.domObj, this.disabledClass );
-        }
-    },
-    /**
-     * Method: setImage
-     * set the image of this button to a new image URL
-     *
-     * Parameters:
-     * path - {String} the new url to use as the image for this button
-     */
-    setImage: function(path) {
-        if (this.domImg) {
-            this.domImg.src = path;
-        }
-    },
-    /**
-     * Method: setLabel
-     * 
-     * sets the text of the button.  Only works if a label was supplied
-     * when the button was constructed
-     *
-     * Parametera: 
-     *
-     * label - {String} the new label for the button
-     */
-    setLabel: function(label) {
-        if (this.domLabel) {
-            this.domLabel.innerHTML = label;
-        }
-    },
-    /**
-     * Method: setTooltip
-     * sets the tooltip displayed by the button
-     *
-     * Parameters: 
-     * tooltip - {String} the new tooltip
-     */
-    setTooltip: function(tooltip) {
-        if (this.domImg) {
-            this.domImg.title = tooltip;
-            this.domImg.alt = tooltip;
-        }
-    }
-} );
-
-/**
- * Class: Jx.Button.Flyout
- *
- * Flyout buttons expose a panel when the user clicks the button.  The
- * panel can have arbitrary content.
- *
- * The button itself does not trigger an external action.  You must provide
- * any necessary code to hook up elements in the panel to your application.
- */
-Jx.Button.Flyout = Class.create();
-Object.extend(Jx.Button.Flyout.prototype, Jx.Button.prototype);
-Object.extend(Jx.Button.Flyout.prototype, Jx.ContentLoader.prototype);
-Object.extend(Jx.Button.Flyout.prototype, {
-    /**
-     * Property: content
-     * {HTMLElement} a reference to the DOM node that contains the flyout 
-     * content
-     */
-    content: null,
-    /**
-     * Constructor: Jx.Button.Flyout
-     * construct a new instance of a flyout button.  The single options
-     * argument takes the same parameters as <Jx.Button.initialize> plus
-     * content loading options as per <Jx.ContentLoader>.
-     *
-     * Parameters: 
-     * options - {Object} an options object used to initialize the button.
-     * See <Jx.Button::Jx.Button>
-     */
-    initialize: function(options) {
-        options = options || {};
-        var a = new Jx.Action(this.show.bind(this));
-        Jx.Button.prototype.initialize.apply(this, [a, options]);
-        Element.addClassName(this.domA, 'jxButtonFlyout');
-        
-        /* iframe shim to prevent scrollbars and 
-           inputs from showing through the menu */
-        this.iframe = document.createElement('iframe');
-        this.iframe.className = 'jxMenuShim';
-        this.iframe.scrolling = 'no';
-        this.iframe.frameborder = 0;
-        
-        this.content = document.createElement('div');
-        Element.addClassName(this.content, 'jxFlyout');
-        this.loadContent(this.content, options);
-        this.domObj.appendChild(this.content);
-        this.content.style.display = 'none';
-        
-        this.keypressWatcher = this.keypressHandler.bindAsEventListener(this);
-        this.hideWatcher = this.clickHandler.bindAsEventListener(this);
-    },
-    
-    /**
-     * Method: show
-     * Show the flyout content
-     */
-    show: function() {
-        if (!window.opera && !this.iframe.parentNode) {
-            this.content.appendChild(this.iframe);
-        }
-        this.content.style.display = 'block';
-        Event.observe(window, 'keypress', this.keypressWatcher);
-        Event.observe(document, 'click', this.hideWatcher);
-    },
-    
-    /**
-     * Method: hide
-     * Hide the flyout content
-     */
-    hide: function() {
-        this.content.style.display = 'none';
-        Event.stopObserving(window, 'keypress', this.keypressWatcher);    
-        Event.stopObserving(document, 'click', this.hideWatcher);
-    },
-    /**
-     * Method: clickHandler
-     * hide flyout if the user clicks outside of the flyout 
-     */
-    clickHandler: function(e) {
-        var elm = Event.element(e);
-        if (!Element.descendantOf(elm, this.domObj.parentNode)) {
-            this.hide();
-        }
-    },
-    /**
-     * Method: keypressHandler
-     * hide flyout if the user presses the ESC key 
-     */
-    keypressHandler: function(e) {
-        var charCode=(e.charCode)?e.charCode:e.keyCode;
-        if (charCode == Event.KEY_ESC) {
-            this.hide();
-        }
-    }
-});
-
-/**
- * Class: Jx.Button.Multi
- * 
- * Multi buttons are used to contain multiple buttons in a drop down list
- * where only one button is actually visible and clickable in the interface.
- * 
- * When the user clicks the active button, it performs its normal action.
- * The user may also click a drop-down arrow to the right of the button and
- * access the full list of buttons.  Clicking a button in the list causes
- * that button to replace the active button in the toolbar and performs
- * the button's regular action.
- *
- * Other buttons can be added to the Multi button using the <add> function.
- */
-Jx.Button.Multi = Class.create();
-Jx.Button.Multi.prototype = {
-    /**
-     * Property: {<Jx.Button>} activeButton
-     * the currently selected button
-     */
-    activeButton: null,
-    /**
-     * Property: {Array} buttons
-     * an array of all available buttons
-     */
-    buttons: null,
-    /**
-     * Constructor: Jx.Button.Multi
-     * construct a new instance of Jx.Button.Multi.
-     */
-    initialize: function() {
-        this.buttons = [];
-        this.content = document.createElement('div');
-        this.tb = new Jx.Toolbar(this.content, 'right');
-        this.flyout = new Jx.Button.Flyout({content: this.content, label: '&nbsp;'});
-        Element.addClassName(this.flyout.domObj.firstChild, 'jxButtonMulti');
-        
-        this.domObj = document.createElement('div');
-        //this.domObj.className = 'jxButtonMulti';
-        this.buttonContainer = document.createElement('div');
-        this.buttonContainer.className = 'jxButtonMultiContainer';
-        this.domObj.appendChild(this.buttonContainer);
-        this.domObj.appendChild(this.flyout.domObj);
-    },
-    /**
-     * Method: add
-     * adds one or more buttons to the Multi button.  The first button
-     * added becomes the active button initialize.  This function 
-     * takes a variable number of arguments, each of which is expected
-     * to be an instance of <Jx.Button>.
-     *
-     * Parameters: 
-     * button - {<Jx.Button>} a <Jx.Button> instance, may be repeated in the parameter list
-     */
-    add: function() {
-        for (var i=0; i<arguments.length; i++) {
-            var theButton = arguments[i];
-            var action = new Jx.Action(this.setButton.bind(this, theButton));
-            var button = new Jx.Button(action, {});
-            var click = button.domA.onclick;
-            button.domObj = theButton.domObj.cloneNode(true);
-            button.domObj.onclick = click;
-            this.tb.add(button);
-            if (!this.activeButton) {
-                this.buttonContainer.appendChild(theButton.domObj);
-                this.activeButton = theButton;
-            }
-        }
-    },
-    /**
-     * Method: setActiveButton
-     * update the menu item to be the requested button.
-     *
-     * Parameters: 
-     * button - {<Jx.Button>} a <Jx.Button> instance that was added to this multi button.
-     */
-    setActiveButton: function(button) {
-        while(this.buttonContainer.childNodes.length > 0) {
-            this.buttonContainer.removeChild(this.buttonContainer.firstChild);
-        }
-        this.buttonContainer.appendChild(button.domObj);
-    },
-    /**
-     * Method: setButton
-     * update the active button in the menu item, trigger the button's action
-     * and hide the flyout that contains the buttons.
-     *
-     * Parameters: 
-     * button - {<Jx.Button>} The button to set as the active button
-     */
-    setButton: function(button) {
-        this.setActiveButton(button);
-        button.onclick();
-        this.flyout.hide();
-    }
-};
-
-/**
- * Class: Jx.Button.Picker
- * 
- * A Picker button allows the user to choose an item from a list of items.
- * The items can be any HTML element.  The chosen item is placed into the 
- * menu item.
- */
-Jx.Button.Picker = Class.create();
-Object.extend(Jx.Button.Picker.prototype, Jx.Button.Flyout.prototype);
-Object.extend(Jx.Button.Picker.prototype, {
-    /**
-     * Property: {HTMLElement} ul
-     * the UL element that contains the items to pick from
-     */
-    ul: null,
-    /**
-     * Property {HTMLElement} selectedItem
-     * the currently selected item
-     */
-    selectedItem: null,
-    /**
-     * Constructor: Jx.Button.Picker
-     * construct a new instance of <Jx.Button.Picker>
-     */
-    initialize: function() {
-        Jx.Button.Flyout.prototype.initialize.apply(this, arguments);
-        this.ul = document.createElement('ul');
-        this.content.appendChild(this.ul);
-        Element.removeClassName(this.domLabel, 'jxButtonEmptyLabel');
-    },
-    /**
-     * Method: add
-     * adds one or more items to the picker, passed as separate arguments.
-     *
-     * Parameters: 
-     * item - {Object} can be present one or more times in the argument list.  The item
-     * to be added can be a Jx object with a domObj property, a string,
-     * or an HTML element reference.
-     */
-    add: function() {
-        for (var i=0; i<arguments.length; i++) {
-            var thing = arguments[i];
-            if (thing.domObj) {
-                thing = thing.domObj;
-            }
-            var li = document.createElement('li');
-            var a = document.createElement('a');
-            
-            li.appendChild(a);
-            if (typeof(thing) == 'string') {
-                a.innerHTML = thing;
-            } else {
-                a.appendChild(thing);
-            }
-            this.ul.appendChild(li);
-            
-            if (!this.selectedItem) {
-                this.updateButton(a);
-            }
-        }
-    },
-    /**
-     * Method: clickHandler
-     * handle the user selecting an item in the list
-     *
-     * Parameters: 
-     * e - {Event} the event object associated with the click event
-     */
-    clickHandler: function(e) {
-        var elm = Event.element(e);
-        if (!Element.descendantOf(elm, this.domObj.parentNode)) {
-            this.hide();
-            return;
-        }
-        var a = Event.findElement(e, 'A');
-        if (a && Element.descendantOf(a, this.ul)) {
-            this.updateButton(a);
-            this.hide();
-        }
-    },
-    /**
-     * Method: updateButton
-     * updates the button to contain the picked item
-     *
-     * Parameters: 
-     * a - {HTMLElement} the A tag that the user clicked on
-     */
-    updateButton: function(a) {
-        while(this.domLabel.childNodes.length > 0) {
-            this.domLabel.removeChild(this.domLabel.firstChild);
-        }
-        this.domLabel.appendChild(a.firstChild.cloneNode(true));
-        this.selectedItem = a.firstChild;
-    }
-    
-});/**
- * $Id: jxcolor.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Color
- *
- * Purpose: 
- * Implementation of a color selection panel.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
- 
-Jx.addStyleSheet('color/color.css');
-
-/**
- * Class: Jx.ColorPanel
- *
- * A Jx.ColorPanel presents a user interface for selecting colors.  Currently,
- * the user can either enter a HEX colour value or select from a palette of
- * web-safe colours.  The user can also enter an opacity value.
- *
- * A Jx.ColorPanel can be embedded anywhere in a web page by appending its
- * <Jx.ColorPanel.domObj> property to an HTML element.  However, a
- * a Jx.Button subclass  is provided ( <Jx.Button.Color> ) that embeds a
- * colour panel inside a button for easy use in toolbars.
- *
- * Colour changes are propogated via a colorChanged listener pattern.  To
- * be notified of changes in a Jx.ColorPanel, register a color change
- * listener that implements a colorChanged method.  For instance:
- *
- * (code)
- * var colorChangeListener = {
- * colorChanged: function(colorPanel) {
- *     alert('the color changed to: ' + colorPanel.color);
- *   }
- * }
- *
- * var colorPanel = new Jx.ColorPanel();
- * colorPanel.addColorChangeListener(colorChangeListener);
- *
- * document.getElementsByTagName('BODY')[0].appendChild(colorPanel.domObj);
- * (end)
- */
-Jx.ColorPanel = Class.create();
-
-Jx.ColorPanel.prototype = {
-    /**
-     * Property: {HTMLElement} domObj
-     * the HTML element representing the color panel
-     */
-    domObj: null,
-    /**
-     * Property {String} color
-     * the currently selected colour, in hex format
-     */
-    color: null,
-    /**
-     * Property: {Float} alpha
-     * the current alpha value, between 0 (transparent) and 1 (opaque)
-     */
-    alpha: null,
-    /**
-     * Property: {Array} ccl
-     * color change property listeners
-     */
-    ccl: null,
-    /**
-     * Property: {Array} hexColors
-     * an array of valid hex values that are used to build a web-safe
-     * palette
-     */
-    hexColors: ['00', '33', '66', '99', 'CC', 'FF'],
-    /**
-     * Constructor: Jx.ColorPanel
-     * initialize a new instance of Jx.ColorPanel
-     *
-     * Parameters: 
-     * options - {Object} an object containing a variable list of optional initialization
-     * parameters.
-     *
-     * Options:
-     * color - a colour to initialize the panel with, defaults to #000000
-     *         (black) if not specified.
-     * alpha - an alpha value to initialize the panel with, defaults to 1
-     *         (opaque) if not specified.
-     */
-    initialize: function(options) {
-        
-        options = options || {};
-        this.keypressWatcher = this.keypressHandler.bind(this);
-        
-        this.ccl = [];
-        
-        this.color = options.color || '#000000';
-        this.alpha = options.alpha || 1;
-        
-        this.domObj = document.createElement('div');
-        this.domObj.className = 'jxColorPanel';
-        
-        var top = document.createElement('div');
-        top.className = 'jxColorBar';
-        
-        var d = document.createElement('div');
-        d.className = 'jxColorPreview';
-        
-        // var img = document.createElement('img');
-        // img.src = Jx.baseURL + '/color/grid.png';        
-        // d.appendChild(img);
-        
-        this.selectedSwatch = document.createElement('div');
-        d.appendChild(this.selectedSwatch);
-        
-        top.appendChild(d);
-        
-        this.colorInputLabel = document.createElement('label');
-        this.colorInputLabel.className = 'jxColorLabel';
-        this.colorInputLabel.innerHTML = '#';
-        top.appendChild(this.colorInputLabel);
-        
-        this.colorInput = document.createElement('input');
-        this.colorInput.className = 'jxHexInput';
-        this.colorInput.type = 'text';
-        this.colorInput.maxLength = 6;
-        Event.observe(this.colorInput, 'keyup', this.colorChanged.bind(this));
-        Event.observe(this.colorInput, 'blur', this.colorChanged.bind(this));
-        Event.observe(this.colorInput, 'change', this.colorChanged.bind(this));
-        top.appendChild(this.colorInput);
-        
-        this.alphaLabel = document.createElement('label');
-        this.alphaLabel.className = 'jxAlphaLabel';
-        this.alphaLabel.innerHTML = 'alpha (%)';
-        top.appendChild(this.alphaLabel);
-        
-        this.alphaInput = document.createElement('input');
-        this.alphaInput.className = 'jxAlphaInput';
-        this.alphaInput.type = 'text';
-        this.alphaInput.maxLength = 3;
-        Event.observe(this.alphaInput, 'keyup', this.alphaChanged.bind(this));
-        top.appendChild(this.alphaInput);
-        
-        this.domObj.appendChild(top);
-        
-        var a = document.createElement('a');
-        a.href="javascript:void(0)";
-        a.className = 'jxColorClose';
-        a.alt = 'Close';
-        a.title = 'Close';
-        Event.observe(a, 'click', this.hide.bind(this));
-        
-        img = document.createElement('img');
-        img.className = 'png24';
-        img.src = Jx.baseURL + 'images/close.png';
-        a.appendChild(img);
-        
-        this.domObj.appendChild(a);
-        
-        d = document.createElement('div');
-        d.className = 'jxClearer';
-        this.domObj.appendChild(d);
-        
-        var swatchClick = this.swatchClick.bindAsEventListener(this);
-        var swatchOver = this.swatchOver.bindAsEventListener(this);
-        
-        var table = document.createElement('table');
-        table.className = 'jxColorGrid';
-        var tbody = document.createElement('tbody');
-        table.appendChild(tbody);
-        for (var i=0; i<12; i++) {
-            var tr = document.createElement('tr');
-            for (var j=-3; j<18; j++) {
-                var bSkip = false;
-                var r, g, b;
-                /* hacky approach to building first three columns
-                 * because I couldn't find a good way to do it
-                 * programmatically
-                 */
-                
-                if (j < 0) {
-                    if (j == -3 || j == -1) {
-                        r = g = b = 0;
-                        bSkip = true;
-                    } else {
-                        if (i<6) {
-                            r = g = b = i;
-                        } else {
-                            if (i == 6) {
-                                r = 5; g = 0; b = 0;
-                            } else if (i == 7) {
-                                r = 0; g = 5; b = 0;
-                            } else if (i == 8) {
-                                r = 0; g = 0; b = 5;
-                            } else if (i == 9) {
-                                r = 5; g = 5; b = 0;
-                            } else if (i == 10) {
-                                r = 0; g = 5; b = 5;
-                            } else if (i == 11) {
-                                r = 5; g = 0; b = 5;
-                            }
-                        }
-                    }
-                } else {
-                    /* remainder of the columns are built
-                     * based on the current row/column
-                     */
-                    r = parseInt(i/6)*3 + parseInt(j/6);
-                    g = j%6;
-                    b = i%6;
-                }
-                var bgColor = '#'+this.hexColors[r]+this.hexColors[g]+this.hexColors[b];
-                
-                var td = document.createElement('td');
-                if (!bSkip) {
-                    td.style.backgroundColor = bgColor;
-
-                    var a = document.createElement('a');
-                    if ((r > 2 && g > 2) || (r > 2 && b > 2) || (g > 2 && b > 2)) {
-                        a.className = 'colorSwatch borderBlack';
-                    } else {
-                        a.className = 'colorSwatch borderWhite';
-                    }
-                    a.href = '#';
-                    a.title = bgColor;
-                    a.alt = bgColor;
-                    a.swatchColor = bgColor;
-                    
-                    a.onmouseover = swatchOver;
-                    a.onclick = swatchClick;
-
-                    td.appendChild(a);
-                } else {
-                    var span = document.createElement('span');
-                    td.className = 'emptyCell';
-                    td.appendChild(span);
-                }
-                tr.appendChild(td);
-            }
-            tbody.appendChild(tr);
-        }
-
-        this.domObj.appendChild(table);
-        
-        var d = document.createElement('div');
-        d.className = 'jxColorPreview';
-        this.previewSwatch = document.createElement('div');
-        d.appendChild(this.previewSwatch);
-        this.previewSwatch.style.backgroundColor = this.color;
-        this.domObj.appendChild(d);
-        
-        this.previewLabel = document.createElement('label');
-        this.previewLabel.className = 'jxColorLabel';
-        this.previewLabel.innerHTML = this.color;
-        this.domObj.appendChild(this.previewLabel);
-        
-        d = document.createElement('div');
-        d.className = 'jxClearer';
-        this.domObj.appendChild(d);
-        
-        this.updateSelected();
-    },
-    
-    /**
-     * Method: swatchOver
-     * handle the mouse moving over a colour swatch by updating the preview
-     *
-     * Parameters: 
-     * e - {Event} the mousemove event object
-     */
-    swatchOver: function(e) {
-        var a = Event.element(e);
-        
-        this.previewSwatch.style.backgroundColor = a.swatchColor;
-        this.previewLabel.innerHTML = a.swatchColor;
-    },
-    
-    /**
-     * Method: swatchClick
-     * handle mouse click on a swatch by updating the color and hiding the
-     * panel.
-     *
-     * Parameters: 
-     * e - {Event} the mouseclick event object
-     */
-    swatchClick: function(e) {
-        var a = Event.element(e);
-        
-        this.color = a.swatchColor;
-        this.updateSelected();
-        this.hide();
-    },
-    
-    /**
-     * Method: colorChanged
-     * handle the user entering a new colour value manually by updating the
-     * selected colour if the entered value is valid HEX.
-     */
-    colorChanged: function() {
-        var color = this.colorInput.value;
-        if (color.substring(0,1) == '#') {
-            color = color.substring(1);
-        }
-        if (color.toLowerCase().match(/^[0-9a-f]{6}$/)) {
-            this.color = '#' +color.toUpperCase();
-            this.updateSelected();
-        }
-    },
-    
-    /**
-     * Method: alphaChanged
-     * handle the user entering a new alpha value manually by updating the
-     * selected alpha if the entered value is valid alpha (0-100).
-     */
-    alphaChanged: function() {
-        var alpha = this.alphaInput.value;
-        if (alpha.match(/^[0-9]{1,3}$/)) {
-            this.alpha = parseFloat(alpha/100);
-            this.updateSelected();
-        }
-    },
-    
-    /**
-     * Method: setColor
-     * set the colour represented by this colour panel
-     *
-     * Parameters: 
-     * color - {String} the new hex color value
-     */
-    setColor: function( color ) {
-        this.colorInput.value = color;
-        this.colorChanged();
-    },
-    
-    /**
-     * Method: setAlpha
-     * set the alpha represented by this colour panel
-     *
-     * Parameters: 
-     * alpha - {Integer} the new alpha value (between 0 and 100)
-     */
-    setAlpha: function( alpha ) {
-        this.alphaInput.value = alpha;
-        this.alphaChanged();
-    },
-    
-    /**
-     * Method: updateSelected
-     * update the colour panel user interface based on the current
-     * colour and alpha values
-     */
-    updateSelected: function() {
-        this.selectedSwatch.style.backgroundColor = this.color;
-        this.colorInput.value = this.color.substring(1);
-        
-        this.alphaInput.value = parseInt(this.alpha*100);
-        if (this.alpha < 1) {
-            this.selectedSwatch.style.opacity = this.alpha;
-            this.selectedSwatch.style.filter = 'Alpha(opacity='+(this.alpha*100)+')';
-        } else {
-            this.selectedSwatch.style.opacity = '';
-            this.selectedSwatch.style.filter = '';
-        }
-        this.processEvent(this.ccl,'colorChanged',this);
-    },
-    
-    /**
-     * Method: show
-     * show the panel
-     */
-    show: function() {
-        this.domObj.style.display = 'block';
-        Event.observe(window, 'keypress', this.keypressWatcher);
-    },
-    
-    /**
-     * Method: hide
-     * hide the panel
-     */
-    hide: function() {
-        this.domObj.style.display = 'none';
-        Event.stopObserving(window, 'keypress', this.keypressWatcher);
-        
-    },
-    
-    /**
-     * Method: keypressHandler
-     * handle the user pressing a key.  If the key is the ESC key, then
-     * hide the color panel
-     *
-     * Parameters: 
-     * e - {Event} The keypress event
-     */
-    keypressHandler: function(e) {
-        var charCode=(e.charCode)?e.charCode:e.keyCode;
-        if (charCode == Event.KEY_ESC) {
-            this.hide();
-        }
-    },
-    /**
-     * Method: addColorChangeListener
-     * add a colour change listener, an object that has a colorChanged
-     * function.
-     *
-     * Parameters: 
-     * obj - {Object} The colour change listener to call when the colour changes.
-     */
-    addColorChangeListener: function(obj){this.addListener(this.ccl, obj);},
-    /**
-     * Method: removeColorChangeListener
-     * remove a previously added colour change listener
-     *
-     * Parameters: 
-     * obj - {Object} The colour change listener to remove
-     */
-    removeColorChangeListener: function(obj) {
-        this.removeListener(this.ccl, obj);
-    }
-};
-Object.extend(Jx.ColorPanel.prototype, Jx.Listener.prototype);
-
-/**
- * Class: Jx.Button.Color
- *
- * A <Jx.ColorPanel> wrapped up in a Jx.Button.  The button includes a
- * preview of the currently selected color.  Clicking the button opens
- * the color panel.
- *
- * Inherits From:
- * <Jx.Button.Flyout>
- */
-Jx.Button.Color = Class.create();
-Object.extend(Jx.Button.Color.prototype, Jx.Button.Flyout.prototype);
-Object.extend(Jx.Button.Color.prototype, {
-    /**
-     * Property: { Array } colorPanel
-     * By declaring this property as an array in the prototype, the
-     * array is used for all instances making it a Class property.
-     * A <Jx.ColorPanel> instance used by all color buttons is made the
-     * first element so that only one color panel is ever created.
-     */
-    colorPanel: [],
-    /**
-     * Property: {HTMLElement} swatch
-     * a div used to represent the current colour in the button.
-     */
-    swatch: null,
-    /**
-     * Property: {String} color
-     * the current colour of this button in hex.  We have to maintain
-     * it here because we share a colour panel with all other colour
-     * buttons
-     */
-    color: null,
-    /**
-     * Property: {Integer} alpha
-     * the current alpha of this button.  We have to maintain
-     * it here because we share a colour panel with all other colour
-     * buttons
-     */
-    alpha: null,
-    /**
-     * Property: {Array} ccl
-     * color change property listeners
-     */
-    ccl: null,
-    /**
-     * Constructor: Jx.Button.Color
-     * initialize a new colour button.
-     *
-     * Parameters: 
-     * options - {Object} an object containing a variable list of optional initialization
-     * parameters.
-     *
-     * Options:
-     * color - a colour to initialize the panel with, defaults to #000000
-     *      (black) if not specified.
-     * alpha - an alpha value to initialize the panel with, defaults to 1
-     *      (opaque) if not specified.
-     */
-     
-    initialize: function(options) {
-        options = options || {};
-        options.label = options.label || '&nbsp;';
-        this.color = options.color || '#000000';
-        this.alpha = options.alpha || 100;
-        this.ccl = [];
-        
-        if (this.colorPanel.length == 0) {
-            this.colorPanel[0] = new Jx.ColorPanel();
-        }
-        var d = document.createElement('div');
-        d.className = 'jxColorButtonPreview';
-        
-        this.selectedSwatch = document.createElement('div');
-        d.appendChild(this.selectedSwatch);
-        
-        /* create a button with a label so it doesn't get an empty label class
-           and then replace the label text with the swatch */
-        Jx.Button.Flyout.prototype.initialize.apply(this, [options]);
-        Element.addClassName(this.domObj.firstChild, 'jxButtonColor');
-        this.domObj.firstChild.firstChild.insertBefore(d, this.domObj.firstChild.firstChild.firstChild);
-        this.updateSwatch();
-    },
-    
-    /**
-     * Method: show
-     * show the color panel when the user clicks the button
-     */
-    show: function() {
-        if (this.colorPanel[0].currentButton) {
-            this.colorPanel[0].currentButton.hide();
-        }
-        this.colorPanel[0].currentButton = this;
-        this.colorPanel[0].addColorChangeListener(this);
-        this.content.appendChild(this.colorPanel[0].domObj);
-        this.colorPanel[0].domObj.style.display = 'block';
-        Jx.Button.Flyout.prototype.show.apply(this, arguments);
-        /* setting these before causes an update problem when clicking on
-         * a second color button when another one is open - the color
-         * wasn't updating properly
-         */
-        this.colorPanel[0].setColor(this.color);
-        this.colorPanel[0].setAlpha(this.alpha);
-    },
-    
-    /**
-     * Method: hide
-     * hide the colour panel
-     */    
-    hide: function() {
-        this.colorPanel[0].removeColorChangeListener(this);
-        Jx.Button.Flyout.prototype.hide.apply(this, arguments);
-        this.colorPanel[0].currentButton = null;
-    },
-    
-    /**
-     * Method: setColor
-     * set the colour represented by this colour panel
-     *
-     * Parameters: 
-     * color - {String} the new hex color value
-     */
-    setColor: function(color) {
-        this.color = color;
-        this.updateSwatch();
-    },
-    
-    /**
-     * Method: setAlpha
-     * set the alpha represented by this colour panel
-     *
-     * Parameters: 
-     * alpha - {Integer} the new alpha value (between 0 and 100)
-     */
-    setAlpha: function(alpha) {
-        this.alpha = alpha;
-        this.updateSwatch();
-    },
-    
-    /**
-     * Method: colorChanged
-     * colorChangeListener callback function when the user changes
-     * the colour in the panel (just update the preview).
-     */
-    colorChanged: function(panel) {
-        this.color = panel.color;
-        this.alpha = panel.alpha * 100;
-        this.updateSwatch();
-        this.processEvent(this.ccl,'colorChanged',this);
-    },
-    
-    /**
-     * Method: updateSwatch
-     * Update the swatch color for the current color
-     */
-    updateSwatch: function() {
-        this.selectedSwatch.style.backgroundColor = this.color;
-        if (this.alpha < 100) {
-            this.selectedSwatch.style.opacity = this.alpha/100;
-            this.selectedSwatch.style.filter = 'Alpha(opacity='+(this.alpha)+')';    
-        } else {
-            this.selectedSwatch.style.opacity = '';
-            this.selectedSwatch.style.filter = '';    
-        }
-    },
-    /**
-     * Method: addColorChangeListener
-     * add a colour change listener, an object that has a colorChanged
-     * function.
-     *
-     * Parameters: 
-     * obj - {Object} The colour change listener to call when the colour changes.
-     */
-    addColorChangeListener: function(obj){this.addListener(this.ccl, obj);},
-    /**
-     * Method: removeColorChangeListener
-     * remove a previously added colour change listener
-     *
-     * Parameters: 
-     * obj - {Object} The colour change listener to remove
-     */
-    removeColorChangeListener: function(obj) {
-        this.removeListener(this.ccl, obj);
-    }
-});
-/**
- * $Id: jxdialog.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Dialog
- *
- * Purpose: 
- * Implementation of a javascript Dialog for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-Jx.addStyleSheet('dialog/dialog.css');
-
-/**
- * Class: Jx.Dialog
- *
- * A Jx.Dialog implements a floating dialog.  Dialogs represent a useful way
- * to present users with certain information or application controls.
- * Jx.Dialog is designed to provide the same types of features as traditional
- * operating system dialog boxes, including:
- *
- * - dialogs may be modal (user must dismiss the dialog to continue) or 
- * non-modal
- *
- * - dialogs are moveable (user can drag the title bar to move the dialog
- * around)
- *
- * - dialogs may be a fixed size or allow user resizing.
- *
- * - dialogs may have associated help content that is available as a slide-out
- * help panel on the right-hand side of the dialog.
- *
- * Jx.Dialog uses <Jx.ContentLoader> to load content into the content area
- * of the dialog.  Refer to the <Jx.ContentLoader> documentation for details
- * on content options.  Jx.Dialog also uses <Jx.ContentLoader> to load
- * help content, using non-standard options prefixed by 'help' instead of
- * 'content' (see options in initialize below).
- *
- * (code)
- * var dialog = new Jx.Dialog({});
- * (end)
- *
- * Inherits From:
- * <Jx.ContentLoader>, <Jx.UniqueId>
- */
-Jx.Dialog = Class.create();
-Jx.Dialog.prototype = {
-    /**
-     * Property: {Function} onClose
-     * if specified by the caller, this is a function to invoke
-     * when the dialog closes.
-     */
-    onClose : null,
-    /**
-     * Property: {Function} onOpen
-     * if specified by the caller, this is a function to invoke
-     * when the dialog opens.
-     */
-    onOpen : null,
-    /**
-     * Property: {Function} onChange
-     * if specified by the caller, this is a function to invoke
-     * when any input element in the dialog is changed.
-     */
-    onChange : null,
-    /**
-     * Property: {String} title
-     * the text to display in the title bar of the dialog.
-     */
-    title : null,
-    /**
-     * Property: {HTMLElement} content
-     * the content area element of the dialog, used to load user-
-     * specified content into.
-     */
-    content : null,
-    /**
-     * Property: {HTMLElement} action
-     * the action area element of the dialog, used for buttons.
-     */
-    action : null,
-    /**
-     * Property: {Object} values
-     * when dialog content is loaded, the content is inspected for input
-     * elements and a record of them is keep in this object for later
-     * reference.
-     */
-    values : null,
-    /**
-     * Property: {Object} actions
-     * when dialog content is loaded, the content is inspected for
-     * input elements of type 'button' and a record of them is
-     * kept in this object for later reference.
-     */
-    actions : null,
-    /**
-     * Property: {Function} handler
-     * if specified by the caller, this is a function to invoke
-     * when an input of type button is clicked by the user.
-     */
-    handler : null,
-    /**
-     * TODO: Jx.Dialog.bContentLoaded
-     * remove this property, it is provided by Jx.ContentLoader.
-     */
-    bContentLoaded : null,
-    /**
-     * Property: {Array} zIndex
-     * class variable containing the last assigned z-index so that
-     * dialogs stack correctly.
-     */
-    zIndex: [101],
-    /**
-     * Property: {Array} stack
-     * class variable containing the list of visible dialogs used to
-     * manage the z-index of non-modal dialogs.  This allows the user
-     * to click a dialog and have it appear in front of other dialogs.
-     */
-    stack: [],
-    /**
-     * Property: {HTMLElement} blanket
-     * modal dialogs prevent interaction with the rest of the application
-     * while they are open, this element is displayed just under the
-     * dialog to prevent the user from clicking anything.
-     */
-    blanket: null,
-    
-    /**
-     * Property: firstShow
-     * {Boolean} true if the dialog has not been made visible yet.  This
-     * facilitates resizing of <Jx.Layout> managed elements in the dialog
-     */
-    firstShow: true,
-    
-    /**
-     * Property: {Boolean} modal
-     * whether or not the dialog is modal.
-     */
-    modal: true,
-    /**
-     * Constructor: Jx.Dialog
-     * Construct a new instance of Jx.Dialog
-     *
-     * Parameters: 
-     * options - {Object} an object containing options for the dialog.
-     *
-     * Options:
-     * onChange - (optional) {Function} a function to call if the user changes
-     *      the value of any input in the dialog
-     * onClose - (optional) {Function} a function to call when the user closes
-     *      the dialog
-     * onOpen - (optional) {Function} a function to call when the user opens
-     *      the dialog
-     * onContentLoaded - (optional) {Function} a function to call when the
-     *      content of the dialog has been loaded, used primarily with
-     *      asynchronous content
-     * handler - (optional) {Function} a function to call when the user clicks
-     *      on any input of type 'button' in the dialog
-     * modal - (optional) {Boolean} controls whether the dialog will be modal
-     *      or not.  The default is to create modal dialogs.
-     * top - (optional) {Integer} the distance in pixels to initially place
-     *      the dialog from the top edge of its container.  Default is 0 unless
-     *      bottom is specified, in which case the top value is not used.
-     * bottom - (optional) {Integer} the distance in pixels to initially place
-     *      the dialog from the bottom edge of its container.  Default is null, which
-     *      means that the dialog is not positioned relative to the bottom of its
-     *      container.  If top and bottom are specified, top is used.
-     * left - (optional) {Integer} the distance in pixels to initially place
-     *      the dialog from the left edge of its container.
-     * right - (optional) {Integer} the distance in pixels to initially place
-     *      the dialog from the right edge of its container.  Default is null, which
-     *      means that the dialog is not positioned relative to the right of its
-     *      container.  If left and right are specified, left is used.
-     * width - (optional) {Integer} the initial width in pixels of the dialog.
-     *      The default value is 250 if not specified.
-     * height - (optional) {Integer} the initial height in pixels of the 
-     *      dialog. The default value is 250 if not specified.
-     * title - (optional) {String} the title of the dialog box.  "New Dialog"
-     *      is the default value.
-     * titleHeight - (optional) {Integer} the height, in pixels, of the
-     *      dialog's title bar.  The default value is 22, and works with the default
-     *      dialog styles.  Only change this value is you are overriding the
-     *      default style of the dialog's title bar
-     * closeImg - (optional) {String} URL to an image to use for the close
-     *      button in the dialog title bar area.  The default value is to use
-     *      the close image provided by Jx.  Only override this value if you are
-     *      changing the default style of the dialog's title bar.
-     * helpID - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      help content.
-     * helpURL - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      help content.
-     * helpHTML - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      help content.
-     * help - (optional) {Object} passed to <Jx.ContentLoader> for loading
-     *      help content.
-     * contentID - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      dialog content.
-     * contentURL - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      dialog content.
-     * contentHTML - (optional) {String} passed to <Jx.ContentLoader> for loading
-     *      dialog content.
-     * content - (optional) {Object} passed to <Jx.ContentLoader> for loading
-     *      dialog content.
-     * buttons - (optional) {Array} an array of strings that contain the labels
-     *      for buttons to create in the Action area of the dialog.
-     * id - (optional) {String} an HTML ID to assign to the dialog, primarily
-     *      used for applying CSS styles to specific dialogs
-     * parentObj - (optional) {HTMLElement} a reference to an HTML element that
-     *      the dialog is to be contained by.  The default value is for the dialog
-     *      to be contained by the body element.
-     * resizeable - (optional) {Boolean} determines whether the dialog is
-     *      resizeable by the user or not.  Default is false.
-     * imageBaseUrl - (optional) {String} the path to the various dialog edge
-     *      images.  If not specified, then Jx.baseURL is used.
-     */
-    initialize: function(options) {
-        this.initUniqueId();
-        this.values = {};
-        this.actions = {};
-        this.handler = options.handler?options.handler:null;
-        if (options.onChange) {this.onChange = options.onChange;}
-        if (options.onClose) {this.onClose = options.onClose;}
-        if (options.onOpen) {this.onOpen = options.onOpen;}
-        if (options.onContentLoaded) {this.onContentLoaded = options.onContentLoaded;}
-        
-        this.imageBaseUrl = options.imageBaseUrl || Jx.baseURL + "/images/";
-        if (this.imageBaseUrl.slice(-1) != '/') {
-            this.imageBaseUrl += '/';
-        }
-        this.modal = typeof options.modal == 'undefined' ? true : options.modal;
-        
-        var w = options.width || 250;
-        var h = options.height || 250;
-        var b = (typeof options.bottom != 'undefined') ? options.bottom : null;
-        var r = (typeof options.right != 'undefined') ? options.right : null;
-        var t = (typeof options.top != 'undefined') ? options.top : (b != null ? null : 0);
-        var l = (typeof options.left != 'undefined') ? options.left : (r != null ? null : 0);
-        
-        this.blanket = document.createElement('div');
-        this.blanket.className = 'jxDialogModal';
-        this.blanket.style.display = 'none';
-        
-        if (!window.opera && this.modal) {
-            var iframe = document.createElement('iframe');
-            iframe.className = 'jxDialogShim';
-            iframe.scrolling = 'no';
-            iframe.frameborder = 0;
-            this.blanket.appendChild(iframe);
-            if (options.parentObj) {
-                $(options.parentObj).appendChild(this.blanket);
-            } else {
-                document.body.appendChild(this.blanket);            
-            }        
-        }
-
-        /* dragHandle is the title bar */
-        this.dragHandle = document.createElement('div');
-        this.dragHandle.innerHTML = options.title || '&nbsp;';
-        this.dragHandle.style.width = '100%';
-        
-        var domObj = document.createElement('div');
-        domObj.className = 'jxDialogContainer';
-        this.domObj = domObj;
-        /* set the id if passed in through options */
-        if (options.id) {
-            domObj.id = options.id;
-        }
-
-        var dialogObj = document.createElement('div');
-        dialogObj.className = 'jxDialog';
-        this.innerDialogObj = dialogObj;
-        
-        var titleObj = document.createElement('div');
-        titleObj.className = 'jxDialogTitle';
-        this.title = titleObj;
-        titleObj.appendChild(this.dragHandle);
-        
-        /* element must be in the page to be measured */
-        titleObj.style.visibility = 'hidden';
-        document.getElementsByTagName('BODY')[0].appendChild(titleObj);
-        this.titleHeight = Element.getBorderBoxSize(titleObj).height;
-        document.getElementsByTagName('BODY')[0].removeChild(titleObj);
-        titleObj.style.visibility = '';
-        
-        var contentObj = document.createElement('div');
-        contentObj.className = 'jxDialogContent';
-        this.content = contentObj;
-        
-        domObj.appendChild(dialogObj);
-        dialogObj.appendChild(titleObj);
-        dialogObj.appendChild(contentObj);
-                
-        new Jx.Layout(dialogObj, {width: w, height: h});
-        new Jx.Layout(titleObj, {top: 0, left: 0, right: 0, bottom: null, height: this.titleHeight, width: null});
-
-        /* optional 'action' area for buttons if necessary */
-        this.actionHeight = 0;
-        if (options.buttons) {
-            var actionObj = document.createElement('div');
-            actionObj.className = 'jxDialogAction';
-            actionObj.style.visibility = 'hidden';
-            document.getElementsByTagName('BODY')[0].appendChild(actionObj);
-            this.actionHeight = parseInt(Element.getStyle(actionObj, 'height'));
-            document.getElementsByTagName('BODY')[0].removeChild(actionObj);
-            actionObj.style.visibility = '';
-            dialogObj.appendChild(actionObj);
-            new Jx.Layout(actionObj, {top: null, left: 0, right: 0, bottom: 0, height: this.actionHeight, width: null});
-            this.action = actionObj;
-            this.setButtons(options.buttons);
-        }
-
-        new Jx.Layout(contentObj, {top: this.titleHeight, left: 0, right: 0, bottom: this.actionHeight});
-        
-        
-        /* build the decorations for the title bar */
-        var atag = document.createElement('a');
-        atag.href = 'javascript:void(0)';
-        atag.className = 'jxDialogCloseButton';
-        atag.onclick = this.close.bindAsEventListener(this);
-        
-        var close = document.createElement('img');
-        if(options.closeImg) {
-            close.src = options.closeImg;
-        }
-        else {
-            close.src = this.imageBaseUrl + 'icon_close.png';
-        }
-        close.alt = 'Close Dialog';
-        close.title = 'Close Dialog';
-        atag.appendChild(close);
-        titleObj.appendChild(atag);
-        
-        if (options.helpID || options.helpHTML || options.helpURL || options.help) {
-            /* put a button in the title bar to open help */
-            var atag2 = document.createElement('a');
-            atag2.href = 'javascript:void(0)';
-            atag2.className = 'jxDialogHelpButton';
-            atag2.onclick = this.toggleHelp.bindAsEventListener(this);
-            var help = document.createElement('img');
-            help.src = this.imageBaseUrl + 'icon_quickhelp.png';
-            help.alt = 'Help';
-            help.title = 'Help';
-            atag2.appendChild(help);
-            titleObj.appendChild(atag2);
-
-            /* make the help area */
-            this.help = document.createElement('div');
-            this.help.className = 'jxDialogHelp';
-            this.help.style.display = 'none';
-            this.help.isVisible = false;
-            var helpOpts = {};
-            helpOpts.contentID = options.helpID;
-            helpOpts.content = options.help;
-            helpOpts.contentURL = options.helpURL;
-            helpOpts.contentHTML = options.helpHTML;
-            helpOpts.onContentLoaded = this.onHelpContentLoaded.bind(this);
-            this.loadContent(this.help, helpOpts);
-            dialogObj.appendChild(this.help);
-        }
-        
-        var contentOpts = {};
-        contentOpts.contentID = options.contentID;
-        contentOpts.content = options.content;
-        contentOpts.contentURL = options.contentURL;
-        contentOpts.contentHTML = options.contentHTML;
-        contentOpts.onContentLoaded = this.onDialogContentLoaded.bind(this);
-        this.loadContent(contentObj, contentOpts);
-                
-        /* element must be in the page to be measured */
-        dialogObj.style.visibility = 'hidden';
-        document.body.appendChild(dialogObj);
-        //force an initial size calculation
-        dialogObj.resize();
-        
-        /* the outer box needs to be sized to the border box size plus margins
-         * of the inner box.
-         */
-         
-        this.dialogBoxSize = Element.getBorderBoxSize(dialogObj);
-        this.dialogBoxMargins = Element.getMarginSize(dialogObj);
-        
-        var containerSize = {width: this.dialogBoxSize.width, height: this.dialogBoxSize.height};
-        containerSize.width += this.dialogBoxMargins.left + this.dialogBoxMargins.right; 
-        containerSize.height += this.dialogBoxMargins.top + this.dialogBoxMargins.bottom;
-        
-        document.body.removeChild(dialogObj);
-        dialogObj.style.visibility = '';
-        domObj.appendChild(dialogObj);
-        
-        /* now create overall container with the correct size */
-        domObj.style.display = "none";
-        
-        Element.setBorderBoxSize(domObj, {width:(containerSize.width), height:(containerSize.height)});
-        
-        domObj.style.position = 'absolute';
-        if (t != null) {
-            domObj.style.top = (t) + 'px';
-        } else {
-            domObj.style.bottom = (b) + 'px';
-        }
-        if (l != null) {
-            domObj.style.left = (l) + 'px';
-        } else {
-            domObj.style.right = (r) + 'px';
-        }
-
-        if (options.parentObj) {
-            $(options.parentObj).appendChild(domObj);
-        } else {
-            document.body.appendChild(domObj);            
-        }
-
-        /* Background */
-        this.DTOffset = 0;
-        this.DBOffset = 0;
-        this.DROffset = 0;
-        this.DLOffset = 0;
-        this.decorationOffsets = {top:0, right: 0, bottom: 0, left: 0};
-        
-        /* top left */
-        
-        var imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgTL';
-        var img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_tl.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.decorationOffsets.top += parseInt(Element.getStyle(img,'width'));
-        this.decorationOffsets.left += parseInt(Element.getStyle(img,'height'));
-
-        /* top right */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgTR';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_tr.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.decorationOffsets.top += parseInt(Element.getStyle(img,'width'));
-        this.decorationOffsets.right += parseInt(Element.getStyle(img,'height'));
-
-        /* bottom right */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgBR';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_br.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.decorationOffsets.bottom += parseInt(Element.getStyle(img,'width'));
-        this.decorationOffsets.right += parseInt(Element.getStyle(img,'height'));
-
-        /* bottom left */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgBL';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_bl.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.decorationOffsets.bottom += parseInt(Element.getStyle(img,'width'));
-        this.decorationOffsets.left += parseInt(Element.getStyle(img,'height'));
-
-        /* top */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgT';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_t.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        img.style.width = containerSize.width-this.decorationOffsets.top + 'px';
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.topImg = img;
-
-        /* bottom */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgB';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_b.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        img.style.width = containerSize.width-this.decorationOffsets.bottom + 'px';
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.bottomImg = img;
-
-        /* left */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgL';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_l.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        img.style.height = containerSize.height-this.decorationOffsets.left + 'px';
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.leftImg = img;
-
-        /* right */
-        imgContainer = document.createElement('div');
-        imgContainer.className = 'jxDialogBgR';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + 'dialog_glow_r.png';
-        img.className = 'png24'; /* apply png hack for IE */
-        img.style.height = containerSize.height-this.decorationOffsets.right + 'px';
-        imgContainer.appendChild(img);
-        domObj.appendChild(imgContainer);
-        this.rightImg = img;
-
-        
-        Event.observe(domObj, 'mousedown', this.mouseDown.bind(this));
-        Event.observe(this.title, 'mousedown', this.mouseDown.bind(this));
-                
-        if (options.resizeable) {
-            this.resizeHandle = document.createElement('div');
-            this.resizeHandle.className = 'jxDialogResize';
-            this.resizeHandle.style.position = 'absolute'; //required for Draggable
-            this.domObj.appendChild(this.resizeHandle);
-
-            this.resizeHandleSize = {width:parseInt(Element.getStyle(this.resizeHandle,'width')),
-                                     height:parseInt(Element.getStyle(this.resizeHandle,'height'))};
-
-            this.resizeHandle.style.top = (containerSize.height-this.resizeHandleSize.height) + 'px';
-            this.resizeHandle.style.left = (containerSize.width-this.resizeHandleSize.width) + 'px';
-            new Draggable(this.resizeHandle, {starteffect: false, endeffect: false,change:this.ondrag.bind(this), zindex: 0});
-        }
-        
-        this.bOpen = false;
-    },
-    /**
-     * Method: mouseDown
-     * handle the user clicking the title area, promote the dialog to the
-     * top of the stack so it is fully visible to the user.
-     */
-    mouseDown: function() {
-        for (var i=0; i<this.stack.length; i++) {
-            if (this.stack[i] == this) {
-                this.stack.splice(i, 1);
-                this.stack.push(this);
-            }
-        }
-        for (var i=0; i<this.stack.length; i++) {
-            this.stack[i].domObj.style.zIndex = (101 + i);
-        }
-    },
-    /** 
-     * Method: ondrag
-     * callback function for user-resizing of the dialog
-     *
-     * Parameters: 
-     * obj - {Object} a drag object that indicates what happened.
-     */
-    ondrag: function(obj) {
-        this.mouseDown();
-        
-        var delta = obj.currentDelta();
-        //delta is top/left of resize image.  Bottom/right of the dialog needs to be
-        //adjusted for size of image (20x20).
-        var deltaX = delta[0] + this.resizeHandleSize.width;
-        var deltaY = delta[1] + this.resizeHandleSize.height;
-        this.resize({width: deltaX, height: deltaY});
-    },
-    /**
-     * Method: resize
-     * programmatically resize the dialog in either or both dimensions
-     *
-     * Parameters: 
-     * newSize - {Object} an object containing either or both 'width' and 'height' properties
-     * that hold the new width or height in pixels
-     */
-    resize: function(newSize) {
-
-        /* let jxLayout manage the internal stuff */
-        this.innerDialogObj.resize(newSize);
-                
-        /* sizing logic for container
-         *
-         * we need to set the size of this.innerDialogObj to the requested size
-         * then size the title, content and action area within it and expand
-         * this.domObj to contain it properly.  Then we need to position the
-         * images appropriately too.
-         */
-        if (newSize.width) {
-            var outerWidth = newSize.width;
-            Element.setBorderBoxSize(this.domObj, {width: outerWidth});
-            Element.setBorderBoxSize(this.topImg, {width:outerWidth-this.decorationOffsets.top});
-            Element.setBorderBoxSize(this.bottomImg, {width:outerWidth-this.decorationOffsets.bottom});
-        }
-        if (newSize.height) {
-            var outerHeight = newSize.height;
-            Element.setBorderBoxSize(this.domObj, {height: outerHeight});
-            Element.setBorderBoxSize(this.leftImg, {height:outerHeight-this.decorationOffsets.left});
-            Element.setBorderBoxSize(this.rightImg, {height:outerHeight-this.decorationOffsets.right});
-            if (this.help) {
-                Element.setBorderBoxSize(this.help, {height:newSize.height - this.titleHeight});
-            }
-        }
-    },
-    /**
-     * Method: setTitle
-     * set the text of the dialog title.
-     *
-     * Parameters: 
-     * title - {String} the new title
-     */
-    setTitle: function( title ) {
-        this.title.childNodes[0].innerHTML = title;
-    },
-    /**
-     * Method: setButtons
-     * create buttons in the action area of the dialog
-     *
-     * Parameters: 
-     * buttons - {Array} an array of strings containing the labels to place on the
-     * buttons.  One button is created for each label.
-     */
-    setButtons: function(buttons) {
-        this.action.innerHTML = '';
-        for (var i=0; i<buttons.length;i++) {
-            var button = document.createElement('input');
-            button.id = buttons[i];
-            button.type = 'button';
-            button.className = 'normalButton';
-            button.name = buttons[i];
-            button.value = buttons[i];
-            button.onclick = this.buttonHandler.bind(this, button);
-            this.action.appendChild(button);
-            this.uniqueIdRefs[button.id] = button;
-        }
-    },
-    /**
-     * Method: processInputs
-     * look through the DOM obj for nodes of type INPUT and register
-     * for events on them.
-     *
-     * Parameters: 
-     * obj - {HTMLElement} the DOM obj to process
-     */
-    processInputs : function(obj) {
-        for (var i=0;i<obj.childNodes.length; i++) {
-            var node = obj.childNodes[i];
-            if (node.tagName == 'INPUT' || node.tagName == 'SELECT' || node.tagName == 'TEXTAREA') {
-                if (node.type == 'button') {
-                    this.actions[node.id] = node;
-                    node.onclick = this.buttonHandler.bind(this, node);
-                } else {
-                    this.values[node.id] = node;
-                    if (this.onChange) {
-                        node.onchange = this.onChangeHandler.bind(this, node);
-                    }
-                }
-            } else {
-                if (node.childNodes) {
-                    this.processInputs(node);
-                }
-            }
-        }
-    },
-    /**
-     * Method: buttonHandler
-     * handle button events, dispatching to user handler if required.
-     *
-     * Parameters: 
-     * input - {HTMLElement} the input element that triggered a click event
-     * event - {Event} the event object
-     */
-    buttonHandler : function(input, event) {
-        if (this.handler) {
-            this.handler(input.value, this);
-        }
-    },
-    /**
-     * Method: onChangeHandler
-     * handle onchange events, dispatching to user handler if required.
-     *
-     * Parameters: 
-     * input - {HTMLElement} the input element that triggered an onchange event
-     * event - {Event} the event object
-     */
-    onChangeHandler: function(input, event) {
-        if (this.onChange) {
-            this.onChange(input, this);
-        }
-    },
-    /**
-     * Method: getValue
-     * retrieve the value of an input element in the dialog.  This is done
-     * safely so depending on the type of the input.
-     *
-     * Parameters: 
-     * name - {String} the id of the element to get the value of
-     *
-     * Returns: {String} the value or an empty string.
-     */
-    getValue : function( name ) {
-        var result = '';
-        var input = this.values[name];
-        if (input) {
-            switch (input.tagName) {
-                case 'INPUT': 
-                    result = input.value;
-                    break;
-                case 'SELECT':
-                    result = input.options[input.selectedIndex].value;
-            }
-        }
-        return result;
-    },
-    /**
-     * Method: setValue
-     * set the value of an input element in the dialog.  This is done
-     * safely  depending on the type of the input.
-     *
-     * Parameters: 
-     * name - {String} the id of the element to set the value of
-     * value - {String} the value to set
-     */
-    setValue : function( name, value ) {
-        if (typeof this.values[name] != 'undefined') {
-            if (this.values[name].type == 'text' || this.values[name].type == 'hidden') {
-                this.values[name].value = value;
-            }
-        }
-    },
-    /**
-     * Method: show
-     * show the dialog
-     */
-    show : function( ) {
-        this.stack.push(this);
-        if (this.modal) {
-            this.blanket.style.zIndex = this.zIndex[0]++;
-            this.blanket.style.visibility = 'visible';
-            this.blanket.style.display = 'block';
-        }
-        this.domObj.style.zIndex = this.zIndex[0]++;
-        Effect.Appear(this.domObj, {duration: 0.1});
-        this.domObj.style.display = 'block';
-        new Draggable(this.domObj, {handle:this.dragHandle, starteffect: false, endeffect: false});
-        this.content.resize({forceResize: this.firstShow});
-        this.firstShow = false;
-    },
-    /**
-     * Method: hide
-     * hide the dialog
-     */
-    hide : function() {
-        for (var i=0; i<this.stack.length; i++) {
-            if (this.stack[i] == this) {
-                this.stack.splice(i,1);
-            }
-        }
-        this.zIndex[0]--;
-        Effect.Fade(this.domObj, {duration: 0.3});
-        //this.domObj.style.display = 'none';
-        if (this.modal) {
-            this.blanket.style.visibility = 'hidden';
-            this.zIndex[0]--;
-        }
-        
-    },
-    /**
-     * Method: open
-     * open the dialog.  This may be delayed depending on the 
-     * asynchronous loading of dialog content.  The onOpen
-     * callback function is called when the dialog actually
-     * opens
-     */
-    open: function() {
-        if (!this.bOpen) {
-            this.bOpen = true;
-        }
-        if (this.bContentLoaded) {
-            this.show();
-            if (this.onOpen) this.onOpen();
-        }
-    },
-    /**
-     * Method: close
-     * close the dialog and trigger the onClose callback function
-     * if necessary
-     */
-    close: function() {
-        this.bOpen = false;
-        this.hide();
-        if (this.onClose) this.onClose();
-    },
-    /**
-     * Method: onDialogContentLoaded
-     * handle the dialog content being loaded.  This triggers
-     * processing of inputs and the onContentLoaded callback
-     * function (if necessary).  Also, if the dialog was previously
-     * requested to be opened, this will actually open it.
-     */
-    onDialogContentLoaded : function() {
-        this.processInputs(this.content);
-        if (this.onContentLoaded) {
-            this.onContentLoaded(this);
-        }
-        if (this.bOpen) {
-            //may need to do this?
-            //window.setTimeout(this.open.bind(this),1);
-            this.open();
-            this.bOpen = false;
-        }
-    },
-    /**
-     * Method: onHelpContentLoaded
-     * handle the help content being loaded.  
-     */
-    onHelpContentLoaded : function() {
-        var img = document.createElement('img');
-        img.className = 'jxDialogHelpCloseButton png24';
-        img.src = this.imageBaseUrl + 'help_close.png';
-        img.onclick = this.toggleHelp.bind(this);
-        img.alt = 'Close Help';
-        img.title = 'Close Help';
-        this.help.appendChild(img);
-    },
-    /**
-     * Method: toggleHelp
-     * show or hide the help panel.
-     */
-    toggleHelp: function() { 
-        if (this.help.isVisible) {
-            Effect.Fade(this.help, {duration: 0.3});
-        } else {
-            var actionSize = this.action ? Element.getBorderBoxSize(this.action) : {width: 0, height: 0};
-            var contentSize = Element.getBorderBoxSize(this.content);
-            Element.setBorderBoxSize(this.help, {height:contentSize.height+actionSize.height});
-            Effect.Appear(this.help, {duration: 0.3});
-        }
-        this.help.isVisible = !this.help.isVisible;
-    }
-};
-Object.extend(Jx.Dialog.prototype, Jx.UniqueId.prototype);
-Object.extend(Jx.Dialog.prototype, Jx.ContentLoader.prototype);/**
- * $Id: jxgrid.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Grid
- *
- * Purpose: 
- * Implementation of a javascript Grid control for Jx.
- *
- * Jx.Grid is a tabular control with convenient controls for resizing columns,
- * sorting, and inline editing.  It is created inside another element, typically a
- * div.  If the div is resizable (for instance it fills the page or there is a
- * user control allowing it to be resized), you must call the resize() method
- * of the grid to let it know that its container has been resized.
- *
- * When creating a new Jx.Grid, you can specify a number of options for the grid
- * that control its appearance and functionality.
- *
- * Jx.Grid renders data that comes from an external source.  This external 
- * source, called the model, must implement the following interface.
- *
- * *Mandatory Functions*
- *
- * addGridListener(l) - mandatory
- * mandatory.  This function accepts one argument, l, which is the listener
- * to add.  The model can then call the gridChanged() method on the grid
- * listener object when something in the model changes.
- * 
- * removeGridListener(l) - mandatory
- * mandatory.  This function accepts one argument, l, which is the listener
- * to remove.  The listener should have been previously added using
- * addGridListener.
- * 
- * getColumnCount() - mandatory
- * mandatory.  This function returns the number of columns of data in the 
- * model as an integer value.
- * 
- * getColumnHeaderHTML(column) - mandatory
- * mandatory. This function returns an HTML string to be placed in the
- * column header for the given column index.
- * 
- * getColumnHeaderHeight() - mandatory
- * mandatory.  This function returns an integer which is the height of the
- * column header row in pixels.
- * 
- * getColumnWidth(column) - mandatory
- * mandatory.  This function returns an integer which is the width of the
- * given column in pixels.
- * 
- * getRowHeaderHTML(row) - mandatory
- * mandatory.  This function returns an HTML string to be placed in the row
- * header for the given row index
- * 
- * getRowHeaderWidth() - mandatory
- * mandatory.  This function returns an integer which is the width of the row
- * header column in pixels.
- * 
- * getRowHeight(row) - mandatory
- * mandatory.  This function returns an integer which is the height of the
- * given row in pixels.
- * 
- * getRowCount() - mandatory
- * mandatory.  This function returns the number of rows of data in the model
- * as an integer value.
- * 
- * getValueAt(row, column) - mandatory
- * mandatory.  This function returns an HTML string which is the text to place
- * in the cell at the given row and column.
- * 
- * isCellEditable(row, column) - mandatory
- * mandatory.  This function returns a boolean value to indicate if a given
- * cell is editable by the user.
- *
- * *Optional Functions*
- *  
- * setColumnWidth(column, width) - optional
- * optional.  This function is called with a column index and width in pixels
- * when a column is resized.  This function is only required if the grid
- * allows resizeable columns.
- * 
- * setValueAt(row, column, value) - optional
- * optional.  This function is called with the row and column of a cell and a
- * new value for the cell.  It is mandatory to provide this function if any of
- * the cells in the model are editable.
- * 
- * rowSelected(row) - optional
- * optional.  This function is called by the grid to indicate that the user
- * has selected a row by clicking on the row header.
- * 
- * columnSelected(column) - optional
- * optional.  This function is called by the grid to indicate that the user
- * has selected a column by clicking on the column header.
- * 
- * cellSelected(row, column) - optional
- * optional.  This function is called by the grid to indicate that the user
- * has selected a cell by clicking on the cell in the grid.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-/* our default css styles */
-Jx.addStyleSheet('grid/grid.css');
-
-/**
- * Class: Jx.Grid
- * A tabular control that has fixed scrolling headers on the rows and columns
- * like a spreadsheet.
- */
-Jx.Grid = Class.create();
-Jx.Grid.prototype = {
-    domObj : null,
-    model : null,
-    /**
-     * Constructor: Jx.Grid
-     * construct a new instance of Jx.Grid within the domObj
-     *
-     * Parameters:
-     * domObj - {HTMLElement} the HTML element to create the grid inside.
-     *          The grid will resize to fill the domObj.
-     * options - you can specify some options as attributes of a
-     * generic object.
-     *
-     * Options:
-     * alternateRowColors - defaults to false.  If set to true, then
-     *      alternating CSS classes are used for rows
-     * rowHeaders - defaults to false.  If set to true, then a column
-     *      of row header cells are displayed.
-     * columnHeaders - defaults to false.  If set to true, then a column
-     *      of row header cells are displayed.
-     * rowSelection - defaults to false.  If set to true, allow the
-     *      user to select rows.
-     * cellSelection - defaults to false.  If set to true, allow the
-     *      user to select cells.
-     */
-    initialize : function( domObj, options ) {
-        this.domObj = $(domObj);
-        
-        /* if this grid is the content of a Jx Panel, this will
-           allow the grid to resize when the panel resizes
-         */
-        if (!this.domObj.jxLayout) {
-            new Jx.Layout(this.domObj);
-        }
-        this.domObj.jxLayout.addSizeChangeListener(this);
-        
-        options = options || {};
-        
-        this.rowColObj = document.createElement('div');
-        this.rowColObj.className = 'jxGridContainer';
-        
-        this.colObj = document.createElement('div');
-        this.colObj.className = 'jxGridContainer';
-        this.colTable = document.createElement('table');
-        this.colTable.className = 'jxGridTable';
-        this.colTableHead = document.createElement('thead');
-        this.colTable.appendChild(this.colTableHead);
-        this.colTableBody = document.createElement('tbody');
-        this.colTable.appendChild(this.colTableBody);
-        this.colObj.appendChild(this.colTable);
-        
-        this.rowObj = document.createElement('div');
-        this.rowObj.className = 'jxGridContainer';
-        this.rowTable = document.createElement('table');
-        this.rowTable.className = 'jxGridTable';
-        this.rowTableHead = document.createElement('thead');
-        this.rowTable.appendChild(this.rowTableHead);
-        this.rowObj.appendChild(this.rowTable);
-        
-        this.gridObj = document.createElement('div');
-        this.gridObj.className = 'jxGridContainer';
-        this.gridObj.style.overflow = 'scroll';
-        this.gridTable = document.createElement('table');
-        this.gridTable.className = 'jxGridTable';
-        this.gridTableBody = document.createElement('tbody');
-        this.gridTable.appendChild(this.gridTableBody);
-        this.gridObj.appendChild(this.gridTable);
-        
-        this.domObj.appendChild(this.rowColObj);
-        this.domObj.appendChild(this.rowObj);
-        this.domObj.appendChild(this.colObj);
-        this.domObj.appendChild(this.gridObj);
-        
-        this.bAlternateRowColors = options.alternateRowColors || false;
-        this.showRowHeader = options.rowHeaders || false;
-        this.showColumnHeader = options.columnHeaders || false;
-        this.rowSelection = options.rowSelection || false;
-        this.cellSelection = options.cellSelection || false;
-                
-        Event.observe(this.gridObj, 'scroll', this.onScroll.bind(this));
-        Event.observe(this.gridObj, 'click', this.onClickGrid.bindAsEventListener(this));
-        Event.observe(this.rowObj, 'click', this.onClickRowHeader.bindAsEventListener(this));
-        Event.observe(this.colObj, 'click', this.onClickColumnHeader.bindAsEventListener(this));
-        Event.observe(this.gridObj, 'mousemove', this.onMouseMoveGrid.bindAsEventListener(this));
-        Event.observe(this.rowObj, 'mousemove', this.onMouseMoveRowHeader.bindAsEventListener(this));
-        Event.observe(this.colObj, 'mousemove', this.onMouseMoveColumnHeader.bindAsEventListener(this));
-    },
-    
-    /**
-     * Method: onScroll
-     * handle the grid scrolling by updating the position of the headers
-     */
-    onScroll: function() {
-        this.colObj.scrollLeft = this.gridObj.scrollLeft;
-        this.rowObj.scrollTop = this.gridObj.scrollTop;        
-    },
-    
-    /**
-     * Method: sizeChanged
-     * Handle the container of the grid resizing
-     */
-    sizeChanged: function() {
-        this.resize();
-    },
-    
-    /**
-     * Method: resize
-     * resize the grid to fit inside its container.  This involves knowing something
-     * about the model it is displaying (the height of the column header and the
-     * width of the row header) so nothing happens if no model is set
-     */
-    resize: function() {
-        if (!this.model) {
-            return;
-        }
-        
-        /* TODO: Jx.Grid.resize
-         * if not showing column or row, should we handle the resize differently
-         */
-        var colHeight = this.showColumnHeader ? this.model.getColumnHeaderHeight() : 1;
-        var rowWidth = this.showRowHeader ? this.model.getRowHeaderWidth() : 1;
-        
-        var size = Element.getContentBoxSize(this.domObj);
-        
-        /* -1 because of the right/bottom borders */
-        this.rowColObj.style.width = (rowWidth - 1) + 'px';
-        this.rowColObj.style.height = (colHeight - 1) + 'px';
-        
-        this.rowObj.style.top = (colHeight) + 'px';
-        this.rowObj.style.left = '0px';
-        this.rowObj.style.width = (rowWidth - 1) + 'px';
-        this.rowObj.style.height = (size.height - colHeight - 1) + 'px';
-
-        this.colObj.style.top = '0px';
-        this.colObj.style.left = (rowWidth) + 'px';
-        this.colObj.style.width = (size.width - rowWidth - 1) + 'px';
-        this.colObj.style.height = (colHeight - 1) + 'px';
-
-        this.gridObj.style.top = (colHeight) + 'px';
-        this.gridObj.style.left = (rowWidth) + 'px';
-        this.gridObj.style.width = (size.width - rowWidth - 1) + 'px';
-        this.gridObj.style.height = (size.height - colHeight - 1) + 'px';
-    },
-    
-    /**
-     * Method: setModel
-     * set the model for the grid to display.  If a model is attached to the grid
-     * it is removed and the new model is displayed.
-     * 
-     * Parameters:
-     * model - {Object} the model to use for this grid
-     */
-    setModel: function(model) {
-        if (this.model) {
-            this.model.removeGridListener(this);
-        }
-        this.model = model;
-        if (this.model) {
-            this.domObj.jxLayout.resize();
-            this.model.addGridListener(this);
-            this.createGrid();
-            this.resize();
-        } else {
-            this.destroyGrid();
-        }
-    },
-    
-    /**
-     * Method: destroyGrid
-     * destroy the contents of the grid safely
-     */
-    destroyGrid: function() {
-        var n = this.colTableHead.cloneNode(false);
-        this.colTable.replaceChild(n, this.colTableHead);
-        this.colTableHead = n;
-        
-        n = this.colTableBody.cloneNode(false);
-        this.colTable.replaceChild(n, this.colTableBody);
-        this.colTableBody = n;
-        
-        n = this.rowTableHead.cloneNode(false);
-        this.rowTable.replaceChild(n, this.rowTableHead);
-        this.rowTableHead = n;
-        
-        n = this.gridTableBody.cloneNode(false);
-        this.gridTable.replaceChild(n, this.gridTableBody);
-        this.gridTableBody = n;
-        
-    },
-    
-    /**
-     * Method: createGrid
-     * create the grid for the current model
-     */
-    createGrid: function() {
-        this.destroyGrid();
-        if (this.model) {
-            var model = this.model;
-            var nColumns = model.getColumnCount();
-            var nRows = model.getRowCount();
-            
-            /* create header if necessary */
-            if (this.showColumnHeader) {
-                var colHeight = model.getColumnHeaderHeight();
-                var trHead = document.createElement('tr');
-                this.colTableHead.appendChild(trHead);
-                var trBody = document.createElement('tr');
-                this.colTableBody.appendChild(trBody);
-                
-                var th = document.createElement('th');
-                th.style.width = '0px';
-                th.style.height = '0px';
-                trHead.appendChild(th);
-                th = th.cloneNode(true);
-                th.style.height = (colHeight) + 'px';
-                trBody.appendChild(th);
-                for (var i=0; i<nColumns; i++) {
-                    var colWidth = model.getColumnWidth(i);
-                    th = document.createElement('th');
-                    th.className = 'jxGridColHeadHide';
-                    th.style.width = (colWidth) + 'px';
-                    var p = document.createElement('p');
-                    p.style.height = '0px';
-                    p.style.width = (colWidth) + 'px';
-                    th.appendChild(p);
-                    trHead.appendChild(th);
-                    
-                    th = document.createElement('th');
-                    th.className = 'jxGridColHead';
-                    th.innerHTML = model.getColumnHeaderHTML(i);
-                    trBody.appendChild(th);
-                }
-                /* one extra column at the end for filler */
-                var th = document.createElement('th');
-                th.style.width = '1000px';
-                th.style.height = '0px';
-                trHead.appendChild(th);
-                th = th.cloneNode(true);
-                th.style.height = (colHeight - 1) + 'px';
-                th.className = 'jxGridColHead';
-                trBody.appendChild(th);
-                
-            }
-            
-            if (this.showRowHeader) {
-                var rowWidth = model.getRowHeaderWidth();
-                var tr = document.createElement('tr');
-                var td = document.createElement('td');
-                td.style.width = '0px';
-                td.style.height = '0px';
-                tr.appendChild(td);
-                var th = document.createElement('th');
-                th.style.width = (rowWidth) + 'px';
-                th.style.height = '0px';
-                tr.appendChild(th);
-                this.rowTableHead.appendChild(tr);
-                for (var i=0; i<nRows; i++) {
-                    var rowHeight = model.getRowHeight(i);
-                    var tr = document.createElement('tr');
-                    var td = document.createElement('td');
-                    td.className = 'jxGridRowHeadHide';
-                    td.style.width = '0px';
-                    td.style.height = (rowHeight)+'px';
-                    var p = document.createElement('p');
-                    p.style.width = '0px';
-                    p.style.height = (rowHeight)+'px';
-                    td.appendChild(p);
-                    tr.appendChild(td);
-                    var th = document.createElement('th');
-                    th.className = 'jxGridRowHead';
-                    th.innerHTML = model.getRowHeaderHTML(i);
-                    tr.appendChild(th);
-                    this.rowTableHead.appendChild(tr);
-                }
-                /* one extra row at the end for filler */
-                var tr = document.createElement('tr');
-                var td = document.createElement('td');
-                td.style.width = '0px';
-                td.style.height = '1000px';
-                tr.appendChild(td);
-                var th = document.createElement('th');
-                th.style.width = (rowWidth) + 'px';
-                th.style.height = '1000px';
-                th.className = 'jxGridRowHead';
-                tr.appendChild(th);
-                this.rowTableHead.appendChild(tr);
-            }
-            
-            var colHeight = model.getColumnHeaderHeight();
-            var trBody = document.createElement('tr');
-            this.gridTableBody.appendChild(trBody);
-            
-            var td = document.createElement('td');
-            td.style.width = '0px';
-            td.style.height = '0px';
-            trBody.appendChild(td);
-            for (var i=0; i<nColumns; i++) {
-                var colWidth = model.getColumnWidth(i);
-                td = document.createElement('td');
-                td.className = 'jxGridColHeadHide';
-                td.style.width = (colWidth) + 'px';
-                var p = document.createElement('p');
-                p.style.height = '0px';
-                p.style.width = (colWidth) + 'px';
-                td.appendChild(p);
-                trBody.appendChild(td);
-            }
-            
-            for (var j=0; j<nRows; j++) {
-                var rowHeight = model.getRowHeight(j);
-                var actualRowHeight = rowHeight;
-                var tr = document.createElement('tr');
-                this.gridTableBody.appendChild(tr);
-                
-                var td = document.createElement('td');
-                td.className = 'jxGridRowHeadHide';
-                td.style.width = '0px';
-                td.style.height = (rowHeight) + 'px';
-                var p = document.createElement('p');
-                p.style.height = (rowHeight) + 'px';
-                td.appendChild(p);
-                tr.appendChild(td);
-                for (var i=0; i<nColumns; i++) {
-                    var colWidth = model.getColumnWidth(i);
-                    td = document.createElement('td');
-                    td.className = 'jxGridCell';
-                    td.innerHTML = model.getValueAt(j,i);
-                    tr.appendChild(td);
-                    var tdSize = Element.getDimensions(td);
-                    if (tdSize.height > actualRowHeight) {
-                        actualRowHeight = tdSize.height;
-                    }
-                }
-                /* some notes about row sizing
-                 * In Safari, the height of a TR is always returned as 0
-                 * In Safari, the height of any given TD is the height it would
-                 * render at, not the actual height of the row
-                 * In IE, the height is returned 1px bigger than any other browser
-                 * Firefox just works
-                 *
-                 * So, for Safari, we have to measure every TD and take the highest one
-                 * and if its IE, we subtract 1 from the overall height, making all
-                 * browsers identical
-                 *
-                 * Using document.all is not a good hack for this
-                 */
-                if (document.all) {
-                    actualRowHeight -= 1;
-                }
-                if (this.showRowHeader) {
-                    this.setRowHeaderHeight(j, actualRowHeight);                    
-                }
-                /* if we apply the class before adding content, it
-                 * causes a rendering error in IE (off by 1) that is 'fixed'
-                 * when another class is applied to the row, causing dynamic
-                 * shifting of the row heights
-                 */
-                if (this.bAlternateRowColors) {
-                    tr.className = (j%2) ? 'jxGridRowOdd' : 'jxGridRowEven';
-                } else {
-                    tr.className = 'jxGridRowAll';
-                }
-            }
-            
-        }
-    },
-    
-    /**
-     * Method: setRowHeaderHeight
-     * set the height of a row.  This is used internally to adjust the height of
-     * the row header when cell contents wrap.  A limitation of the table structure
-     * is that overflow: hidden on a td will work horizontally but not vertically
-     *
-     * Parameters:
-     * row - {Integer} the row to set the height for
-     * height - {Integer} the height to set the row (in pixels)
-     */
-    setRowHeaderHeight: function(row, height) {
-        //this.rowTableHead.childNodes[row+1].childNodes[0].style.height = (height) + 'px';
-        this.rowTableHead.childNodes[row+1].childNodes[0].childNodes[0].style.height = (height) + 'px';
-    },
-    
-    /**
-     * Method: gridChanged
-     * called through the grid listener interface when data has changed in the
-     * underlying model
-     *
-     * Parameters:
-     * model - {Object} the model that changed
-     * row - {Integer} the row that changed
-     * col - {Integer} the column that changed
-     * value - {Mixed} the new value
-     */
-    gridChanged: function(model, row, col, value) {
-        if (this.model == model) {
-            this.gridObj.childNodes[row].childNodes[col].innerHTML = value;
-        }
-    },
-    
-    /** 
-     * Method: prelightRowHeader
-     * apply the jxGridRowHeaderPrelight style to the header cell of a row.
-     * This removes the style from the previously pre-lit row header.
-     * 
-     * Parameters:
-     * row - {Integer} the row to pre-light the header cell of
-     */
-    prelightRowHeader: function(row) {
-        var cell = (row >= 0 && row < this.rowTableHead.rows.length-1) ? this.rowTableHead.rows[row+1].cells[1] : null;
-        if (this.prelitRowHeader != cell) {
-            if (this.prelitRowHeader) {
-                Element.removeClassName(this.prelitRowHeader, 'jxGridRowHeaderPrelight');
-            }
-            this.prelitRowHeader = cell;
-            if (this.prelitRowHeader) {
-                Element.addClassName(this.prelitRowHeader, 'jxGridRowHeaderPrelight');
-            }
-        }
-    },
-    
-    /** 
-     * Method: prelightColumnHeader
-     * apply the jxGridColumnHeaderPrelight style to the header cell of a column.
-     * This removes the style from the previously pre-lit column header.
-     * 
-     * Parameters:
-     * col - {Integer} the column to pre-light the header cell of
-     */
-    prelightColumnHeader: function(col) {
-        if (this.colTableBody.rows.length == 0) {
-            return;
-        }
-        var cell = (col >= 0 && col < this.colTableBody.rows[0].cells.length-1) ? this.colTableBody.rows[0].cells[col+1] : null;
-        if (this.prelitColumnHeader != cell) {
-            if (this.prelitColumnHeader) {
-                Element.removeClassName(this.prelitColumnHeader, 'jxGridColumnHeaderPrelight');
-            }
-            this.prelitColumnHeader = cell;
-            if (this.prelitColumnHeader) {
-                Element.addClassName(this.prelitColumnHeader, 'jxGridColumnHeaderPrelight');
-            }
-        }
-    },
-    
-    /** 
-     * Method: prelightRow
-     * apply the jxGridRowPrelight style to row.
-     * This removes the style from the previously pre-lit row.
-     * 
-     * Parameters:
-     * row - {Integer} the row to pre-light
-     */
-    prelightRow: function(row) {
-        var tr = (row >= 0 && row < this.gridTableBody.rows.length-1) ? this.gridTableBody.rows[row+1] : null;
-        
-        if (this.prelitRow != row) {
-            if (this.prelitRow) {
-                Element.removeClassName(this.prelitRow, 'jxGridRowPrelight');
-            }
-            this.prelitRow = tr;
-            if (this.prelitRow && !Element.hasClassName(this.prelitRow, 'jxGridRowSelected')) {
-                this.prelightRowHeader(row);
-                Element.addClassName(this.prelitRow, 'jxGridRowPrelight');
-            }
-        }
-    },
-    
-    /** 
-     * Method: prelightColumn
-     * apply the jxGridColumnPrelight style to a column.
-     * This removes the style from the previously pre-lit column.
-     * 
-     * Parameters:
-     * col - {Integer} the column to pre-light
-     *
-     * TODO: Jx.Grid.prelightColumn
-     * Not Yet Implemented.
-     */
-    prelightColumn: function(col) {
-        /* TODO: Jx.Grid.prelightColumn
-         * implement column prelighting (possibly) 
-         */
-        this.prelightColumnHeader(col);
-    },
-    
-    /** 
-     * Method: prelightCell
-     * apply the jxGridCellPrelight style to a cell.
-     * This removes the style from the previously pre-lit cell.
-     *
-     * Parameters:
-     * row - {Integer} the row of the cell to pre-light
-     * col - {Integer} the column of the cell to pre-light
-     */
-    prelightCell: function(row, col) {
-         var td = (row >=0 && col >=0 && row < this.gridTableBody.rows.length - 1 && col < this.gridTableBody.rows[row+1].cells.length - 1) ? this.gridTableBody.rows[row+1].cells[col+1] : null;
-        if (this.prelitCell != td) {
-            if (this.prelitCell) {
-                Element.removeClassName(this.prelitCell, 'jxGridCellPrelight');
-            }
-            this.prelitCell = td;
-            if (this.prelitCell) {
-                Element.addClassName(this.prelitCell, 'jxGridCellPrelight');
-                this.prelightRow(row);
-                this.prelightColumn(col);
-            }
-        }    
-    },
-    
-    /** 
-     * Method: selectCell
-     * Select a cell and apply the jxGridCellSelected style to it.
-     * This deselects a previously selected cell.
-     *
-     * If the model supports cell selection, it should implement
-     * a cellSelected function to receive notification of the selection.
-     *
-     * Parameters:
-     * row - {Integer} the row of the cell to select
-     * col - {Integer} the column of the cell to select
-     */
-    selectCell: function(row, col) {
-         var td = (row >=0 && col >=0 && row < this.gridTableBody.rows.length - 1 && col < this.gridTableBody.rows[row+1].cells.length - 1) ? this.gridTableBody.rows[row+1].cells[col+1] : null;
-         if (!td) {
-             return;
-         }
-         
-         if (this.selectedCell) {
-             Element.addClassName(this.selectedCell, 'jxGridCellSelected');
-         } else {
-             Element.removeClassName(this.selectedCell, 'jxGridCellSelected');
-         }
-    },
-    
-    /** 
-     * Method: selectRowHeader
-     * Apply the jxGridRowHeaderSelected style to the row header cell of a
-     * selected row.
-     *
-     * Parameters:
-     * row - {Integer} the row header to select
-     * selected - {Boolean} the new state of the row header
-     */
-    selectRowHeader: function(row, selected) {
-        var cell = (row >= 0 && row < this.rowTableHead.rows.length-1) ? this.rowTableHead.rows[row+1].cells[1] : null;
-        if (!cell) {
-            return;
-        }
-        if (selected) {
-            Element.addClassName(cell, 'jxGridRowHeaderSelected');
-        } else {
-            Element.removeClassName(cell, 'jxGridRowHeaderSelected');
-        }
-    },
-    
-    /** 
-     * Method: selectRow
-     * Select a row and apply the jxGridRowSelected style to it.
-     *
-     * If the model supports row selection, it should implement
-     * a rowSelected function to receive notification of the selection.
-     *
-     * Parameters:
-     * row - {Integer} the row to select
-     * selected - {Boolean} the new state of the row
-     */
-    selectRow: function(row, selected) {
-        var tr = (row >= 0 && row < this.gridTableBody.rows.length - 1) ? this.gridTableBody.rows[row+1] : null;
-        if (tr) {
-            if (selected) {
-                Element.addClassName(tr, 'jxGridRowSelected');
-            } else {
-                Element.removeClassName(tr, 'jxGridRowSelected');
-            }
-        }
-        this.selectRowHeader(row, selected);
-    },
-    
-    /** 
-     * method: selectColumnHeader
-     * Apply the jxGridColumnHeaderSelected style to the column header cell of a
-     * selected column.
-     *
-     * Parameters:
-     * col - {Integer} the column header to select
-     * selected - {Boolean} the new state of the column header
-     */
-    selectColumnHeader: function(col, selected) {
-        if (this.colTableBody.rows.length == 0) {
-            return;
-        }
-        var cell = (col >= 0 && col < this.colTableBody.rows[0].cells.length-1) ? this.colTableBody.rows[0].cells[col+1] : null;
-        if (cell == null) { 
-            return; 
-        }
-        
-        if (selected) {
-            Element.addClassName(cell, 'jxGridColumnHeaderSelected');
-        } else {
-            Element.removeClassName(cell, 'jxGridColumnHeaderSelected');
-        }
-    },
-    
-    /** 
-     * Method: selectColumn
-     * Select a column.
-     * This deselects a previously selected column.
-     *
-     * Parameters:
-     * col - {Integer} the column to select
-     * selected - {Boolean} the new state of the column
-     */
-    selectColumn: function(col, selected) {
-        /* todo: implement column selection */
-        if (col >= 0 && col < this.gridTable.rows[0].cells.length) {
-            if (selected) {
-                for (var i=0; i<this.gridTable.rows.length; i++) {
-                    Element.removeClassName(this.gridTable.rows[i].cells[this.selectedColumn + 1], 'jxGridColumnSelected');
-                }
-            } else {
-                for (var i=0; i<this.gridTable.rows.length; i++) {
-                    Element.addClassName(this.gridTable.rows[i].cells[col+1], 'jxGridColumnSelected');
-                }
-                
-            }
-        }
-        this.selectColumnHeader(col, selected);
-    },
-    
-    /**
-     * Method: onMouseMoveGrid
-     * handle the mouse moving over the main grid.  This pre-lights the cell,
-     * and subsquently the row and column (and headers).
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onMouseMoveGrid: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        this.prelightCell(rc.row, rc.column);
-    },
-    
-    /**
-     * Method: onMouseMoveRowHeader
-     * handle the mouse moving over the row header cells.  This pre-lights
-     * the row and subsequently the row header.
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onMouseMoveRowHeader: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        this.prelightRow(rc.row);
-    },
-
-    /**
-     * Method: onMouseMoveColumnHeader
-     * handle the mouse moving over the column header cells.  This pre-lights
-     * the column and subsequently the column header.
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onMouseMoveColumnHeader: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        this.prelightColumn(rc.column);
-    },
-    
-    /**
-     * Method: onClickGrid
-     * handle the user clicking on the grid.  This triggers an
-     * event to the model (if a cellSelected function is provided).
-     *
-     * The following is an example of a function in the model that selects
-     * a row when the cellSelected function is called and deselects any rows
-     * that are currently selected.
-     *
-     * (code)
-     * cellSelected: function(grid, row,col) { 
-     *    if (this.selectedRow != null) {
-     *        grid.selectRow(this.selectedRow, false);
-     *    }
-     *    this.selectedRow = row;
-     *    grid.selectRow(row, true);
-     * }
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onClickGrid: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        //this.selectCell(rc.row, rc.column);
-        
-        if (this.model.cellSelected) {
-            this.model.cellSelected(this, rc.row, rc.column);
-        }
-    },
-    
-    /**
-     * Method: onClickRowHeader
-     * handle the user clicking on the row header.  This triggers an
-     * event to the model (if a rowSelected function is provided) which
-     * can then select the row if desired.  
-     *
-     * The following is an example of a function in the model that selects
-     * a row when the rowSelected function is called and deselects any rows
-     * that are currently selected.  More complex code could be written to 
-     * allow the user to select multiple rows.
-     *
-     * (code)
-     * rowSelected: function(grid, row) {
-     *    if (this.selectedRow != null) {
-     *        grid.selectRow(this.selectedRow, false);
-     *    }
-     *    this.selectedRow = row;
-     *    grid.selectRow(row, true);
-     * }
-     * (end)
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onClickRowHeader: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        
-        if (this.model.rowSelected) {
-            this.model.rowSelected(this, rc.row);
-        }
-    },
-    
-    /**
-     * Method: onClickColumnHeader
-     * handle the user clicking on the column header.  This triggers column
-     * selection and column (and header) styling changes and an
-     * event to the model (if a columnSelected function is provided)
-     *
-     * The following is an example of a function in the model that selects
-     * a column when the columnSelected function is called and deselects any 
-     * columns that are currently selected.  More complex code could be written
-     * to allow the user to select multiple columns.
-     *
-     * (code)
-     * colSelected: function(grid, col) {
-     *    if (this.selectedColumn != null) {
-     *        grid.selectColumn(this.selectedColumn, false);
-     *    }
-     *    this.selectedColumn = col;
-     *    grid.selectColumn(col, true);
-     * }
-     * (end)
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     */
-    onClickColumnHeader: function(e) {
-        var rc = this.getRowColumnFromEvent(e);
-        
-        if (this.model.columnSelected) {
-            this.model.columnSelected(this, rc.column);
-        }
-    },
-    
-    /**
-     * method: getRowColumnFromEvent
-     * retrieve the row and column indexes from an event click.
-     * This function is used by the grid, row header and column
-     * header to safely get these numbers.
-     *
-     * If the event isn't valid (i.e. it wasn't on a TD or TH) then
-     * the returned values will be -1, -1
-     *
-     * Parameters:
-     * e - {Event} the browser event object
-     *
-     * @return Object an object with two properties, row and column,
-     *         that contain the row and column that was clicked
-     */
-    getRowColumnFromEvent: function(e) {
-        var td = Event.element(e);
-        if (td.tagName != 'TD' && td.tagName != 'TH') {
-            return {row:-1,column:-1};
-        }
-        var tr = td.parentNode;
-        var col = td.cellIndex - 1; /* because of hidden spacer column */
-        var row = tr.rowIndex - 1; /* because of hidden spacer row */
-        
-        if (col == -1) { 
-            /* bug in safari returns 0 for cellIndex - only choice seems
-             * to be to loop through the row
-             */
-            for (var i=0; i<tr.childNodes.length; i++) {
-                if (tr.childNodes[i] == td) {
-                    col = i - 1;
-                    break;
-                }
-            }
-        }
-        return {row:row,column:col};
-    }
-};/**
- * $Id: jxlayout.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Layout
- *
- * Purpose: 
- * Implementation of a javascript layout engine for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-/**
- * Class: Jx.Layout
- *
- * Jx.Layout is used to provide more flexible layout options for applications
- *
- * Jx.Layout wraps an existing DOM element (typically a div) and provides
- * extra functionality for sizing that element within its parent and sizing
- * elements contained within it that have a 'resize' function attached to them.
- *
- * To create a Jx.Layout, pass the element or id plus an options object to
- * the constructor:
- *
- * (code)
- * var myContainer = new Jx.Layout('myDiv', options);
- * (end)
- *
- * Inherits From:
- * <Jx.Listener>
- */
- 
-Jx.Layout = Class.create();
-Jx.Layout.prototype = {
-    scl: null,
-    /**
-     * Constructor: Jx.Layout
-     * Create a new instance of Jx.Layout.
-     *
-     * Parameters:
-     * domObj - {HTMLElement} element or id to apply the layout to
-     * options - {Object} options can be passed to the Jx.Layout as an object
-     * with some, all, or none of the options below.
-     *
-     * Options:
-     * position - how to position the element, either 'absolute' or 'relative'.
-     *    The default (if not passed) is 'absolute'.  When using
-     *    'absolute' positioning, both the width and height are
-     *    controlled by Jx.Layout.  If 'relative' positioning is used
-     *    then only the width is controlled, allowing the height to
-     *    be controlled by its content.
-     * left - the distance (in pixels) to maintain the left edge of the element
-     *    from its parent element.  The default value is 0.  If this is set
-     *    to 'null', then the left edge can be any distance from its parent
-     *    based on other parameters.
-     * right - the distance (in pixels) to maintain the right edge of the element
-     *    from its parent element.  The default value is 0.  If this is set
-     *    to 'null', then the right edge can be any distance from its parent
-     *    based on other parameters.
-     * top - the distance (in pixels) to maintain the top edge of the element
-     *    from its parent element.  The default value is 0.  If this is set
-     *    to 'null', then the top edge can be any distance from its parent
-     *    based on other parameters.
-     * bottom - the distance (in pixels) to maintain the bottom edge of the element
-     *    from its parent element.  The default value is 0.  If this is set
-     *    to 'null', then the bottom edge can be any distance from its parent
-     *    based on other parameters.
-     * width - the width (in pixels) of the element.  The default value is null.
-     *    If this is set to 'null', then the width can be any value based on
-     *    other parameters.
-     * height - the height (in pixels) of the element.  The default value is null.
-     *    If this is set to 'null', then the height can be any value based on
-     *    other parameters.
-     * minWidth - the minimum width that the element can be sized to.  The default
-     *    value is 0.
-     * minHeight - the minimum height that the element can be sized to.  The
-     *    default value is 0.
-     * maxWidth - the maximum width that the element can be sized to.  The default
-     *    value is -1, which means no maximum.
-     * maxHeight - the maximum height that the element can be sized to.  The
-     *    default value is -1, which means no maximum.
-     */
-    initialize: function(domObj, options) {
-        options = options || {};
-        this.options = new Jx.Constraint(options);
-        this.domObj = $(domObj);
-        this.domObj.resize = this.resize.bind(this);
-        this.domObj.style.position = this.options.position;
-        this.domObj.jxLayout = this;
-
-        if (this.domObj.parentNode && this.domObj.parentNode.tagName == 'BODY') {
-            Event.observe(window, 'resize', this.windowResize.bind(this));
-        }
-        
-        this.scl = [];
-    },
-    
-    /**
-     * Method: windowResize
-     * when the window is resized, any Jx.Layout controlled elements that are
-     * direct children of the BODY element are resized
-     */
-     windowResize: function() {
-        if (this.resizeTimer) {
-            window.clearTimeout(this.resizeTimer);
-            this.resizeTimer = null;
-        }
-        this.resizeTimer = window.setTimeout(this.resize.bind(this), 250);
-    },
-    
-    /**
-     * Method: resize
-     * resize the element controled by this Jx.Layout object.
-     *
-     * Parameters:
-     * options - new options to apply, see <Jx.Layout::Jx.Layout>
-     */
-     resize: function(options) {
-        this.resizeTimer = null;
-        var needsResize = false;
-        if (options) {
-            for (var i in options) {
-                if (this.options[i] != options[i]) {
-                    needsResize = true;
-                    this.options[i] = options[i];
-                }
-            }
-            if (options.forceResize) {
-                needsResize = true;
-            }
-        }
-        
-        
-        var parentSize;
-        if (this.domObj.parentNode.tagName == 'BODY') {
-            parentSize = Element.getPageDimensions();
-        } else {
-            parentSize = Element.getContentBoxSize(this.domObj.parentNode);
-        }
-        
-        if (this.lastParentSize && !needsResize) {
-            needsResize = (this.lastParentSize.width != parentSize.width || 
-                          this.lastParentSize.height != parentSize.height);
-        } else {
-            needsResize = true;
-        }
-        this.lastParentSize = parentSize;
-        
-        if (!needsResize) {
-            return;
-        }
-        
-        var l, t, w, h;
-        
-        /* calculate left and width */
-        if (this.options.left != null) {
-            /* fixed left */
-            l = this.options.left;
-            if (this.options.right == null) {
-                /* variable right */
-                if (this.options.width == null) {
-                    //console.log( 'fixed left, variable right, variable width' );
-                    /* variable right and width
-                     * set right to min, stretch width */
-                    w = parentSize.width - l;
-                    if (w < this.options.minWidth ) {
-                        w = this.options.minWidth;
-                    }
-                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
-                        w = this.options.maxWidth;
-                    }
-                } else {
-                    //console.log( 'fixed left, variable right, fixed width' );
-                    /* variable right, fixed width
-                     * use width
-                     */
-                    w = this.options.width;
-                }
-            } else {
-                /* fixed right */
-                if (this.options.width == null) {
-                    //console.log( 'fixed left, fixed right, variable width' );
-                    
-                    /* fixed right, variable width
-                     * stretch width
-                     */
-                    w = parentSize.width - l - this.options.right;
-                    if (w < this.options.minWidth) {
-                        w = this.options.minWidth;
-                    }
-                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
-                        w = this.options.maxWidth;
-                    }
-                } else {
-                    //console.log( 'fixed left, fixed right, fixed width' );
-                    
-                    /* fixed right, fixed width
-                     * respect left and width, allow right to stretch
-                     */
-                    w = this.options.width;
-                }
-            }
-            
-        } else {
-            if (this.options.right == null) {
-                if (this.options.width == null) {
-                    //console.log( 'variable left, variable right, variable width' );
-                    
-                    /* variable left, width and right
-                     * set left, right to min, stretch width
-                     */
-                     l = 0;
-                     w = parentSize.width;
-                     if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
-                         l = l + parseInt(w - this.options.maxWidth)/2;
-                         w = this.options.maxWidth;
-                     }
-                } else {
-                    //console.log( 'variable left, variable right, fixed width' );
-                    
-                    /* variable left, fixed width, variable right
-                     * distribute space between left and right
-                     */
-                    w = this.options.width;
-                    l = parseInt((parentSize.width - w)/2);
-                    if (l < 0) {
-                        l = 0;
-                    }
-                }
-            } else {
-                if (this.options.width != null) {
-                    //console.log( 'variable left, fixed right, fixed width' );
-                    
-                    /* variable left, fixed width, fixed right
-                     * left is calculated directly
-                     */
-                    w = this.options.width;
-                    l = parentSize.width - w - this.options.right;
-                    if (l < 0) {
-                        l = 0;
-                    }
-                } else {
-                    //console.log( 'variable left, fixed right, variable width' );
-                    
-                    /* variable left and width, fixed right
-                     * set left to min value and stretch width
-                     */
-                    l = 0;
-                    w = parentSize.width - this.options.right;
-                    if (w < this.options.minWidth) {
-                        w = this.options.minWidth;
-                    }
-                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
-                        l = w - this.options.maxWidth - this.options.right;
-                        w = this.options.maxWidth;                        
-                    }
-                }
-            }
-        }
-        
-        /* calculate the top and height */
-        if (this.options.top != null) {
-            /* fixed top */
-            t = this.options.top;
-            if (this.options.bottom == null) {
-                /* variable bottom */
-                if (this.options.height == null) {
-                    //console.log( 'fixed top, variable bottom, variable height' );
-                    
-                    /* variable bottom and height
-                     * set bottom to min, stretch height */
-                    h = parentSize.height - t;
-                    if (h < this.options.minHeight) {
-                        h = this.options.minHeight;
-                    }
-                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
-                        h = this.options.maxHeight;
-                    }
-                } else {
-                    //console.log( 'fixed top, variable bottom, fixed height' );
-                    
-                    /* variable bottom, fixed height
-                     * stretch height
-                     */
-                    h = this.options.height;
-                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
-                        t = h - this.options.maxHeight;
-                        h = this.options.maxHeight;
-                    }
-                }
-            } else {
-                /* fixed bottom */
-                if (this.options.height == null) {
-                    //console.log( 'fixed top, fixed bottom, variable height' );
-                    
-                    /* fixed bottom, variable height
-                     * stretch height
-                     */
-                    h = parentSize.height - t - this.options.bottom;
-                    if (h < this.options.minHeight) {
-                        h = this.options.minHeight;
-                    }
-                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
-                        h = this.options.maxHeight;
-                    }                
-                } else {
-                    //console.log( 'fixed top, fixed bottom, fixed height' );
-                    
-                    /* fixed bottom, fixed height
-                     * respect top and height, allow bottom to stretch
-                     */
-                    h = this.options.height;
-                }
-            }
-            
-        } else {
-            if (this.options.bottom == null) {
-                if (this.options.height == null) {
-                    //console.log( 'variable top, variable bottom, variable height' );
-                    
-                    /* variable top, height and bottom
-                     * set top, bottom to min, stretch height
-                     */
-                     t = 0;
-                     h = parentSize.height;
-                     if (h < this.options.minHeight) {
-                         h = this.options.minHeight;
-                     }
-                     if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
-                         t = parseInt((parentSize.height - this.options.maxHeight)/2);
-                         h = this.options.maxHeight;
-                     }
-                } else {
-                    //console.log( 'variable top, variable bottom, fixed height' );
-                    
-                    /* variable top, fixed height, variable bottom
-                     * distribute space between top and bottom
-                     */
-                    h = this.options.height;
-                    t = parseInt((parentSize.height - h)/2);
-                    if (t < 0) {
-                        t = 0;
-                    }
-                }
-            } else {
-                if (this.options.height != null) {
-                    //console.log( 'variable top, fixed bottom, fixed height' );
-                    
-                    /* variable top, fixed height, fixed bottom
-                     * top is calculated directly
-                     */
-                    h = this.options.height;
-                    t = parentSize.height - h - this.options.bottom;
-                    if (t < 0) {
-                        t = 0;
-                    }
-                } else {
-                    //console.log( 'variable top, fixed bottom, variable height' );
-                    
-                    /* variable top and height, fixed bottom
-                     * set top to min value and stretch height
-                     */
-                    t = 0;
-                    h = parentSize.height - this.options.bottom;
-                    if (h < this.options.minHeight) {
-                        h = this.options.minHeight;
-                    }
-                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
-                        t = parentSize.height - this.options.maxHeight - this.options.bottom;
-                        h = this.options.maxHeight;
-                    }
-                }
-            }
-        }
-                
-        this.domObj.style.position = this.options.position;
-        if (this.options.position == 'absolute') {
-            var padding = Element.getPaddingSize(this.domObj.parentNode);
-        
-            this.domObj.style.left = (l+padding.left) + 'px';
-            this.domObj.style.top = (t+padding.top) + 'px';
-            Element.setBorderBoxSize(this.domObj, {width: w, height: h} );
-        } else {
-            var sizeOpts = {width: w};
-            if (this.options.height) {
-                sizeOpts.height = this.options.height;
-            }
-            Element.setBorderBoxSize(this.domObj, sizeOpts);
-        }
-        
-        var o = {forceResize: options ? options.forceResize : false};
-        for (var i=0; i<this.domObj.childNodes.length; i++) {
-            var c = this.domObj.childNodes[i];
-            if (c.resize) {
-                c.resize(o);
-            }
-        }
-        this.processEvent(this.scl,'sizeChanged',this);
-    },
-    /**
-     * Method: addSizeChangeListener
-     * add a size change listener to be notified when the size of the
-     * element changes.
-     *
-     * Parameters:
-     * obj - {Object} a size change listener
-     */
-     addSizeChangeListener: function(obj){this.addListener(this.scl, obj);},
-    /**
-     * Method: removeSizeChangeListener
-     * remove a size change listener 
-     *
-     * Parameters:
-     * obj - {Object} a size change listener
-     */
-     removeSizeChangeListener: function(o) {
-        this.removeListener(this.scl, o);
-    }
-};
-Object.extend(Jx.Layout.prototype, Jx.Listener.prototype);
-
-/**
- * Class: Jx.Constraint
- * A utility class used with <Jx.Layout> to represent the current
- * set of constraints on an element.  This object is not intended
- * to be instantiated directly by a user
- */
-Jx.Constraint = Class.create();
-Jx.Constraint.prototype = {
-    position: 'absolute',
-    left: 0,
-    right: 0,
-    top: 0,
-    bottom: 0,
-    width: null,
-    height: null,
-    minWidth: 0,
-    minHeight: 0,
-    maxWidth: -1,
-    maxHeight: -1,
-    initialize: function(o) {
-        for( var i in o ) {
-            this[i] = o[i];
-        }
-    }
-};/**
- * $Id: jxmenu.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Menu
- *
- * Purpose: 
- * Implementation of a javascript menuing system for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-
- Jx.addStyleSheet('menu/menu.css');
- Jx.addStyleSheet('button/button.css');
-
-/**
- * Class: Jx.MenuItem
- * A menu item is a single entry in a menu.  It is typically composed of
- * a label and an optional icon.  Selecting the menu item triggers an
- * action.
- */
-Jx.MenuItem = Class.create();
-Object.extend(Jx.MenuItem.prototype, Jx.Listener.prototype);
-Object.extend(Jx.MenuItem.prototype, {
-    /**
-     * Property: al
-     * {Array} action listeners
-     */
-    al: null,
-    /**
-     * Property: domObj
-     * {HTMLElement} the HTML element for this menu item.
-     */
-    domObj: null,
-    /**
-     * Property: parent
-     * {<Jx.SubMenu> or <Jx.Menu>} the menu that contains the menu item.
-     */
-    parent: null,
-    /**
-     * Property: enabled
-     * {Boolean} whether the menu item is enabled or not
-     */
-    enabled: false,
-    /**
-     * Property: button
-     * {<Jx.Button>} the clickable part of the menu item is managed as a
-     * <Jx.Button>
-     */
-    button: null,
-    /**
-     * Constructor: Jx.MenuItem
-     * Create a new instance of Jx.MenuItem
-     *
-     * Parameters:
-     * action - {<Jx.Action>} the action to invoke when the menu item is
-     *          invoked
-     * options - {Object} an object containing options as below.
-     * 
-     * Options:
-     * image - {String} URL to an image to use as an icon on this menu item
-     * label - {String} the label for the menu item.
-     */
-    initialize: function(action, options) {
-        this.initializeItem(options);
-        action.bindTo(this);
-        this.propertyChanged(action);
-    },
-    /**
-     * Method: initializeItem
-     * Internal method to initalize the button for this menu item.
-     *
-     * Parameters:
-     * options - {Object} an object containing options as below.
-     *
-     * Options:
-     * image - {String} URL to an image to use as an icon on this menu item
-     * label - {String} the label for the menu item.     */
-    initializeItem: function(options) { 
-        if (!options.image) {
-            options.image = Jx.baseURL + 'images/a_pixel.png';
-        }
-        if (!options.label) {
-            options.label = '&nbsp;';
-        }
-        this.label = options.label || '&nbsp;';
-        this.image = options.image || null;
-        
-        this.al = [];
-        this.domObj = document.createElement('li');
-        this.domObj.className = 'jxMenuItem';
-        
-        /* menu items are buttons without the jxButton class */
-        var action = new Jx.Action(this.processActionEvent.bindAsEventListener(this))
-        this.button = new Jx.Button(action, options);
-        //Element.removeClassName(this.button.domA, 'jxButton');
-        
-        Event.observe(this.button.domObj, 'mouseover', this.onmouseover.bindAsEventListener(this), true);
-        
-        this.domObj.appendChild(this.button.domObj);
-    },
-    /**
-     * Method: setParent
-     * Set the parent of this menu item
-     *
-     * Parameters:
-     * obj - {Object} the new parent
-     */
-    setParent: function(obj) {
-        this.parent = obj;
-    },
-    /**
-     * Method: hide
-     * Hide the menu item.
-     */
-    hide: function() {},
-    /**
-     * Method: show
-     * Show the menu item
-     */
-    show: function() {},
-    /**
-     * Method: addActionListener
-     * Add an action listener to this menu item
-     *
-     * Parameters:
-     * obj - {Object} the action listener
-     */
-    addActionListener: function(obj) { this.addListener(this.al,obj); },
-    /**
-     * Method: removeActionListener
-     * Remove an action listener from this menu item
-     *
-     * Parameters:
-     * obj - {Object} the action listener
-     */
-    removeActionListener : function(obj) { this.removeListener(this.al, obj); },
-    /**
-     * Method: processActionEvent
-     * Process an action event by informing any action listeners that the action
-     * associated with this menu item and hiding the menu.
-     *
-     * Parameters:
-     * e - {Event} the event associated with the user clicking on the menu item
-     */
-    processActionEvent: function(e) { 
-        if (this.enabled) {
-            this.processEvent(this.al, 'actionPerformed', this);
-            if (this.parent && this.parent.deactivate) {
-                this.parent.deactivate(e);
-            }
-        }
-    },
-    /**
-     * Method: propertyChanged
-     * Track when a property of the action changes and update the state of the
-     * menu item accordingly.
-     *
-     * Parameters:
-     * obj - {<Jx.Action>} the action object
-     */
-    propertyChanged: function(obj) {
-        this.enabled = obj.isEnabled();
-        if (this.enabled) {
-            Element.removeClassName( this.domObj.childNodes[0].childNodes[0], 'jxDisabled' );
-        } else {
-            Element.addClassName( this.domObj.childNodes[0].childNodes[0], 'jxDisabled' );
-        }
-    },
-    /**
-     * Method: onmouseover
-     * handle the mouse moving over the menu item
-     *
-     * Parameters:
-     * e - {Event} the mousemove event
-     */
-    onmouseover: function(e) {
-        var target = Event.element(e);
-        if (this.parent && this.parent.setVisibleItem) {
-            this.parent.setVisibleItem(this);
-        }
-        this.show();
-    }
-});
-
-/**
- * Class: Jx.MenuSeparator
- * A convenience class to create a visual separator in a menu.
- */
-Jx.MenuSeparator = Class.create();
-Object.extend(Jx.MenuSeparator.prototype, {
-    /**
-     * Property: domObj
-     * {HTMLElement} the HTML element that the separator is contained
-     * within
-     */
-    domObj: null,
-    /**
-     * Property: parent
-     * {<Jx.Menu>, <Jx.SubMenu>} the menu that the separator is in.
-     */
-    parent: null,
-    /**
-     * Constructor: Jx.MenuSeparator
-     * Create a new instance of a menu separator
-     */
-    initialize: function() {
-        this.domObj = document.createElement('li');
-        this.domObj.className = 'jxMenuItem';
-        var span = document.createElement('span');
-        span.className = 'jxMenuSeparator';
-        span.innerHTML = '&nbsp;';
-        this.domObj.appendChild(span);
-    },
-    /**
-     * Method: setParent
-     * Set the parent of this menu item
-     *
-     * Parameters:
-     * obj - {Object} the new parent
-     */
-    setParent: function(obj) {
-        this.parent = obj;
-    },
-    /**
-     * Method: hide
-     * Hide the menu item.
-     */
-    hide: function() {},
-    /**
-     * Method: show
-     * Show the menu item
-     */
-    show: function() {}
-});
-
-/**
- * Class: Jx.SubMenu
- * A sub menu contains menu items within a main menu or another
- * sub menu.
- *
- * Inherits From:
- * <Jx.MenuItem>
- */
-Jx.SubMenu = Class.create();
-Object.extend(Jx.SubMenu.prototype, Jx.MenuItem.prototype);
-Object.extend(Jx.SubMenu.prototype, {
-    /**
-     * Property: subDomObj
-     * {HTMLElement} the HTML container for the sub menu.
-     */
-    subDomObj: null,
-    /**
-     * Property: parent
-     * {<Jx.Menu> or <Jx.SubMenu>} the menu or sub menu that this sub menu
-     * belongs
-     */
-    parent: null,
-    /**
-     * Property: visibleItem
-     * {<Jx.MenuItem>} the visible item within the menu
-     */
-    visibleItem: null,
-    /**
-     * Property: items
-     * {Array} the menu items that are in this sub menu.
-     */
-    items: null,
-    /**
-     * Constructor: Jx.SubMenu
-     * Create a new instance of Jx.SubMenu
-     *
-     * Parameters:
-     * options - see <Jx.MenuItem::Jx.MenuItem>
-     */
-    initialize: function(options) { 
-        this.open = false;
-        this.items = [];
-        this.initializeItem(options);
-        Element.addClassName(this.domObj.childNodes[0].childNodes[0], 'jxButtonSubMenu');
-        
-        this.iframe = document.createElement('iframe');
-        this.iframe.className = 'jxMenuShim';
-        this.iframe.scrolling = 'no';
-        this.iframe.frameborder = 0;
-        
-        this.subDomObj = document.createElement('ul');
-        this.subDomObj.className = 'jxSubMenu';
-        this.subDomObj.style.display = 'none';
-        
-        // this.button.domObj.appendChild(this.subDomObj);
-        this.domObj.appendChild(this.subDomObj);
-    },
-    /**
-     * Method: setParent
-     * Set the parent of this sub menu
-     *
-     * Parameters:
-     * obj - {Object} the parent
-     */
-    setParent: function(obj) {
-        this.parent = obj;
-    },
-    /**
-     * Method: show
-     * Show the sub menu
-     */
-    show: function() {
-        if (this.open || this.items.length == 0) {
-            return;
-        }
-
-        this.open = true;
-        this.subDomObj.style.display = 'block';
-        if (!window.opera) {
-            this.subDomObj.childNodes[0].appendChild(this.iframe);
-            var size = Element.getBorderBoxSize(this.subDomObj);
-            this.iframe.style.width = size.width + "px";
-            this.iframe.style.height = size.height + "px";
-            
-        }
-        this.setActive(true);
-    },
-    /**
-     * Method: hide
-     * Hide the sub menu
-     */
-    hide: function() {
-        if (!this.open) {
-            return;
-        }
-        this.open = false;
-        for (var i=0; i<this.items.length; i++) {
-            this.items[i].hide();
-        }
-        this.subDomObj.style.display = 'none';
-        if (!window.opera && this.iframe.parentNode) {
-            this.subDomObj.childNodes[0].removeChild(this.iframe);
-        }
-        this.visibleItem = null;
-    },
-    /**
-     * Method: add
-     * Add menu items to the sub menu.
-     *
-     * Parameters:
-     * item - {<Jx.MenuItem>} the menu item to add.  Multiple menu items
-     * can be added by passing multiple arguments to this function.
-     */
-    add : function() { /* menu */
-        for (var i=0; i<arguments.length; i++) {
-            var item = arguments[i];
-            this.items.push(item);
-            item.setParent(this);
-            this.subDomObj.appendChild(item.domObj);
-        }
-    },
-    /**
-     * Method: insertBefore
-     * Insert a menu item before another menu item.
-     *
-     * Parameters:
-     * newItem - {<Jx.MenuItem>} the menu item to insert
-     * targetItem - {<Jx.MenuItem>} the menu item to insert before
-     */
-    insertBefore: function(newItem, targetItem) {
-        var bInserted = false;
-        for (var i=0; i<this.items.length; i++) {
-            if (this.items[i] == targetItem) {
-                this.items.splice(i, 0, newItem);
-                this.subDomObj.insertBefore(newItem.domObj, targetItem.domObj);
-                bInserted = true;
-                break;
-            }
-        }
-        if (!bInserted) {
-            this.add(newItem);
-        }
-    },
-    /**
-     * Method: remove
-     * Remove a single menu item from the menu.
-     *
-     * Parameters:
-     * item - {<Jx.MenuItem} the menu item to remove.
-     */
-    remove: function(item) {
-        for (var i=0; i<this.items.length; i++) {
-            if (this.items[i] == item) {
-                this.items.splice(i,1);
-                this.subDomObj.removeChild(item.domObj);
-                break;
-            }
-        }
-    },
-    /**
-     * Method: processActionEvent
-     * Process an action event coming from the menu item that
-     * represents the sub menu in its parent by showing or hiding
-     * the sub menu.
-     */
-    processActionEvent: function(e) { 
-        if (this.open) { 
-            this.hide(); 
-        } else { 
-            this.show();
-        }
-        return Event.stop(e);
-    },
-    /**
-     * Method: deactivate
-     * Deactivate the sub menu
-     *
-     * Parameters:
-     * e - {Event} the event that triggered the menu being
-     * deactivated.
-     */
-    deactivate: function(e) {
-        if (this.parent) {
-            this.parent.deactivate(e);            
-        }
-    },
-    /**
-     * Method: isActive
-     * Indicate if this sub menu is active
-     *
-     * Returns:
-     * {Boolean} true if the <Jx.Menu> that ultimately contains
-     * this sub menu is active, false otherwise.
-     */
-    isActive: function() { 
-        if (this.parent) {
-            return this.parent.isActive();
-        } else {
-            return false;
-        }
-    },
-    /**
-     * Method: setActive
-     * Set the active state of the <Jx.Menu> that contains this sub menu
-     *
-     * Parameters:
-     * isActive - {Boolean} the new active state
-     */
-    setActive: function(isActive) { 
-        if (this.parent && this.parent.setActive) {
-            this.parent.setActive(isActive);
-        }
-    },
-    /**
-     * Method: setVisibleItem
-     * Set a sub menu of this menu to be visible and hide the previously
-     * visible one.
-     *
-     * Parameters: 
-     * obj - {<Jx.SubMenu>} the sub menu that should be visible
-     */
-    setVisibleItem: function(obj) {
-        if (this.visibleItem != obj) {
-            if (this.visibleItem && this.visibleItem.hide) {
-                this.visibleItem.hide();
-            }
-            this.visibleItem = obj;
-            this.visibleItem.show();
-        }
-    }
-});
-
-/**
- * Class: Jx.Menu
- * A main menu as opposed to a sub menu that lives inside the menu.
- *
- * TODO: Jx.Menu
- * revisit this to see if Jx.Menu and Jx.SubMenu can be merged into
- * a single implementation.
- */
-Jx.Menu = Class.create();
-Jx.Menu.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} The HTML element containing the menu.
-     */
-    domObj : null,
-    /**
-     * Property: buttonObj
-     * {<Jx.Button>} The button that represents this menu in a toolbar and
-     * opens the menu.
-     */
-    buttonObj : null,
-    /**
-     * Property: subDomObj
-     * {HTMLElement} the HTML element that contains the menu items
-     * within the menu.
-     */
-    subDomObj : null,
-    /**
-     * Property: items
-     * {Array} the items in this menu
-     */
-    items : null,
-    /**
-     * Property: menus
-     * {Array} Class variable that contains a reference to all
-     * menus shared by all menu instances.
-     */
-    menus : [],
-    /**
-     * Constructor: Jx.Menu
-     * Create a new instance of Jx.Menu.
-     *
-     * Parameters:
-     * options - {Object} an options object passed directly to the
-     * <Jx.Button> when creating the button that triggers this menu.
-     * If options is not passed, then no button is created.
-     */
-    initialize : function(options) {
-        /* stores menu items and sub menus */
-        this.items = [];
-        
-        /* iframe shim to prevent scrollbars and 
-           inputs from showing through the menu */
-        this.iframe = document.createElement('iframe');
-        this.iframe.className = 'jxMenuShim';
-        this.iframe.scrolling = 'no';
-        this.iframe.frameborder = 0;
-        
-        /* the DOM element that holds the actual menu */
-        this.subDomObj = document.createElement('ul');
-        this.subDomObj.className = 'jxMenu';
-        this.subDomObj.style.display = 'none';
-        
-        /* if options are passed, make a button inside an LI so the
-           menu can be embedded inside a toolbar */
-        if (options) {
-            this.domObj = document.createElement('li');
-            
-            var action = new Jx.Action(this.show.bind(this));
-            this.button = new Jx.Button(action, options);
-            Element.addClassName(this.button.domObj.firstChild, 'jxButtonMenu');
-            this.domObj.appendChild(this.button.domObj);
-        
-            Event.observe(this.domObj, 'mouseover', this.onMouseOver.bindAsEventListener(this));
-            //this.button.domObj.appendChild(this.subDomObj);
-            this.domObj.appendChild(this.subDomObj);
-        }
-        
-        /* pre-bind the hide function for efficiency */
-        this.hideWatcher = this.hide.bindAsEventListener(this);
-    },
-    /**
-     * Method: add
-     * Add menu items to the sub menu.
-     *
-     * Parameters:
-     * item - {<Jx.MenuItem>} the menu item to add.  Multiple menu items
-     * can be added by passing multiple arguments to this function.
-     */
-    add : function() {
-        for (var i=0; i<arguments.length; i++) {
-            var item = arguments[i];
-            this.items.push(item);
-            item.setParent(this);
-            this.subDomObj.appendChild(item.domObj);
-        }
-    },
-    /**
-     * Method: deactivate
-     * Deactivate the menu by hiding it.
-     */
-    deactivate: function() { this.hide(); },
-    /**
-     * Method: actionPerformed
-     * Any action performed in the menu ultimately calls this
-     * method to hide the menu.
-     */
-    actionPerformed : function() {this.hide();},
-    /**
-     * Method: onMouseOver
-     * Handle the user moving the mouse over the button for this menu
-     * by showing this menu and hiding the other menu.
-     *
-     * Parameters:
-     * e - {Event} the mouse event
-     */
-    onMouseOver: function(e) {
-        if (this.menus[0] && this.menus[0] != this) {
-            this.show(e);
-        }
-    },
-    /**
-     * Method: hide
-     * Hide the menu.
-     *
-     * Parameters:
-     * e - {Event} the mouse event
-     */
-    hide: function(e) {
-        if (e) {
-            var root = Event.findElement(e, 'LI');
-            if (root == this.domObj) {
-                return;
-            }
-        }
-        if (this.menus[0] && this.menus[0] == this) {
-            this.menus[0] = null;
-        }
-        for (var i=0; i<this.items.length; i++) {
-            this.items[i].hide(e);
-        }
-        Event.stopObserving(document, 'click', this.hideWatcher, true);
-        this.subDomObj.style.display = 'none';  
-    },
-    /**
-     * Method: show
-     * Show the menu
-     *
-     * Parameters:
-     * e - {Event} the mouse event
-     */
-    show : function(e) {
-        if (this.menus[0] && this.menus[0] != this) {
-            this.menus[0].hide(e);
-        }
-        if (this.items.length ==0) {
-            return;
-        }
-        this.menus[0] = this;
-        this.subDomObj.style.display = 'block';
-        this.subDomObj.style.visibility = 'visible';
-        
-        if (!window.opera) {
-            this.subDomObj.childNodes[0].appendChild(this.iframe);
-            var size = Element.getContentBoxSize(this.subDomObj);
-            this.iframe.style.width = size.width + "px";
-            this.iframe.style.height = size.height + "px";
-        }
-        Event.stop(e);
-        /* fix bug in IE that closes the menu as it opens because of bubbling */
-        Event.observe(document, 'click', this.hideWatcher, true);
-    },
-    /**
-     * Method: setVisibleItem
-     * Set the sub menu that is currently open
-     *
-     * Parameters:
-     * obj- {<Jx.SubMenu>} the sub menu that just became visible
-     */
-    setVisibleItem: function(obj) {
-        if (this.visibleItem != obj) {
-            if (this.visibleItem && this.visibleItem.hide) {
-                this.visibleItem.hide();
-            }
-            this.visibleItem = obj;
-            this.visibleItem.show();
-        }
-    }
-};
-
-/**
- * Class: Jx.ContextMenu
- * A <Jx.Menu> that has no button but can be opened at a specific 
- * browser location to implement context menus (for instance).
- *
- * Inherits From:
- * <Jx.Menu>
- */
-Jx.ContextMenu = Class.create();
-Object.extend(Jx.ContextMenu.prototype, Jx.Menu.prototype);
-Object.extend(Jx.ContextMenu.prototype, {
-    /**
-     * Constructor: Jx.ContextMenu
-     * create a new context menu
-     *
-     * Parameters:
-     * id - {HTMLElement} element or id to make this the context menu
-     * for.  The menu hooks the oncontextmenu event of the element
-     * and shows itself at the mouse position where the right-click
-     * happened.
-     */
-    initialize : function(id) {
-        Jx.Menu.prototype.initialize.apply(this, []);
-        document.getElementsByTagName('BODY')[0].appendChild(this.subDomObj);
-        if ($(id)) {
-            $(id).oncontextmenu = this.show.bindAsEventListener(this);;
-        }
-    },
-    /**
-     * Method: show
-     * Show the context menu at the location of the mouse click
-     *
-     * Parameters:
-     * e - {Event} the mouse event
-     */
-    show : function(e) {
-        this.subDomObj.style.left = Event.pointerX(e) + "px";
-        this.subDomObj.style.top = Event.pointerY(e) + "px";
-        Jx.Menu.prototype.show.apply(this, [e]);
-    }
-});/**
- * $Id: jxpanel.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Panel
- *
- * Purpose: 
- * Implementation of a javascript panels for Jx.  Panels are vertically 
- * oriented areas that can be resized by the user dragging the panel title
- * bar.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-Jx.addStyleSheet('panel/panel.css');
-
-/**
- * Class: Jx.PanelManager
- * A panel manager manages a set of panels within a DOM element.
- */
-Jx.PanelManager = Class.create();
-Jx.PanelManager.prototype = {
-    /**
-     * Property: panels
-     * {Array} the panels being managed by the manager
-     */
-    panels: null,
-    /**
-     * Property: height
-     * {Integer} the height of the container, cached for speed
-     */
-    height: null,
-    /**
-     * Property: firstLayout
-     * {Boolean} true until the panel manager has first been resized
-     */
-    firstLayout: true,
-    /**
-     * Constructor: Jx.PanelManager
-     * Create a new instance of Jx.PanelManager.
-     *
-     * Parameters:
-     * domObj - {HTMLElement} the HTML element that will contain the panels
-     * panels - {Array} the panels to go into the PanelManager
-     *
-     * TODO: Jx.PanelManager.initialize
-     * Remove the panels parameter in favour of an add method.
-     */
-    initialize: function(domObj, panels) {
-        this.domObj = $(domObj);
-        this.panels = panels;
-        var d = document.createElement('div');
-        d.style.position = 'absolute';
-        new Jx.Layout(d, {minHeight:0,maxHeight:0,height:0});
-        var elements = [d];
-        for (var i=0; i<this.panels.length; i++) {
-            elements.push(this.panels[i].domObj);
-        }
-        this.splitter = new Jx.Splitter(this.domObj, {splitInto: panels.length+1,
-                                                     layout: 'vertical',
-                                                     elements: elements });
-        /* redirect splitter sizeChanged so we can capture the first time the
-         * splitter is layed out in the client in a way that we can measure
-         * the title bar heights
-         */
-        this.splitter.sizeChanged = this.sizeChanged.bind(this);
-        /* create the bars for the panel manager */
-        for (var i=0; i<this.panels.length; i++) {
-            var panel = this.panels[i];
-            this.splitter.bars[i].appendChild(panel.title);
-            this.splitter.bars[i].style.height = Element.getBorderBoxSize(panel.title).height + 'px';
-            Element.removeClassName(this.splitter.bars[i], 'jxSplitterBar');
-            Element.addClassName(this.splitter.bars[i], 'jxPanelBar');
-            panel.manager = this;
-        }
-    },
-    /**
-     * Method: sizeChanged
-     * called when the size of the container of the splitter changes.  This tracks the
-     * first time the panel titles have a non-zero height (i.e. they are put in the
-     * DOM and are visible) and recalculates the panel title height then.
-     */ 
-    sizeChanged: function() {
-        if (this.firstLayout) {
-            if (Element.getBorderBoxSize(this.panels[0].title).height != 0) {
-                for (var i=0; i<this.splitter.bars.length; i++) {
-                    var panel = this.panels[i];
-                    this.splitter.bars[i].style.height = Element.getBorderBoxSize(panel.title).height + 'px';
-                    this.splitter.bars[i].size = null;
-                }
-                this.firstLayout = false;
-                Jx.Splitter.prototype.sizeChanged.apply(this.splitter, []);            
-            }
-        } else {
-            Jx.Splitter.prototype.sizeChanged.apply(this.splitter, []);            
-        }
-    },
-    
-    /**
-     * Method: maximizePanel
-     * Maximize the panel, taking up all available space (taking into
-     * consideration any minimum or maximum values)
-     */
-    maximizePanel: function(panel) {
-        var h = Element.getContentBoxSize(this.domObj).height;
-        
-        var t = 0;
-        for (var i=1; i<this.splitter.elements.length; i++) {
-            var p = this.splitter.elements[i];
-            t += Element.getBorderBoxSize(p.leftBar).height;
-            if (p !== panel.domObj) {
-                p.jxLayout.resize({top: t, height: p.jxLayout.options.minHeight, bottom: null});                    
-                t += p.jxLayout.options.minHeight;
-                p.rightBar.style.top = t + 'px';
-            } else {
-                break;
-            }
-        }
-        
-        b = h;
-        for (var i=this.splitter.elements.length - 1; i > 0; i--) {
-            p = this.splitter.elements[i];
-            if (p !== panel.domObj) {
-                b -= p.jxLayout.options.minHeight;
-                p.jxLayout.resize({top: b, height: p.jxLayout.options.minHeight, bottom: null});
-                b -= Element.getBorderBoxSize(p.leftBar).height;
-                p.leftBar.style.top = b + 'px';
-                
-            } else {
-                break;
-            }
-        }
-        panel.domObj.jxLayout.resize({top: t, height:b - t, bottom: null});
-    }
-};
-
-/**
- * Class: Jx.Panel
- * A panel that can be displayed inside a panel manager.
- */
-Jx.Panel = Class.create();
-Jx.Panel.prototype = {
-    /** 
-     * Property: labelObj
-     * the DOM object that holds the label in the title bar. 
-     */
-    labelObj : null,
-    /**
-     * Property: state
-     * the state of this panel 
-     */
-    state : 'open',
-    /**
-     * Property: busyCount
-     * track the busy state of this panel - used to control a 'loading' image 
-     */
-    busyCount : null,
-    /**
-     * Property: bContentReady
-     * {Boolean} is the content ready to be displayed?
-     */
-    bContentReady : null,
-    /**
-     * Property: onContentReady
-     * {Function} a function to call when the content is ready
-     */
-    onContentReady : null,
-    
-    /** 
-     * Constructor: Jx.Panel
-     * Initialize a new Jx.Panel instance
-     *
-     * Options:
-     *
-     * label - String, the title of the Jx Panel
-     * toolbar - element to use as the toolbar
-     * menubar - element to use as the menu
-     * content - element to use as the content. A content area is created
-     *           if none is provided.  Otherwise, the content element is moved
-     *           in the DOM
-     * statusbar - element to use as the statusbar
-     * helpCallback - function to call when the user clicks the contextual help button
-     * state - initial state of the panel (open or closed)
-     *
-     * Inherits From:
-     * <Jx.UniqueId>, <Jx.ContentLoader>
-     */
-    initialize : function(options){
-        //console.log("Jx.Panel::initialize('"+options.label+"')");
-        this.initUniqueId();
-        
-        /* set up the title object */
-        this.title = document.createElement('div');
-        this.title.className = "jxPanelTitle";
-        //TODO: Jx.Panel.initialize
-        //Opera is broken because it doesn't report the height of the
-        //title bars at all unless set through javascript
-        //this is a hack until we can figure out from css what the height is
-        this.title.style.height = '22px';
-        
-        this.labelObj = document.createElement('span');
-        this.labelObj.className = 'jxPanelLabel';
-        this.labelObj.innerHTML = options.label?options.label:'empty';
-    
-        this.imageBaseUrl = options.imageBaseUrl || Jx.baseURL + 'images/';
-        
-        var a, img;
-        if (options.helpCallback) {
-            a = document.createElement('a');
-            a.className = 'jxPanelHelp';
-            a.href = 'javascript:void(0)';
-            Event.observe(a, 'click', options.helpCallback);
-            img = document.createElement('img');
-            img.src = this.imageBaseUrl + "help.png";
-            img.alt = 'Help on this panel';
-            img.title = 'Help on this panel';
-            a.appendChild(img);
-            this.title.appendChild(a);
-        }
-    
-        a = document.createElement('a');
-        a.className = 'jxPanelMaximize';
-        a.href = 'javascript:void(0)';
-        Event.observe(a, 'click', this.maximize.bindAsEventListener(this));
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + "maximize.png";
-        img.alt = 'Maximize Panel';
-        img.title = 'Maximize Panel';
-        a.appendChild(img);
-        this.title.appendChild(a);
-    
-        a = document.createElement('a');
-        a.className = 'jxPanelLoading';
-        a.href = 'javascript:void(0)';
-        img = document.createElement('img');
-        img.src = this.imageBaseUrl + "loading.gif";
-        img.alt = 'Loading Panel';
-        img.title = 'Loading Panel';
-        a.appendChild(img);
-        this.loadingObj = {};
-        this.loadingObj.link = a;
-        this.loadingObj.img = img;
-        this.title.appendChild(this.loadingObj.link);
-        this.title.appendChild(this.labelObj);
-        
-        Event.observe(this.title, 'dblclick', this.maximize.bindAsEventListener(this));
-        
-        this.domObj = document.createElement('div');
-        this.domObj.className = 'jxPanel';
-        
-        this.jxLayout = new Jx.Layout(this.domObj, options.constraint || {});
-        this.jxLayout.addSizeChangeListener(this);
-        
-        var top = 0;
-        var bottom = 0;
-        if (options.menubar) {
-            this.menubar = options.menubar;
-            this.domObj.appendChild(options.menubar);
-            var h = Element.getBorderBoxSize(options.menubar).height;
-            new Jx.Layout(this.menubar, {top: top, height:h});
-            top += h;
-        }
-        if (options.toolbar) {
-            this.toolbar = options.toolbar;
-            this.domObj.appendChild(options.toolbar);
-            var h = Element.getBorderBoxSize(options.toolbar).height;
-            new Jx.Layout(this.toolbar, {top:top, height: h});
-        }
-        
-        if (options.statusbar) {
-            this.statusbar = options.statusbar;
-            this.domObj.appendChild(options.statusbar);
-            var h = Element.getBorderBoxSize(options.statusbar).height;
-            new Jx.Layout(this.statusbar, {bottom: bottom, height: h, top: null});
-            bottom += h;
-        }
-        this.content = document.createElement('div');
-        Element.addClassName(this.content, 'jxPanelContent');
-        new Jx.Layout(this.content, {top: top, bottom: bottom});
-        this.domObj.appendChild(this.content);
-        this.loadContent(this.content, options);
-        
-        this.busyCount = 0;
-        this.bContentReady = false;
-    },
-    /**
-     * Method: setLabel
-     * Set the label in the title bar of this panel
-     *
-     * Parameters:
-     * s - {String} the new label
-     */
-    setLabel: function(s) {
-        this.labelObj.innerHTML = s;
-    },
-    /**
-     * Method: getLabel
-     * Get the label of the title bar of this panel
-     *
-     * Returns: 
-     * {String} the label
-     */
-    getLabel: function() {
-        return this.labelObj.innerHTML;
-    },
-    /**
-     * Method: finalize
-     * Clean up the panel
-     */
-    finalize: function() {
-        this.domObj = null;
-        this.deregisterIds();
-    },
-    /**
-     * Method: maximize
-     * Maximize this panel
-     */
-    maximize: function() {
-        if (this.manager) {
-            this.manager.maximizePanel(this);
-        }
-    },
-    /**
-     * Method: setContent
-     * set the content of this panel to some HTML
-     *
-     * Parameters:
-     * html - {String} the new HTML to go in the panel
-     */
-    setContent : function (html) {
-        //console.log('Jx.Panel::setContent()');
-        this.content.innerHTML = html;
-        this.bContentReady = true;
-    },
-    /**
-     * Method: setContentURL
-     * Set the content of this panel to come from some URL.
-     *
-     * Parameters:
-     * url - {String} URL to some HTML content for this panel
-     */
-    setContentURL : function (url) {
-        this.bContentReady = false;
-        this.setBusy(true);
-        if (arguments[1]) {
-            this.onContentReady = arguments[1];
-        }
-        if (url.indexOf('?') == -1) {
-            url = url + '?';
-        }
-        //var ts = (new Date()).getTime();
-        //url = url + 'ts='+ts;
-        var opts = { method: 'get',
-                     onComplete:this.panelContentLoaded.bind(this),
-                     requestHeaders: ['If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT']};
-        var a = new Ajax.Request( url, opts);
-    },
-    /**
-     * Method: panelContentLoaded
-     * When the content of the panel is loaded from a remote URL, this 
-     * method is called when the ajax request returns.
-     *
-     * Parameters:
-     * r - {XmlHttpRequest} the XmlHttpRequest object
-     */
-    panelContentLoaded: function(r) {
-        this.content.innerHTML = r.responseText;
-        this.bContentReady = true;
-        this.setBusy(false);
-        if (this.onContentReady) {
-            window.setTimeout(this.onContentReady.bind(this),1);
-        }
-    },
-    /**
-     * Method: setBusy
-     * Set the panel as busy or not busy, which displays a loading image
-     * in the title bar.
-     *
-     * Parameters:
-     * isBusy - {Boolean} the busy state
-     */
-    setBusy : function(isBusy) {
-        this.busyCount += isBusy?1:-1;
-        this.loadingObj.img.style.visibility = (this.busyCount>0)?'visible':'hidden';
-    },
-    /**
-     * Method: sizeChanged
-     * handle the size of the container changing by resizing the various
-     * elements of the panel.
-     */
-    sizeChanged: function() {
-        var top = 0;
-        var bottom = 0;
-        if (this.menubar) {
-            this.menubar.style.height = '';
-            var size = Element.getBorderBoxSize(this.menubar);
-            this.menubar.resize({height:size.height});
-            top += size.height;
-        }
-        if (this.toolbar) {
-            this.toolbar.style.height = '';
-            var size = Element.getBorderBoxSize(this.toolbar);
-            this.toolbar.resize({height:size.height});
-            top += size.height;
-        }
-        if (this.statusbar) {
-            this.statusbar.style.height = '';
-            var size = Element.getBorderBoxSize(this.statusbar);
-            this.statusbar.resize({height:size.height});
-            bottom += size.height;
-        }
-        if (top || bottom) {
-            this.content.resize({bottom: bottom, top: top});
-        }               
-    }
-};
-Object.extend(Jx.Panel.prototype, Jx.UniqueId.prototype);
-Object.extend(Jx.Panel.prototype, Jx.ContentLoader.prototype);/**
- * $Id: jxpicker.js 516 2008-03-10 23:21:04Z pspencer $
- *
- * Title: Jx.Picker
- *
- * Purpose: 
- * Implementation of a javascript Pick List for Jx.  This is analagous to an 
- * HTML select except that it allows other things to be put in the list.  The
- * selected item from the list can also be editable.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-Jx.addStyleSheet('picker/picker.css');
-
-/**
- * Class: Jx.Picker
- * A drop down list of selectable items that can be any HTML.
- *
- * Inherits From:
- * <Jx.Listener>
- */
-Jx.Picker = Class.create();
-Jx.Picker.prototype = {
-    /** 
-     * Property: sl
-     * {Array} selection listeners 
-     */
-    sl : null,
-    
-    /** 
-     * Property: domObj
-     * {HTMLElement} the div that contains the control, 
-     * used to show/hide the control 
-     */
-    domObj : null,
-    /** 
-     * Property: ul
-     * {HTMLElement} the ul that contains the selectable items 
-     */
-    ul : null,
-    /**
-     * Property: currentSelection
-     * {Object} current selection in the list 
-     */
-    currentSelection : null,
-    
-    /**
-     * Property: isEditable
-     * {Boolean} is the selected item editable? 
-     **/
-    isEditable: false,
-    /** 
-     * Constructor: Jx.Picker
-     * create a new instance of Jx.Picker
-     *
-     * Options:
-     * editable - {Boolean} defaults to false.  If true, then the selected item
-     * is editable.
-     */
-    initialize: function(options) {
-        options = options || {};
-        
-        this.domObj = document.createElement('div');
-        this.domObj.className = 'jxPicker';
-        this.isEditable = options.editable || false;
-        
-        if (this.isEditable) {
-            this.domInput = document.createElement('input');
-            this.domInput.type = 'text';
-            Event.observe(this.domInput, 'change', this.valueChanged.bind(this));
-            Event.observe(this.domInput, 'keydown', this.onKeyPress.bind(this));
-        } else {
-            this.domInput = document.createElement('span');
-        }
-        this.domInput.className = 'jxPickerInput';
-        
-        this.domObj.appendChild(this.domInput);
-        
-        this.domA = document.createElement('a');
-        this.domA.href = 'javascript:void(0)';
-        this.domA.className = 'jxPickerDiscloser';
-        Event.observe(this.domA, 'click', this.toggle.bind(this));
-        
-        this.domButton = document.createElement('img');
-        this.domButton.src = Jx.baseURL + 'images/disclose2.png';
-        Element.addClassName(this.domButton, 'png24');
-        this.domA.appendChild(this.domButton);
-        this.domObj.appendChild(this.domA);
-        
-        if (!window.opera) {
-            //insert iframeShim for IE to cover other controls in the page.
-            var iframe = document.createElement('iframe');
-            iframe.className = 'jxDialogShim';
-            iframe.scrolling = 'no';
-            iframe.frameborder = 0;
-            this.domObj.appendChild(iframe);
-        }
-        
-        this.domListDiv = document.createElement('div');
-        this.domListDiv.className = 'jxPickerOptions';
-        this.domListDiv.style.display = 'none';
-        this.domObj.appendChild(this.domListDiv);
-        this.domList = document.createElement('ul');
-        this.domListDiv.appendChild(this.domList);
-        this.sl = [];
-    },
-    
-    /**
-     * Method: onKeyPress
-     * Handle the user pressing a key by looking for an ENTER key to set the
-     * value.
-     *
-     * Parameters:
-     * e - {Event} the keypress event
-     */
-    onKeyPress: function(e) {
-        var charCode = (e.charCode) ? e.charCode : ((e.keyCode) ? e.keyCode : e.which);
-        if (charCode == Event.KEY_RETURN) {
-            this.valueChanged();
-        }
-    },
-    
-    /**
-     * Method: valueChanged
-     * When the value is changed, propogate the change to the selection 
-     * listeners
-     */
-    valueChanged: function() {
-        this.processEvent(this.sl, 'selectionChanged', this);
-    },
-    
-    /**
-     * Method: add
-     * add a new item to the pick list
-     *
-     * Parameters:
-     * domObj - {HTMLElement} the element to add
-     * idx - {Integer} the index to add the element add
-     */
-    add: function(domObj, idx) {
-        var li = document.createElement('li');
-        var a = document.createElement('a');
-        a.href="javascript:void(0)";
-        
-        if (typeof(domObj) == 'string') {
-            a.innerHTML = domObj;
-        } else {
-            a.appendChild(domObj);
-        }
-        Event.observe(a, 'click', this.pick.bindAsEventListener(this));
-        li.appendChild(a);
-
-        if (arguments.length > 1 && this.domList.childNodes.length > idx) {
-            this.domList.insertBefore(li, this.domList.childNodes[idx]);
-        } else {
-            this.domList.appendChild(li);
-        }
-        if (this.getValue() == '') {
-            this.setValue(a.childNodes[0]);
-        }
-    },
-    
-    /**
-     * Method: remove
-     * Remove the item at the given index
-     *
-     * Parameters:
-     * idx - {Integer} the item to remove.
-     */
-    remove: function(idx) {
-        if (idx > 0 && idx < this.domList.childNodes.length) {
-            this.domList.removeChild(this.domList.childNodes[idx]);
-        }
-    },
-    
-    /**
-     * Method: pick
-     * user has clicked something in the list, select it
-     *
-     * Parameters:
-     * e - {Event} the mouse event from the user's click
-     */
-    pick: function(e) {
-        var target = Event.element(e);
-        if (target.tagName == 'A') {
-            this.currentSelection = target;
-            this.setValue(this.currentSelection.childNodes[0]);
-            this.valueChanged();
-        }
-        this.close();
-    },
-    /**
-     * Method: setValue
-     * set the value of the picker
-     *
-     * Parameters:
-     * value - {Object} the new value.  May be a string, a text node, or
-     * another DOM element.
-     */
-    setValue: function(value) {
-        if (this.isEditable) {
-            if (typeof(value) == 'string') {
-                this.domInput.value = value;
-            } else if (value.nodeType && value.nodeType == 3) {
-                this.domInput.value = value.nodeValue;
-            } else {
-                this.domInput.value = value.innerHTML;
-            }
-        } else if (!this.isEditable) {
-            if (typeof(value) == 'string') {
-                this.domInput.innerHTML = value;
-            } else if (value.nodeType && value.nodeType == 3) {
-                this.domInput.innerHTML = value.nodeValue;
-            } else {
-                this.domInput.appendChild(value);
-            }
-        }
-    },
-    
-    /**
-     * Method: getValue
-     * Return the current value
-     *
-     * Returns:
-     * {Object} returns the currently selected item
-     */
-    getValue: function() {
-        value = '';
-        if (this.isEditable) {
-            value = this.domInput.value;
-        } else if (this.domInput.childNodes.length > 0) {
-            if (this.domInput.childNodes[0].nodeType == 3) {
-                value = this.domInput.innerHTML;
-            } else {
-                value = this.domInput.childNodes[0];
-            }
-        }
-        return value;
-    },
-    
-    /**
-     * Method: toggle
-     * Toggle the display of the list associated with the picker
-     */
-    toggle: function() {
-        if (this.domListDiv.style.display == 'block') {
-            this.close();
-        } else {
-            this.open();
-        }
-    },
-    
-    /**
-     * Method: open
-     * Open the pick list
-     */
-    open: function() {
-        if (!this.keypressListener) {
-            this.keypressListener = this.keypress.bindAsEventListener(this);
-        }
-        this.domListDiv.style.display = 'block';
-        Event.observe(document, 'keypress', this.keypressListener);
-        //Effect.SlideDown(this.domObj, 0.2);
-    },
-    /**
-     * Method: keypress
-     * Handle a key press event when the list is open so we can close it if the
-     * user hits the ESC key.
-     *
-     * Parameters:
-     * e - {Event} the keypress event
-     */
-    keypress: function(e) {
-        var charCode=(e.charCode)?e.charCode:e.keyCode;
-        if (charCode == Event.KEY_ESC) {
-            this.close();
-        }
-    },
-    /**
-     * Method: close
-     * Close the picker.
-     */
-    close: function() {
-        this.domListDiv.style.display = 'none';
-        Event.stopObserving(document, 'keypress', this.keypressListener);
-        //Effect.SlideUp(this.domObj, 0.2);
-    },
-    /**
-     * Method: addSelectionListener
-     * Add a selection listener to the picker
-     *
-     * Parameters:
-     * obj - {Object} the selection listener
-     */
-    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
-    /**
-     * Method: removeSelectionListener
-     * Remove a selection listener to the picker
-     *
-     * Parameters:
-     * obj - {Object} the selection listener
-     */
-    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); },
-    /**
-     * Method: getSelection
-     * return the current selection
-     *
-     * Returns:
-     * {Object} the current selection or an empty string.
-     */
-    getSelection: function() {
-        return this.currentSelection ? this.currentSelection.name : '';
-    }
-};
-Object.extend(Jx.Picker.prototype, Jx.Listener.prototype);/**
- * $Id: jxsplitter.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Splitter
- *
- * Purpose: 
- * Implementation of a javascript Splitter for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-  
-/**
- * Class: Jx.Splitter
- * a Jx.Splitter creates two or more containers within a parent container
- * and provides user control over the size of the containers.  The split
- * can be made horizontally or vertically.
- * 
- * A horizontal split creates containers that divide the space horizontally
- * with vertical bars between the containers.  A vertical split divides
- * the space vertically and creates horizontal bars between the containers.
- */
- 
-Jx.Splitter = Class.create();
-Jx.Splitter.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} the element being split
-     */
-    domObj: null,
-    /**
-     * Property: elements
-     * {Array} an array of elements that are displayed in each of the split 
-     * areas
-     */
-    elements: null,
-    /**
-     * Property: bars
-     * {Array} an array of the bars between each of the elements used to
-     * resize the split areas.
-     */
-    bars: null,
-    /**
-     * Property: firstUpdate
-     * {Boolean} track the first resize event so that unexposed Jx things
-     * can be forced to calculate their size the first time they are exposed.
-     */
-    firstUpdate: true,
-    /**
-     * Constructor: Jx.Splitter
-     * Create a new instance of Jx.Splitter
-     *
-     * Parameters:
-     * domObj - {HTMLElement} the element or id of the element to split
-     * options - {Object} optional arguments specified as properties of
-     * this object are as below.
-     *
-     * Options:
-     * elements - {Array} an array of elements to put into the split areas.
-     *      If splitInto is not set, then it is calculated from the length of
-     *      this array.
-     * splitInto - {Integer} the number of elements to split the domObj into.
-     *      If not set, then the length of the elements option is used, or 2 if
-     *      elements is not specified.  If splitInto is specified and elements
-     *      is specified, then splitInto is used.  If there are more elements than
-     *      splitInto specifies, then the extras are ignored.  If there are less
-     *      elements than splitInto specifies, then extras are created.
-     * containerOptions - {Array} an array of objects that provide options
-     *      for the <Jx.Layout> constraints on each element.
-     * layout - {String} either 'horizontal' or 'vertical', indicating the
-     *      direction in which the domObj is to be split.
-     * snappers - {Array} an array of objects which can be used to snap
-     *      elements open or closed.
-     */
-    initialize: function(domObj, options) {
-        options = options || {};  
-        
-        this.domObj = $(domObj);
-        this.domObj.style.overflow = 'hidden';
-        if (this.domObj.jxLayout) {
-            this.domObj.jxLayout.addSizeChangeListener(this);
-        }
-       
-        this.elements = [];
-        this.bars = [];
-        
-        var nSplits = options.splitInto || (options.elements ? options.elements.length : 2);
-        
-        var aContainerOpts = options.containerOptions || [];
-
-        for (var i=0; i<nSplits; i++) {
-            this.elements[i] = options.elements ? options.elements[i] : this.prepareElement();
-            this.domObj.appendChild(this.elements[i]);
-            if (!this.elements[i].jxLayout) {
-                new Jx.Layout(this.elements[i], aContainerOpts[i]);
-            }
-        }
-        
-        for (var i=1; i<nSplits; i++) {
-            this.bars[i-1] = this.prepareBar();
-            this.bars[i-1].leftSide = this.elements[i-1];
-            this.bars[i-1].rightSide = this.elements[i];
-            this.elements[i-1].rightBar = this.bars[i-1];
-            this.elements[i].leftBar = this.bars[i-1];
-            this.domObj.appendChild(this.bars[i-1]);
-        }
-
-        this.layout = options.layout || 'horizontal';
-        this.establishConstraints();
-        
-        if (options.snappers) {
-            for (var i=0; i<options.snappers.length; i++) {
-                if (options.snappers[i]) {
-                    new Jx.Splitter.Snapper(options.snappers[i], this.elements[i], this);
-                }
-            }
-        }
-    },
-    /**
-     * Method: prepareElement
-     * Prepare a new, empty element to go into a split area.
-     *
-     * Returns:
-     * {HTMLElement} an HTMLElement that goes into a split area.
-     */
-    prepareElement: function(){
-        var o = document.createElement('div');
-        o.style.position = 'absolute';
-        o.leftBar = null;
-        o.rightBar = null;
-        return o;
-    },
-    
-    /**
-     * Method: prepareBar
-     * Prepare a new, empty bar to go into between split areas.
-     *
-     * Returns:
-     * {HTMLElement} an HTMLElement that becomes a bar.
-     */
-    prepareBar: function() {
-        var o = document.createElement('div');
-        o.className = 'jxSplitterBar';
-        o.style.position = 'absolute';
-        o.title = 'drag this bar to resize';
-        o.style.lineHeight = '1px'; // for IE, horizontal bars
-        o.splitterObj = this;
-        return o;
-    },
-    
-    /**
-     * Method: establishConstraints
-     * Setup the initial set of constraints that set the behaviour of the
-     * bars between the elements in the split area.
-     */
-    establishConstraints: function() {
-        if (this.layout == 'horizontal') {
-            for (var i=0; i< this.bars.length; i++) {
-                this.bars[i].style.top = '0px';
-                this.bars[i].style.height = '100%';
-                new Draggable(this.bars[i], { constraint: 'horizontal' , 
-                                     starteffect : function(element) { 
-                                            element.style.backgroundColor = '#eee';
-                                            },
-                                     endeffect : function(element) {
-                                         element.style.backgroundColor = '';
-                                     }
-                });
-            }
-        } else {
-            for (var i=0; i< this.bars.length; i++) {
-                this.bars[i].style.left = '0px';
-                this.bars[i].style.width = '100%';
-                new Draggable(this.bars[i], { constraint: 'vertical' , 
-                                     starteffect : function(element) { 
-                                            element.style.backgroundColor = '#eee';
-                                            },
-                                     endeffect : function(element) {
-                                         element.style.backgroundColor = '';
-                                     }
-                });
-            }
-        }
-        Draggables.addObserver(this);
-    },
-    
-    /**
-     * Method: onEnd
-     * Handle the end of a drag event on a bar.
-     *
-     * Parameters:
-     * eventName - {String} the name associated with the drag event
-     * obj - {HTMLElement} the bar that was dragged
-     * event - {Event} the event object associated with the drag
-     */
-    onEnd: function(eventName, obj, event) {
-        if (obj.element.splitterObj != this) {
-            return;
-        }
-        if (this.layout == 'horizontal') {
-            this.dragHorizontal(eventName, obj, event);
-        } else {
-            this.dragVertical(eventName, obj, event);
-        }
-    },
-    
-    /**
-     * Method: dragHorizontal
-     * In a horizontally split container, handle a bar being dragged left or
-     * right by resizing the elements on either side of the bar.
-     *
-     * Parameters:
-     * eventName - {String} the name associated with the drag event
-     * obj - {HTMLElement} the bar that was dragged
-     * event - {Event} the event object associated with the drag
-     */
-    dragHorizontal: function(eventName, obj, event) {
-        var leftEdge = parseInt(obj.element.style.left);
-        var leftSide = obj.element.leftSide;
-        var rightSide = obj.element.rightSide;
-        
-        /* process right side first */
-        var rsLeft, rsWidth, rsRight;
-        
-        if (!obj.element.size) {
-            obj.element.size = Element.getBorderBoxSize(obj.element);
-        }
-        var barSize = obj.element.size;
-        rsLeft = leftEdge + barSize.width;
-        
-        var parentSize = Element.getContentBoxSize(this.domObj);
-        
-        if (rightSide.jxLayout.options.width != null) {
-            rsWidth = rightSide.jxLayout.options.width + rightSide.jxLayout.options.left - rsLeft;
-            rsRight = parentSize.width - rsLeft - rsWidth;
-        } else {
-            rsWidth = parentSize.width - rightSide.jxLayout.options.right - rsLeft;
-            rsRight = rightSide.jxLayout.options.right;
-        }
-        
-        /* enforce constraints on right side */
-        if (rsWidth < 0) {
-            rsWidth = 0;
-        }
-        
-        if (rsWidth < rightSide.jxLayout.options.minWidth) {
-            rsWidth = rightSide.jxLayout.options.minWidth;
-        }
-        if (rightSide.jxLayout.options.maxWidth >= 0 && rsWidth > rightSide.jxLayout.options.maxWidth) {
-            rsWidth = rightSide.jxLayout.options.maxWidth;
-        }
-        
-        rsLeft = parentSize.width - rsRight - rsWidth;
-        leftEdge = rsLeft - barSize.width;
-        
-        /* process left side */
-        var lsLeft, lsWidth;
-        lsLeft = leftSide.jxLayout.options.left;
-        lsWidth = leftEdge - lsLeft;
-        
-        /* enforce constraints on left */
-        if (lsWidth < 0) {
-            lsWidth = 0;
-        }
-        if (lsWidth < leftSide.jxLayout.options.minWidth) {
-            lsWidth = leftSide.jxLayout.options.minWidth;
-        }
-        if (leftSide.jxLayout.options.maxWidth >= 0 && 
-            lsWidth > leftSide.jxLayout.options.maxWidth) {
-            lsWidth = leftSide.jxLayout.options.maxWidth;
-        }
-        
-        /* update the leftEdge to accomodate constraints */
-        if (lsLeft + lsWidth != leftEdge) {
-            /* need to update right side, ignoring constraints because left side
-               constraints take precedence (arbitrary decision)
-             */
-            leftEdge = lsLeft + lsWidth;
-            var delta = leftEdge + barSize.width - rsLeft;
-            rsLeft += delta;
-            rsWidth -= delta; 
-        }
-        
-        /* put bar in its final location based on constraints */
-        obj.element.style.left = leftEdge + 'px';
-        
-        /* update leftSide positions */
-        if (leftSide.jxLayout.options.width == null) {
-            var parentSize = Element.getContentBoxSize(this.domObj);
-            leftSide.jxLayout.resize({right: parentSize.width - lsLeft-lsWidth});
-        } else {
-            leftSide.jxLayout.resize({width: lsWidth});
-        }
-        
-        /* update rightSide position */
-        if (rightSide.jxLayout.options.width == null) {
-            rightSide.jxLayout.resize({left:rsLeft});
-        } else {
-            rightSide.jxLayout.resize({left: rsLeft, width: rsWidth});
-        }
-    },
-    
-    /**
-     * Method: dragVertical
-     * In a vertically split container, handle a bar being dragged up or
-     * down by resizing the elements on either side of the bar.
-     *
-     * Parameters:
-     * eventName - {String} the name associated with the drag event
-     * obj - {HTMLElement} the bar that was dragged
-     * event - {Event} the event object associated with the drag
-     */
-    dragVertical: function(eventName, obj, event) {
-        /* top edge of the bar */
-        var topEdge = parseInt(obj.element.style.top);
-        
-        /* the containers on either side of the bar */
-        var topSide = obj.element.leftSide;
-        var bottomSide = obj.element.rightSide;
-        
-        /* measure the bar and parent container for later use */
-        if (!obj.element.size) {
-            obj.element.size = Element.getBorderBoxSize(obj.element);
-        }
-        var barSize = obj.element.size;
-        var parentSize = Element.getContentBoxSize(this.domObj);
-
-        /* process top side first */
-        var bsTop, bsHeight, bsBottom;
-        
-        /* top edge of bottom side is the top edge of bar plus the height of the bar */
-        bsTop = topEdge + barSize.height;
-        
-        if (bottomSide.jxLayout.options.height != null) {
-            /* bottom side height is fixed */
-            bsHeight = bottomSide.jxLayout.options.height + bottomSide.jxLayout.options.top - bsTop;
-            bsBottom = parentSize.height - bsTop - bsHeight;
-        } else {
-            /* bottom side height is not fixed. */
-            bsHeight = parentSize.height - bottomSide.jxLayout.options.bottom - bsTop;
-            bsBottom = bottomSide.jxLayout.options.bottom;
-        }
-        
-        /* enforce constraints on bottom side */
-        if (bsHeight < 0) {
-            bsHeight = 0;
-        }
-        
-        if (bsHeight < bottomSide.jxLayout.options.minHeight) {
-            bsHeight = bottomSide.jxLayout.options.minHeight;
-        }
-        
-        if (bottomSide.jxLayout.options.maxHeight >= 0 && bsHeight > bottomSide.jxLayout.options.maxHeight) {
-            bsHeight = bottomSide.jxLayout.options.maxHeight;
-        }
-        
-        /* recalculate the top of the bottom side in case it changed
-           due to a constraint.  The bar may have moved also.
-         */
-        bsTop = parentSize.height - bsBottom - bsHeight;
-        topEdge = bsTop - barSize.height;
-                
-        /* process left side */
-        var tsTop, tsHeight;
-        tsTop = topSide.jxLayout.options.top;
-        tsHeight = topEdge - tsTop;
-                        
-        /* enforce constraints on left */
-        if (tsHeight < 0) {
-            tsHeight = 0;
-        }
-        if (tsHeight < topSide.jxLayout.options.minHeight) {
-            tsHeight = topSide.jxLayout.options.minHeight;
-        }
-        if (topSide.jxLayout.options.maxHeight >= 0 && 
-            tsHeight > topSide.jxLayout.options.maxHeight) {
-            tsHeight = topSide.jxLayout.options.maxHeight;
-        }
-        
-        /* update the topEdge to accomodate constraints */
-        if (tsTop + tsHeight != topEdge) {
-            /* need to update right side, ignoring constraints because left side
-               constraints take precedence (arbitrary decision)
-             */
-            topEdge = tsTop + tsHeight;
-            var delta = topEdge + barSize.height - bsTop;
-            bsTop += delta;
-            bsHeight -= delta; 
-        }
-        
-        /* put bar in its final location based on constraints */
-        obj.element.style.top = topEdge + 'px';
-        
-        /* update topSide positions */
-        if (topSide.jxLayout.options.height == null) {
-            topSide.jxLayout.resize({bottom: parentSize.height - tsTop-tsHeight});
-        } else {
-            topSide.jxLayout.resize({height: tsHeight});
-        }
-        
-        /* update bottomSide position */
-        if (bottomSide.jxLayout.options.height == null) {
-            bottomSide.jxLayout.resize({top:bsTop});
-        } else {
-            bottomSide.jxLayout.resize({top: bsTop, height: bsHeight});
-        }
-    },
-    
-    /**
-     * Method: sizeChanged
-     * handle the size of the container being changed.
-     */
-    sizeChanged: function() {
-        if (this.layout == 'horizontal') {
-            this.horizontalResize();
-        } else {
-            this.verticalResize();
-        }
-    },
-    
-    /**
-     * Method: horizontalResize
-     * Resize a horizontally layed-out container
-     */
-    horizontalResize: function() {
-        var availableSpace = Element.getContentBoxSize(this.domObj).width;
-        var overallWidth = availableSpace;
-
-        for (var i=0; i<this.bars.length; i++) {
-            var bar = this.bars[i];
-            if (!bar.size) {
-                bar.size = Element.getBorderBoxSize(bar);
-            }
-            availableSpace -= bar.size.width;
-        }
-
-        var nVariable = 0;
-        var jxo;
-        for (var i=0; i<this.elements.length; i++) {
-            var e = this.elements[i];
-            jxo = e.jxLayout.options;
-            if (jxo.width != null) {
-                availableSpace -= parseInt(jxo.width);
-            } else {
-                var w = 0;
-                if (jxo.right != 0 || 
-                    jxo.left != 0) {
-                    w = Element.getBorderBoxSize(e).width;
-                }
-                
-                availableSpace -= w;
-                nVariable++;
-            }
-        }
-
-        if (nVariable == 0) { /* all fixed */
-            /* stick all available space in the last one */
-            availableSpace += jxo.width;
-            jxo.width = null;
-            nVariable = 1;
-        }
-
-        var amount = parseInt(availableSpace / nVariable);
-        /* account for rounding errors */
-        var remainder = availableSpace % nVariable;
-
-        var currentPosition = 0;
-
-        for (var i=0; i<this.elements.length; i++) {
-             var e = this.elements[i];
-             var jxl = e.jxLayout;
-             var jxo = jxl.options;
-             if (jxo.width != null) {
-                 jxl.resize({left: currentPosition});
-                 currentPosition += jxo.width;
-             } else {
-                 var a = amount;
-                 if (nVariable == 1) {
-                     a += remainder;
-                 }
-                 nVariable--;
-                 
-                 var w = 0;
-                 if (jxo.right != 0 || jxo.left != 0) {
-                     w = Element.getBorderBoxSize(e).width + a;
-                 } else {
-                     w = a;
-                 }
-                 
-                 if (w < 0) {
-                     if (nVariable > 0) {
-                         amount = amount + w/nVariable;
-                     }
-                     w = 0;
-                 }
-                 if (w < jxo.minWidth) {
-                     if (nVariable > 0) {
-                         amount = amount + (w - jxo.minWidth)/nVariable;
-                     }
-                     w = jxo.minWidth;
-                 }
-                 if (jxo.maxWidth >= 0 && w > jxo.maxWidth) {
-                     if (nVariable > 0) {
-                         amount = amount + (w - jxo.maxWidth)/nVariable;
-                     }
-                     w = e.options.maxWidth;
-                 }
-                 
-                 var r = overallWidth - currentPosition - w;
-                 jxl.resize({left: currentPosition, right: r});
-                 currentPosition += w;
-             }
-             if (e.rightBar) {
-                 e.rightBar.style.left = currentPosition + 'px';
-                 currentPosition += e.rightBar.size.width;
-             }
-         }
-    },
-    
-    /**
-     * Method: verticalResize
-     * Resize a vertically layed out container.
-     */
-    verticalResize: function() { 
-        var availableSpace = Element.getContentBoxSize(this.domObj).height;
-        var overallHeight = availableSpace;
-
-        for (var i=0; i<this.bars.length; i++) {
-            var bar = this.bars[i];
-            if (!bar.size) {
-                bar.size = Element.getBorderBoxSize(bar);
-            }
-            availableSpace -= bar.size.height;
-        }
-
-        var nVariable = 0;
-        
-        var jxo;
-        for (var i=0; i<this.elements.length; i++) {
-            var e = this.elements[i];
-            jxo = e.jxLayout.options;
-            if (jxo.height != null) {
-                availableSpace -= parseInt(jxo.height);
-            } else {
-                var h = 0;
-                if (jxo.bottom != 0 || jxo.top != 0) {
-                    h = Element.getBorderBoxSize(e).height;
-                }
-                
-                availableSpace -= h;
-                nVariable++;
-            }
-        }
-
-        if (nVariable == 0) { /* all fixed */
-            /* stick all available space in the last one */
-            availableSpace += jxo.height;
-            jxo.height = null;
-            nVariable = 1;
-        }
-
-        var amount = parseInt(availableSpace / nVariable);
-        /* account for rounding errors */
-        var remainder = availableSpace % nVariable;
-
-        var currentPosition = 0;
-
-        for (var i=0; i<this.elements.length; i++) {
-             var e = this.elements[i];
-             var jxl = e.jxLayout;
-             var jxo = jxl.options;
-             if (jxo.height != null) {
-                 jxl.resize({top: currentPosition});
-                 currentPosition += jxo.height;
-             } else {
-                 var a = amount;
-                 if (nVariable == 1) {
-                     a += remainder;
-                 }
-                 nVariable--;
-                 
-                 var h = 0;
-                 if (jxo.bottom != 0 || 
-                     jxo.top != 0) {
-                     h = Element.getBorderBoxSize(e).height + a;
-                 } else {
-                     h = a;
-                 }
-                 
-                 if (h < 0) {
-                     if (nVariable > 0) {
-                         amount = amount + h/nVariable;
-                     }
-                     h = 0;
-                 }
-                 if (h < jxo.minHeight) {
-                     if (nVariable > 0) {
-                         amount = amount + (h - jxo.minHeight)/nVariable;
-                     }
-                     h = jxo.minHeight;
-                 }
-                 if (jxo.maxHeight >= 0 && h > jxo.maxHeight) {
-                     if (nVariable > 0) {
-                         amount = amount + (h - jxo.maxHeight)/nVariable;
-                     }
-                     h = jxo.maxHeight;
-                 }
-                 
-                 var r = overallHeight - currentPosition - h;
-                 jxl.resize({top: currentPosition, bottom: r});
-                 currentPosition += h;
-             }
-             if (e.rightBar) {
-                 e.rightBar.style.top = currentPosition + 'px';
-                 currentPosition += e.rightBar.size.height;
-             }
-         }
-    }
-};
-
-/**
- * Class: Jx.Splitter.Snapper
- * A helper class to create an element that can snap a split panel open or
- * closed.
- */
-Jx.Splitter.Snapper = Class.create();
-Jx.Splitter.Snapper.prototype = {
-    /**
-     * Property: snapper
-     * {HTMLElement} the DOM element of the snapper (the thing that gets
-     * clicked).
-     */
-    snapper: null,
-    /**
-     * Property: element
-     * {HTMLElement} An element of the <Jx.Splitter> that gets controlled
-     * by this snapper
-     */
-    element: null,
-    /**
-     * Property: splitter
-     * {<Jx.Splitter>} the splitter that this snapper is associated with.
-     */
-    splitter: null,
-    /**
-     * Property: layout
-     * {String} track the layout of the splitter for convenience.
-     */
-    layout: 'vertical',
-    /**
-     * Constructor: Jx.Splitter.Snapper
-     * Create a new Jx.Splitter.Snapper
-     *
-     * Parameters:
-     * snapper - {HTMLElement} the clickable thing that snaps the element
-     *           open and closed
-     * element - {HTMLElement} the element that gets controlled by the snapper
-     * splitter - {<Jx.Splitter>} the splitter that this all happens inside of.
-     */
-    initialize: function(snapper, element, splitter) {
-        this.snapper = snapper;
-        this.element = element;
-        element.jxLayout.addSizeChangeListener(this);
-        this.splitter = splitter;
-        this.layout = splitter.layout; 
-        var jxo = this.element.jxLayout.options;
-        var size = Element.getBorderBoxSize(this.element);
-        if (this.layout == 'vertical') {
-            this.originalSize = size.height;
-            this.minimumSize = jxo.minHeight ? jxo.minHeight : 0;
-        } else {
-            this.originalSize = size.width;
-            this.minimumSize = jxo.minWidth ? jxo.minWidth : 0;
-        }
-        
-        Event.observe(snapper, 'click', this.toggleElement.bind(this));
-    },
-    
-    /**
-     * Method: toggleElement
-     * Snap the element open or closed.
-     */
-    toggleElement: function() {
-        var size = Element.getBorderBoxSize(this.element);
-        var newSize = {};
-        if (this.layout == 'vertical') {
-            if (size.height == this.minimumSize) {
-                newSize.height = this.originalSize;
-            } else {
-                this.originalSize = size.height;
-                newSize.height = this.minimumSize;
-            }
-        } else {
-            if (size.width == this.minimumSize) {
-                newSize.width = this.originalSize;
-            } else {
-                this.originalSize = size.width;
-                newSize.width = this.minimumSize;
-            }
-        }
-        this.element.jxLayout.resize(newSize);
-        this.splitter.sizeChanged();
-    },
-    
-    /**
-     * Method: sizeChanged
-     * Handle the size of the element changing to see if the
-     * toggle state has changed.
-     */
-    sizeChanged: function() {
-        var size = Element.getBorderBoxSize(this.element);
-        if (this.layout == 'vertical') {
-            if (size.height == this.minimumSize) {
-                Element.addClassName(this.snapper, 'jxSnapClosed');
-                Element.removeClassName(this.snapper, 'jxSnapOpened');
-            } else {
-                Element.addClassName(this.snapper, 'jxSnapOpened');
-                Element.removeClassName(this.snapper, 'jxSnapClosed');
-            }
-        } else {
-            if (size.width == this.minimumSize) {
-                Element.addClassName(this.snapper, 'jxSnapClosed');
-                Element.removeClassName(this.snapper, 'jxSnapOpened');
-            } else {
-                Element.addClassName(this.snapper, 'jxSnapOpened');
-                Element.removeClassName(this.snapper, 'jxSnapClosed');
-            }
-        }
-    }
-};/**
- * $Id: jxtab.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Tab
- *
- * Purpose: 
- * Implementation of a javascript tabbed panel capability for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-Jx.addStyleSheet('tab/tabs.css');
-Jx.addStyleSheet('tabs/tabs_ie.css', true);
-
-/**
- * Class: Jx.TabSet
- * A TabSet manages a set of <Jx.Tab> content areas by ensuring that only one
- * of the content areas is visible (i.e. the active tab).  TabSet does not
- * manage the actual tabs.  The instances of <Jx.Tab> that are to be managed
- * as a set have to be added to both a TabSet and a <Jx.Toolbar>.  The content
- * areas of the <Jx.Tab>s are sized to fit the content area that the TabSet
- * is managing.
- *
- * (code)
- * var tabBar = new Jx.Toolbar('tabBar');
- * var tabSet = new Jx.TabSet('tabArea');
- * 
- * var tab1 = new Jx.Tab('tab 1', {contentID: 'content1'});
- * var tab2 = new Jx.Tab('tab 2', {contentID: 'content2'});
- * var tab3 = new Jx.Tab('tab 3', {contentID: 'content3'});
- * var tab4 = new Jx.Tab('tab 4', {contentURL: 'test_content.html'});
- * 
- * tabSet.add(t1, t2, t3, t4);
- * tabBar.add(t1, t2, t3, t4);
- * (end)
- *
- * Inherits From:
- * <Jx.Listener>
- */
-Jx.TabSet = Class.create();
-Jx.TabSet.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} The HTML element that represents this tab set in the DOM.
-     * The content areas of each tab are sized to fill the domObj.
-     */
-    domObj : null,
-    /**
-     * Property: sl
-     * {Array} array of selection listeners.
-     */
-    sl: null,
-    /**
-     * Constructor: Jx.TabSet
-     * Create a new instance of <Jx.TabSet> within a specific element of
-     * the DOM.
-     *
-     * Parameters:
-     * domObj - {HTMLElement} an element or id of an element to put the
-     * content of the tabs into.
-     */
-    initialize : function(domObj) {
-        this.domObj = $(domObj);
-        if (!Element.hasClassName(this.domObj, 'jxTabSetContainer')) {
-            Element.addClassName(this.domObj, 'jxTabSetContainer');
-        }
-        this.sl = [];
-    },
-    /**
-     * Method: sizeChanged
-     * Respond to the size of the container changing.
-     *
-     * TODO: is this needed?
-     */
-    sizeChanged: function() { 
-      this.resizeTabBox(); 
-    },
-    /**
-     * Method: resizeTabBox
-     * Resize the tab set content area and propogate the changes to
-     * each of the tabs managed by the tab set.
-     */
-    resizeTabBox: function() {
-    
-        var parentSize = Element.getContentBoxSize(this.domObj.parentNode);
-        Element.setBorderBoxSize(this.domObj, {width: parentSize.width, height: parentSize.height});
-        // this is a bullshit hack for IE.  We need to set the tab content height
-        // for IE when the tabs are in a snap panel, otherwise the tab content
-        // doesn't collapse with the panel and no scrollbars appear.  This only
-        // affects the height.  In fact, setting the width breaks tab placement
-        
-        for (var i=0; i<this.domObj.childNodes.length; i++) {
-            // don't try to set the height on a text node 
-            if (this.domObj.childNodes[i].nodeType == 3) {
-                 continue;
-             }
-            Element.setBorderBoxSize(this.domObj.childNodes[i], {height: parentSize.height});
-            if (this.domObj.childNodes[i].resize) {
-                this.domObj.childNodes[i].resize({forceResize: true});
-            }
-        }
-    },
-    
-    /**
-     * Method: add
-     * Add one or more <Jx.Tab>s to the TabSet.
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} an instance of <Jx.Tab> to add to the tab set.  More
-     * than one tab can be added by passing extra parameters to this method.
-     */
-    add : function() {
-        for (var i=0; i<arguments.length; i++) {
-            var tab = arguments[i];
-            tab.addSelectionListener(this);
-            this.domObj.appendChild(tab.content);
-            if (!this.activeTab) {
-                this.setActiveTab(tab);
-            }
-        }
-    },
-    /**
-     * Method: remove
-     * Remove a tab from the TabSet.
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} the tab to remove.
-     *
-     * TODO: Implement remove for Jx.TabSet
-     */
-    remove : function(tab) {},
-    /**
-     * Method: setActiveTab
-     * Set the active tab to the one passed to this method
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} the tab to make active.
-     */
-    setActiveTab: function(tab) {
-        if (this.activeTab) {
-            Element.removeClassName(this.activeTab.domObj, 'tabActive');
-            Element.removeClassName(this.activeTab.content, 'tabContentActive');
-        }
-        this.activeTab = tab;
-        Element.addClassName(this.activeTab.domObj, 'tabActive');
-        Element.addClassName(this.activeTab.content, 'tabContentActive');
-        if (this.activeTab.content.resize) {
-          this.activeTab.content.resize({forceResize: true});
-        }
-    },
-    /**
-     * Method: selectionChanged
-     * Handle selection changing on the tabs themselves and activate the
-     * appropriate tab in response.
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} the tab to make active.
-     */
-    selectionChanged: function(tab) {
-        this.setActiveTab(tab);
-        this.processEvent(this.sl, 'selectionChanged', tab);
-    },
-    /**
-     * Method: addSelectionListener
-     * Add a selection listener
-     *
-     * Parameters:
-     * obj - {Object} the selection listener to add
-     */
-    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
-    /**
-     * Method: removeSelectionListener
-     * Remove a selection listener
-     *
-     * Parameters:
-     * obj - {Object} the selection listener to remove
-     */
-    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); }
-};
-Object.extend(Jx.TabSet.prototype, Jx.Listener.prototype);
-
-/**
- * Class: Jx.Tab
- * A single tab in a tab set.  A tab has a label (displayed in the tab) and a
- * content area that is displayed when the tab is active.  A tab has to be
- * added to both a <Jx.TabSet> (for the content) and <Jx.Toolbar> (for the
- * actual tab itself) in order to be useful.  Alternately, you can use
- * a <Jx.TabBox> which combines both into a single control at the cost of
- * some flexibility in layout options.
- *
- * A tab is a <Jx.ContentLoader> and you can specify the initial content of
- * the tab using any of the methods supported by 
- * <Jx.ContentLoader::loadContent>.  You can acccess the actual DOM element
- * that contains the content (if you want to dynamically insert content
- * for instance) via the <Jx.Tab::content> property.
- *
- * (code)
- * var tab1 = new Jx.Tab('tab 1', {contentID: 'content1'});
- * (end)
- *
- * Inherits From:
- * <Jx.Listener>, <Jx.ContentLoader>
- */
-Jx.Tab = Class.create();
-Jx.Tab.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} The button that is used to activate the tab.
-     */
-    domObj: null,
-    /**
-     * Property: content
-     * {HTMLElement} The content area that is displayed when the tab is active.
-     */
-    content: null,
-    /**
-     * Property: name
-     * {String} the name of the tab is also the label.
-     */
-    name: null,
-    /**
-     * Property: sl
-     * {Array} an array of selection listeners.
-     */
-    sl: null,
-    /**
-     * Constructor: Jx.Tab
-     * Create a new instance of Jx.Tab.
-     *
-     * Parameters:
-     * name - {String} the name (and label) of the tab.
-     * options - {Object} an object containing options that are used
-     * to control the appearance of the tab.  See 
-     * <Jx.ContentLoader::loadContent> and <Jx.Layout::Jx.Layout> for
-     * valid options.
-     */
-    initialize : function(name, options) {
-        this.sl = [];
-        options = options || {};
-        this.name = name;
-        this.content = document.createElement('div');
-        this.content.className = 'tabContent';
-        this.loadContent(this.content, options);
-        var a = new Jx.Action(this.clicked.bind(this));
-        var b = new Jx.Button(a, {label: name});
-        this.domObj = b.domA;
-        // rename the element from jxButton to jxTab
-        // Element.removeClassName(this.domObj, 'jxButton');
-        Element.addClassName(this.domObj, 'jxTab');
-        new Jx.Layout(this.content, options);
-        //this.content.resize = this.resize.bind(this);
-    },
-    /**
-     * Method: clicked
-     * Handle the tab being clicked by generating a selectionChanged
-     * event.
-     */
-    clicked: function() {
-        this.processEvent(this.sl, 'selectionChanged', this);
-        this.domObj.childNodes[0].blur();
-    },
-    /**
-     * Method: addSelectionListener
-     * Add a selection listener
-     *
-     * Parameters:
-     * obj - {Object} the selection listener to add
-     */
-    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
-    /**
-     * Method: removeSelectionListener
-     * Remove a selection listener
-     *
-     * Parameters:
-     * obj - {Object} the selection listener to remove
-     */
-    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); }
-};
-Object.extend(Jx.Tab.prototype, Jx.Listener.prototype);
-Object.extend(Jx.Tab.prototype, Jx.ContentLoader.prototype);
-
-/**
- * Class: Jx.TabBox
- * A convenience class to handle the common case of a single toolbar
- * directly attached to the content area of the tabs.  It manages both a
- * <Jx.Toolbar> and a <Jx.TabSet> so that you don't have to.  If you are using
- * a TabBox, then tabs only have to be added to the TabBox rather than to
- * both a <Jx.TabSet> and a <Jx.Toolbar>.
- *
- * (code)
- * var tabBox = new Jx.TabBox('subTabArea', 'top');
- * 
- * var tab1 = new Jx.Tab('Tab 1', {contentID: 'content4'});
- * var tab2 = new Jx.Tab('Tab 2', {contentID: 'content5'});
- * 
- * tabBox.add(tab1, tab2);
- * (end)
- *
- * Inherits From:
- * <Jx.Listener>
- */
-Jx.TabBox = Class.create();
-Jx.TabBox.prototype = {
-    /**
-     * Property: tabBar
-     * {<Jx.Toolbar>} the toolbar for this tab box.
-     */
-    tabBar: null,
-    /**
-     * Property: tabSet
-     * {<Jx.TabSet>} the tab set for this tab box.
-     */
-    tabSet: null,
-    /**
-     * Constructor: Jx.TabBox
-     */
-    initialize : function(domObj, position) {
-        var parent = $(domObj);
-        position = position || 'top';
-        var tabBarDiv = document.createElement('div');
-        parent.appendChild(tabBarDiv);
-        this.tabBar = new Jx.Toolbar(tabBarDiv, position);
-        this.tabSet = new Jx.TabSet(parent);
-        switch (position) {
-            case 'top':
-                Element.addClassName(parent, 'jxTabBoxTop');
-                break;
-            case 'bottom':
-                Element.addClassName(parent, 'jxTabBoxBottom');
-                break;
-            case 'left':
-                Element.addClassName(parent, 'jxTabBoxLeft');
-                Element.addClassName(tabBarDiv, 'verticalToolbar');
-                break;
-            case 'right':
-                Element.addClassName(parent, 'jxTabBoxRight');
-                Element.addClassName(tabBarDiv, 'verticalToolbar');
-                break;
-        }
-        this.sl = [];
-    },
-    /**
-     * Method: sizeChanged
-     * Handle the size of the content area of the tab box changing.
-     *
-     * TODO: is this needed?
-     */
-    sizeChanged: function() { this.tabSet.sizeChanged(); },
-    
-    /**
-     * Method: add
-     * Add one or more <Jx.Tab>s to the TabBox.
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} an instance of <Jx.Tab> to add to the tab box.  More
-     * than one tab can be added by passing extra parameters to this method.
-     * Unlike <Jx.TabSet>, tabs do not have to be added to a separate 
-     * <Jx.Toolbar>.
-     */
-    add : function() { 
-        this.tabBar.add.apply(this.tabBar, arguments); 
-        this.tabSet.add.apply(this.tabSet, arguments); 
-    },
-    /**
-     * Method: remove
-     * Remove a tab from the TabSet.
-     *
-     * Parameters:
-     * tab - {<Jx.Tab>} the tab to remove.
-     *
-     * TODO: implement remove for Jx.TabBox.
-     */
-    remove : function(tab) { /* TODO */ }
-};
-Object.extend(Jx.TabBox.prototype, Jx.Listener.prototype);
-/**
- * $Id: jxtoolbar.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Toolbar
- *
- * Purpose: 
- * Implementation of a javascript Toolbar for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-/**
- * import stylesheets
- */
-Jx.addStyleSheet('toolbar/toolbar.css');
-Jx.addStyleSheet('button/button.css');
-
-/**
- * Class: Jx.Toolbar
- *
- * A toolbar is a container object that contains other objects such as
- * buttons.  The toolbar organizes the objects it contains automatically,
- * wrapping them as necessary.  Multiple toolbars may be placed within
- * the same containing object.
- *
- * Jx.Toolbar includes CSS classes for styling the appearance of a
- * toolbar to be similar to traditional desktop application toolbars.
- *
- * There is one special object, Jx.ToolbarSeparator, that provides
- * a visual separation between objects in a toolbar.
- *
- * The following example shows how to create a Jx.Toolbar instance and place two objects in it.
- * (code)
- * //myToolbarContainer is the id of a <div> in the HTML page.
- * function myFunction() {}
- * var myToolbar = new Jx.Toolbar('myToolbarContainer');
- * 
- * var myAction = new Jx.Action(myFunction):
- * var myButton = new Jx.Button(myAction);
- *
- * var myElement = document.createElement('select');
- *
- * myToolbar.add(myButton, new Jx.ToolbarSeparator(), myElement);
- * (end)
- *
- * While a toolbar is generally a *dumb* container, it serves a special purpose
- * for menus by providing some infrastructure so that menus can behave
- * properly.
- *
- * In general, almost anything can be placed in a Toolbar, and mixed with 
- * anything else.
- */
-Jx.Toolbar = Class.create();
-Jx.Toolbar.prototype = {
-    /**
-     * Property: items
-     * {Array} an array of the things in the toolbar.
-     */
-    items : null,
-    /**
-     * Property: domObj
-     * {HTMLElement} the HTML element that the toolbar lives in
-     */
-    domObj : null,
-    /**
-     * Property: isActive
-     * When a toolbar contains <Jx.Menu> instances, they want to know
-     * if any menu in the toolbar is active and this is how they
-     * find out.
-     */
-    isActive : false,
-    /**
-     * Constructor: Jx.Toolbar
-     * Create a new instance of Jx.Toolbar.
-     *
-     * Parameters:
-     * domObj - {HTMLElement} object reference or id to place the toolbar in.
-     * position - one of 'top', 'right', 'bottom', or 'left', indicates how
-     * the toolbar is being placed in the page and may influence the behaviour
-     * of items in the toolbar that open sub panels, they will tend to open
-     * them towards the center of the page.  Default is top.
-     */
-    initialize : function(domObj, position) {
-        var parent = $(domObj);
-        this.domObj = document.createElement('ul');
-        Element.addClassName(this.domObj,'jxToolbar');
-        
-        if (!Element.hasClassName(parent, 'jxToolbarContainer')) {
-            Element.addClassName(parent, 'jxToolbarContainer');
-            parent.appendChild(this.domObj);
-            var clearer = document.createElement('div');
-            clearer.className = 'jxClearer';
-            parent.appendChild(clearer);                    
-        } else {
-            parent.insertBefore(this.domObj, parent.lastChild);
-        }
-        switch (position) {
-            case 'top':
-                Element.addClassName(parent, 'jxBarTop');
-                break;
-            case 'right':
-                Element.addClassName(parent, 'jxBarRight');
-                break;
-            case 'bottom':
-                Element.addClassName(parent, 'jxBarBottom');
-                break;
-            case 'left':
-                Element.addClassName(parent, 'jxBarLeft');
-                break;
-            default:
-                Element.addClassName(parent, 'jxBarTop');
-        }
-        this.deactivateWatcher = this.deactivate.bindAsEventListener(this);
-        
-    },
-    /**
-     * Method: add
-     * Add an item to the toolbar.  If the item being added is a Jx component
-     * with a domObj property, the domObj is added.  If the item being added
-     * is an LI element, then it is given a CSS class of *jxToolItem*.
-     * Otherwise, the thing is wrapped in a <Jx.ToolbarItem>.
-     *
-     * Parameters:
-     * thing - {Object} the thing to add.  More than one thing can be added
-     * by passing multiple arguments.
-     */
-    add : function( ) {
-        for (var i=0; i<arguments.length; i++) {
-            var thing = arguments[i];
-            thing.toolbar = this;
-            if (thing.domObj) {
-                thing = thing.domObj;
-            }
-            if (thing.tagName == 'LI') {
-                if (!Element.hasClassName(thing, 'jxToolItem')) {
-                    Element.addClassName(thing, 'jxToolItem');
-                }
-                this.domObj.appendChild(thing);
-            } else {
-                var item = new Jx.ToolbarItem(thing);
-                this.domObj.appendChild(item.domObj);
-            }
-        }
-    },
-    /**
-     * Method: deactivate
-     * Deactivate the Toolbar (when it is acting as a menu bar).
-     */
-    deactivate: function() {
-        for (var i=0; i<this.items.length; i++) {
-            this.items[i].hide();
-        }
-        this.setActive(false);
-    },
-    /**
-     * Method: isActive
-     * Indicate if the toolbar is currently active (as a menu bar)
-     *
-     * Returns:
-     * {Boolean}
-     */
-    isActive: function() { 
-        return this.isActive; 
-    },
-    /**
-     * Method: setActive
-     * Set the active state of the toolbar (for menus)
-     *
-     * Parameters: 
-     * b - {Boolean} the new state
-     */
-    setActive: function(b) { 
-        this.isActive = b;
-        if (this.isActive) {
-            Event.observe(document, 'click', this.deactivateWatcher);
-        } else {
-            Event.stopObserving(document, 'click', this.deactivateWatcher);
-        }
-    },
-    /**
-     * Method: setVisibleItem
-     * For menus, they want to know which menu is currently open.
-     *
-     * Parameters:
-     * obj - {<Jx.Menu>} the menu that just opened.
-     */
-    setVisibleItem: function(obj) {
-        if (this.visibleItem && this.visibleItem.hide && this.visibleItem != obj) {
-            this.visibleItem.hide();
-        }
-        this.visibleItem = obj;
-        if (this.isActive()) {
-            this.visibleItem.show();
-        }
-    }
-};
-
-/**
- * Class: Jx.ToolbarItem
- * A helper class to provide a container for something to go into 
- * a <Jx.Toolbar>.
- */
-Jx.ToolbarItem = Class.create();
-Jx.ToolbarItem.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} an element to contain the thing to be placed in the
-     * toolbar.
-     */
-    domObj: null,
-    /**
-     * Constructor: Jx.ToolbarItem
-     * Create a new instance of Jx.ToolbarItem.
-     *
-     * Parameters:
-     * jxThing - {Object} the thing to be contained.
-     */
-    initialize : function( jxThing ) {
-        this.al = [];
-        this.domObj = document.createElement('li');
-        this.domObj.className = 'jxToolItem';
-        if (jxThing) {
-            if (jxThing.domObj) {
-                this.domObj.appendChild(jxThing.domObj);
-                if (jxThing instanceof Jx.Tab) {
-                    // this.domObj.className = 'jxTabItem';
-                    Element.addClassName(this.domObj, 'jxTabItem');
-                }
-            } else {
-                this.domObj.appendChild(jxThing);
-                if (Element.hasClassName(jxThing, 'jxTab')) {
-                    // this.domObj.className = 'jxTabItem';
-                    Element.addClassName(this.domObj, 'jxTabItem');
-                }
-            }
-        }
-    }
-};
-
-/**
- * Class: Jx.ToolbarSeparator
- * A helper class that represents a visual separator in a <Jx.Toolbar>
- */
-Jx.ToolbarSeparator = Class.create();
-Jx.ToolbarSeparator.prototype = {
-    /**
-     * Property: domObj
-     * {HTMLElement} The DOM element that goes in the <Jx.Toolbar>
-     */
-    domObj: null,
-    /**
-     * Constructor: Jx.ToolbarSeparator
-     * Create a new Jx.ToolbarSeparator
-     */
-    initialize: function() {
-        this.domObj = document.createElement('li');
-        this.domObj.className = 'jxToolItem';
-        this.domSpan = document.createElement('span');
-        this.domSpan.className = 'separator';
-        this.domObj.appendChild(this.domSpan);
-    }
-};
-
-/**
- * $Id: jxtree.js 512 2008-03-07 21:15:45Z pspencer $
- *
- * Title: Jx.Tree
- *
- * Purpose: 
- * Implementation of a javascript Tree for Jx.
- *
- * Author: 
- * Paul Spencer (pspencer at dmsolutions.ca)
- *
- * Copyright:
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/
-
-Jx.addStyleSheet('tree/tree.css');
-Jx.addStyleSheet('tree/tree_ie.css', true);
-
-/**
- * Class: Jx.TreeItem 
- * An item in a tree.  An item is a leaf node that has no children.
- *
- * Jx.TreeItem supports selection listeners.  When an item in the tree
- * is selected by the user, listeners are called by invoking the
- * selectionChanged method on the listener and passing the tree item
- * object that was selected.  The application is responsible for
- * changing the style of the selected item in the tree and for
- * tracking selection if that is important.
- * 
- * When the selection changes, the mouse event that triggered the
- * selection change is passed to the listener as a lastEvent
- * member of the tree item object.  You can use this to determine
- * if the item was clicked, double-clicked, right clicked etc.
- *
- * Inherits From:
- * <Jx.Listener>
- */
-Jx.TreeItem = Class.create();
-Jx.TreeItem.prototype = {
-    /**
-     * Property: data
-     * {Object} arbitrary data associated with the TreeItem
-     */
-    data : null,
-    /**
-     * Property: domObj
-     * {HTMLElement} a reference to the HTML element that is the TreeItem
-     * in the DOM
-     */
-    domObj : null,
-    /**
-     * Property: parent
-     * {Object} the folder or tree that this item belongs to
-     */
-    parent : null,
-    /**
-     * Property: currentClassName
-     * {String} the current CSS class name for this TreeItem.
-     *
-     * TODO: Property currentClassName
-     * This property does not appear to be used?
-     */
-    currentClassName : null,
-    /**
-     * Property: onClick
-     * {Function} callback function to invoke with the TreeItem is clicked
-     */
-    onClick : null,
-    /**
-     * Property: sl
-     * {Array} an array of selection listeners
-     */
-    sl : null,
-    /**
-     * Property: enabled
-     * {Boolean} is the TreeItem enabled or not?
-     */
-    enabled : null,
-    /**
-     * Property: contextMenu
-     *
-     * {<Jx.ContextMenu>} an optional context menu for the TreeItem
-     */
-    contextMenu : null,
-    /**
-     * Constructor: Jx.TreeItem
-     * Create a new instance of Jx.TreeItem with the associated options
-     *
-     * Parameters:
-     * options - {Object} an object containing the below optional
-     * attributes that control how the TreeItem functions.
-     *
-     * Options:
-     * label - {String} the label to display for the TreeItem
-     * data - {Object} any arbitrary data to be associated with the TreeItem
-     * contextMenu - {<Jx.ContextMenu>} the context menu to trigger if there
-     *      is a right click on the node
-     * imgNode - {String} URL to an image to use for the node of this 
-     *      TreeItem.  Not sure if this should ever be set.
-     * imgIcon - {String} URL to an image to use as the icon next to the
-     *      label of this TreeItem
-     * enabled - {Boolean} the initial state of the TreeItem.  If the 
-     *      TreeItem is not enabled, it cannot be clicked.
-     */
-    initialize : function( options ) {
-        this.initializeItem(options);
-    },
-    /**
-     * Method: initializeItem
-     * internal method to initialize the TreeItem.
-     *
-     * Parameters: 
-     * options - See <Jx.TreeItem::Jx.TreeItem>
-     */
-    initializeItem: function(options) {
-        options = options || {};
-        this.sl = [];
-        var label = options.label || 'new node';
-        this.data = options.data || null;
-        this.contextMenu = options.contextMenu || null;
-        
-        this.imgNode = options.imgNode || Jx.baseURL + 'images/tree_none.png';
-        this.imgIcon = options.imgIcon || Jx.baseURL + 'images/tree_page.png';
-                
-        this.domObj = document.createElement('li');
-        this.domObj.className = 'jxTreeNode';
-        this.currentClassName = 'jxTreeNode';
-      
-        var elm = document.createElement('img');
-        elm.className = 'jxTreeNodeImage';
-        //elm.src = this.imgNode;
-        Jx.addToImgQueue({domElement: elm, src: this.imgNode});
-        this.domObj.appendChild(elm);
-        
-        elm = document.createElement('img');
-        elm.className = 'jxTreeNodeIcon';
-        //elm.src = this.imgIcon;
-        Jx.addToImgQueue({domElement: elm, src: this.imgIcon});
-        this.domObj.appendChild(elm);
-      
-        elm = document.createElement('a');
-        elm.href = 'javascript:void(0)';
-        elm.onclick = this.selected.bindAsEventListener(this);
-        elm.ondblclick = this.selected.bindAsEventListener(this);
-        elm.oncontextmenu = this.showMenu.bindAsEventListener(this);
-        elm.innerHTML = label;
-        this.domObj.appendChild(elm);
-        
-        //this.update(false);
-        //TODO: this could cause a memory leak in remove
-        this.domObj.jxTreeItem = this;
-        this.domObj.childNodes[2].jxTreeItem = this;
-        
-        this.onClick = options.onClick || null;
-        this.enabled = typeof options.enabled != 'undefined' ? options.enabled : true;
-        if (this.enabled) {
-            Element.removeClassName(this.domObj, 'jxDisabled');
-        } else {
-            Element.addClassName(this.domObj, 'jxDisabled');
-        }
-        var clearer = document.createElement('span');
-        clearer.className = 'jxClearer';
-        this.domObj.appendChild(clearer);
-    },
-    /**
-     * Method: finalize
-     * Clean up the TreeItem and remove all DOM references
-     */
-    finalize: function() { this.finalizeItem(); },
-    /**
-     * Method: finalizeItem
-     * Clean up the TreeItem and remove all DOM references
-     */
-    finalizeItem: function() {  
-        if (!this.domObj) {
-            return;
-        }
-        this.domObj.childNodes[2].onclick = null;
-        this.domObj.childNodes[2].ondblclick = null;
-        this.domObj.childNodes[2].oncontextmenu = null;
-        this.contextMenu = null;
-        this.onClick = null;
-        for (var i=this.sl.length; i>=0; i--) {
-            this.removeSelectionListener(this.sl[i]);
-        }
-        this.parent = null;
-        this.domObj.jxTreeItem = null;
-        this.domObj = null;
-    },
-    /**
-     * Method: clone
-     * Create a clone of the TreeItem
-     * 
-     * Returns: 
-     * {<Jx.TreeItem>} a copy of the TreeItem
-     */
-    clone : function() {
-        var options = { label : this.domObj.childNodes[2].innerHTML, 
-                        data : this.data,
-                        onClick : this.onClick,
-                        imgNode : this.imgNode,
-                        imgIcon : this.imgIcon
-                        };
-        var item = new Jx.TreeItem(options);
-        return item;
-    },
-    /**
-     * Method: update
-     * Update the CSS of the TreeItem's DOM element in case it has changed
-     * position
-     *
-     * Parameters:
-     * shouldDescend - {Boolean} propagate changes to child nodes?
-     */
-    update : function(shouldDescend) {
-        var isLast = (arguments.length > 1) ? arguments[1] : 
-                     (this.parent && this.parent.isLastNode(this));
-        if (isLast) {
-            Element.removeClassName(this.domObj, 'jxTreeNode');
-            Element.addClassName(this.domObj, 'jxTreeNodeLast');
-        } else {
-            Element.removeClassName(this.domObj, 'jxTreeNodeLast');
-            Element.addClassName(this.domObj, 'jxTreeNode');
-        }
-    },
-    /**
-     * Method: selected
-     * Called when the DOM element for the TreeItem is clicked, the
-     * node is selected.
-     *
-     * Parameters:
-     * e - {Event} the DOM event
-     */
-    selected : function(e) {
-        this.lastEvent = e?e:event;
-        this.processEvent(this.sl,'selectionChanged',this);
-    },
-    /**
-     * Method: showMenu
-     * Called when the DOM element for the TreeItem is right-clicked.  The
-     * node is selected and the context menu displayed (if there is one).
-     *
-     * Parameters:
-     * e - {Event} the DOM event
-     */
-    showMenu: function(e) {
-        this.lastEvent = e?e:event;
-        this.processEvent(this.sl,'selectionChanged',this);
-        if (this.contextMenu) {
-            this.contextMenu.show(this.lastEvent);
-        }
-        Event.stop(e);
-    },
-    /**
-     * Method: addSelectionListener
-     * Add a selection listener.
-     *
-     * Parameters:
-     * obj - {Object} the object to add as a selection listener
-     */
-    addSelectionListener: function(obj){this.addListener(this.sl, obj);},
-    /**
-     * Method: removeSelectionListener
-     * Remove a selection listener.
-     *
-     * Parameters:
-     * obj - {Object} the object to remove as a selection listener
-     */
-    removeSelectionListener: function(obj) {this.removeListener(this.sl, obj);},
-    /**
-     * Method: getName
-     * Get the label associated with a TreeItem
-     *
-     * Returns: 
-     * {String} the name
-     */
-    getName : function() { return this.domObj.childNodes[2].innerHTML; },
-    /**
-     * Method: setName
-     * Set the label of a TreeItem
-     *
-     * Parameters:
-     * name - {String} the new label
-     */
-    setName : function(name) { this.domObj.childNodes[2].innerHTML = name; },
-    /**
-     * Method: propertyChanged
-     * A property of an object has changed, synchronize the state of the 
-     * TreeItem with the state of the object
-     *
-     * Parameters:
-     * obj - {Object} the object whose state has changed
-     */
-    propertyChanged : function(obj) {
-        this.enabled = obj.isEnabled();
-        if (this.enabled) {
-            Element.removeClassName(this.domObj, 'jxDisabled');
-        } else {
-            Element.addClassName(this.domObj, 'jxDisabled');
-        }
-    }
-};
-Object.extend(Jx.TreeItem.prototype, Jx.Listener.prototype);
-
-/**
- * Class: Jx.TreeFolder
- *
- * A Jx.TreeFolder is an item in a tree that can contain other items.  It is
- * expandable and collapsible.
- *
- * Inherits From:
- * <Jx.TreeItem>
- */
-Jx.TreeFolder = Class.create();
-Object.extend(Jx.TreeFolder.prototype, Jx.TreeItem.prototype);
-Object.extend(Jx.TreeFolder.prototype, {
-    /**
-     * Property: subDomObj
-     * {HTMLElement} an HTML container for the things inside the folder
-     */
-    subDomObj : null,
-    /**
-     * Property: nodes
-     * {Array} an array of references to the javascript objects that are
-     * children of this folder
-     */
-    nodes : null,
-    /**
-     * Property: isOpen
-     * {Boolean} is the folder open or not?
-     */
-    isOpen : false,
-    /**
-     * Property: dl
-     * {Array} disclosure listeners
-     */
-    dl : null,
-    /**
-     * Constructor: Jx.TreeFolder
-     * Create a new instance of Jx.TreeFolder
-     *
-     * Parameters:
-     * options - {Object} an object containing any of the options of a
-     * <Jx.TreeItem> (see <Jx.TreeItem::Jx.TreeItem>) plus the following
-     * optional attributes that control how the TreeFolder functions.
-     *
-     * Options:
-     * imgTreePlus - {String} a URL to an image for opening the folder
-     * imgTreeMinus - {String} a URL to an image for closing the folder
-     * imgTreeFolder - {String} a URL to an image to represent the folder
-     *      when it is closed
-     * imgTreeFolderOpen - {String} a URL to an image to represent the folder
-     *      when it is open
-     */
-    initialize : function( options ) {
-        this.initializeFolder(options);
-    },
-    /**
-     * Method: initializeFolder
-     * Internal method for initializing a folder.
-     *
-     * Parameters:
-     * options - {Object} see <Jx.TreeFolder::Jx.TreeFolder> for options.
-     */
-    initializeFolder : function(options) {
-        options = options || {};
-        this.initializeItem(options);
-        
-        this.imgTreePlus = options.imgTreePlus || Jx.baseURL + 'images/tree_plus.png';
-        this.imgTreeMinus = options.imgTreeMinus || Jx.baseURL + 'images/tree_minus.png';
-        
-        this.imgTreeFolder = options.imgTreeFolder || Jx.baseURL + 'images/tree_folder.png';
-        this.imgTreeFolderOpen = options.imgTreeFolderOpen || Jx.baseURL + 'images/tree_folder_open.png';
-        
-        //console.log('imgTreePlus is ' + this.imgTreePlus);
-        //this.domObj.childNodes[0].src = this.imgTreePlus;
-        //this.domObj.childNodes[1].src = this.imgTreeFolder;
-        Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreePlus});
-        Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolder});
-        
-        this.domObj.childNodes[0].onclick = this.clicked.bindAsEventListener(this);
-                
-        this.nodes = [];
-        this.subDomObj = document.createElement('ul');
-        this.domObj.appendChild(this.subDomObj);
-        this.subDomObj.className = 'jxTree';
-        this.isOpen = options.isOpen || false;
-        this.dl = [];
-        if (this.isOpen) {
-            this.expand();
-        } else {
-            this.collapse();
-        }
-    //this.makeDroppable();
-    },
-    /**
-     * Method: finalize
-     * Clean up a TreeFolder.
-     */
-    finalize: function() {
-        this.finalizeFolder();
-        this.finalizeItem();
-        this.subDomObj = null;
-    },
-    /**
-     * Method: finalizeFolder
-     * Internal method to clean up folder-related stuff.
-     */
-    finalizeFolder: function() {
-        this.domObj.childNodes[0].onclick = null;
-        for (var i=this.nodes.length-1; i>=0; i--) {
-            this.nodes[i].finalize();
-            if (this.nodes[i].domObj) this.subDomObj.removeChild(this.nodes[i].domObj);
-            this.nodes.pop();
-        }
-        for (var i=this.dl.length-1; i>=0; i--) {
-            this.removeDisclosureListener(this.dl[i]);
-        }
-    },
-    /*
-    makeDroppable : function() {
-        if (!document.Jx.TreeCurrentTimeout) document.Jx.TreeCurrentTimeout = null;
-        Droppables.add(this.domObj.childNodes[2], {
-            greedy : true,
-            onHover : function(draggable, droppable, overlap) { 
-                var dropped = droppable.parentNode.jxTreeItem;
-                if (document.Jx.TreeCurrentTimeout && 
-                    document.currentDroppable != droppable) {
-                    window.clearTimeout(document.Jx.TreeCurrentTimeout);
-                    document.Jx.TreeCurrentTimeout = null;
-                }
-                if (!document.Jx.TreeCurrentTimeout && 
-                    dropped.nodes && 
-                    !dropped.isOpen)
-                {
-                    document.Jx.TreeCurrentTimeout = window.setTimeout(dropped.expand.bind(dropped), 700);
-                }
-                
-                if (!document.currentHighlight != droppable) {
-                    if (droppable == draggable)
-                    {
-                        Droppables.remove(droppable);
-                    }
-                    if (document.currentDroppable && 
-                        document.currentDroppable != droppable) {
-                        Element.removeClassName(document.currentDroppable, 
-                                                'jxTreeDropzone');
-                    }
-                    
-                    Element.addClassName(droppable, 'jxTreeDropzone');
-                    document.currentDroppable = droppable;
-                }
-            },
-            onDrop : function(draggable, droppable) {
-                var dragged = draggable.jxTreeItem;
-                var dropped = droppable.parentNode.jxTreeItem;
-
-                Element.removeClassName(droppable, 
-                                            'jxTreeDropzone');
-                if (dropped.nodes) {
-                    dragged.parent.remove(dragged);
-                    dropped.append(dragged);
-                    dropped.expand();
-                } else if (dropped.parent != null) {
-                    dragged.parent.remove(dragged);
-                    dropped.parent.insert(dragged,dropped);
-                }
-            }
-        });
-    },
-    */
-    /**
-     * Method: clone
-     * Create a clone of the TreeFolder
-     * 
-     * Returns: 
-     * {<Jx.TreeFolder>} a copy of the TreeFolder
-     */
-    clone : function() {
-        var options = { label : this.domObj.childNodes[2].innerHTML, 
-                        data : this.data,
-                        onClick : this.onClick,
-                        imgTreePlus : this.imgTreePlus,
-                        imgTreeMinus : this.imgTreeMinus,
-                        imgTreeFolder : this.imgTreeFolder,
-                        imgTreeFolderOpen : this.imgTreeFolderOpen
-                        };
-        var node = new Jx.TreeFolder(options);
-        for (var i=0;i<this.nodes.length;i++) {
-            node.append(this.nodes[i].clone());
-        }
-        return node;
-    },
-    /**
-     * Method: isLastNode
-     * Indicates if a node is the last thing in the folder.
-     *
-     * Parameters:
-     * node - {Jx.TreeItem} the node to check
-     *
-     * Returns:
-     *
-     * {Boolean}
-     */
-    isLastNode : function(node) {
-        if (this.nodes.length == 0) {
-            return false;
-        } else {
-            return this.nodes[this.nodes.length-1] == node;
-        }
-    },
-    /**
-     * Method: update
-     * Update the CSS of the TreeFolder's DOM element in case it has changed
-     * position.
-     *
-     * Parameters:
-     * shouldDescend - {Boolean} propagate changes to child nodes?
-     */
-    update : function(bDescend) {
-        /* avoid update if not attached to tree yet */
-        if (!this.parent) return;
-        var bLast = false;
-        if (arguments.length > 1) {
-            bLast = arguments[1];
-        } else {
-            bLast = (this.parent && this.parent.isLastNode(this));
-        }
-        
-        if (bLast) {
-            this.domObj.className = 'jxTreeNodeLast';
-            this.subDomObj.className = 'jxTree';
-        } else {
-            this.domObj.className = 'jxTreeNode';
-            this.subDomObj.className = 'jxTree jxTreeNest';
-        }
-        
-        if (this.isOpen) {
-            //this.domObj.childNodes[0].src = this.imgTreeMinus;
-            //this.domObj.childNodes[1].src = this.imgTreeFolderOpen;
-            Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreeMinus});
-            Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolderOpen});
-        } else {
-            //this.domObj.childNodes[0].src = this.imgTreePlus;
-            //this.domObj.childNodes[1].src = this.imgTreeFolder;
-            Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreePlus});
-            Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolder});
-        }
-        
-        if (this.nodes && bDescend) {
-            //this.nodes.each(function(n){n.update(true);});
-            for(var i=0; i<this.nodes.length; i++) {
-                this.nodes[i].update(false, i==this.nodes.length-1);
-            }
-        }
-    },
-    /**
-     * Method: append
-     * append a node at the end of the sub-tree
-     *
-     * Parameters:
-     * node - {Object} the node to append.
-     */
-    append : function( node ) {
-        node.parent = this;
-        this.nodes.push(node);
-        this.subDomObj.appendChild( node.domObj );
-        this.update(true);
-    },
-    /**
-     * Method: insert
-     * insert a node after refNode.  If refNode is null, insert at beginning
-     *
-     * Parameters:
-     * node - {Object} the node to insert
-     * refNode - {Object} the node to insert before
-     */
-    insert : function( node, refNode ) {
-        node.parent = this;
-        //if refNode is not supplied, insert at the beginning.
-        if (!refNode) {
-            this.nodes.unshift(node);
-            //sanity check to make sure there is actually something there
-            if (this.subDomObj.childNodes.length ==0) {
-                this.subDomObj.appendChild(node.domObj);
-            } else {
-                this.subDomObj.insertBefore(node.domObj, this.subDomObj.childNodes[0]);                
-            }
-        } else {
-            //walk all nodes looking for the ref node.  Track if it actually
-            //happens so we can append if it fails.
-            var b = false;
-            for(var i=0;i<this.nodes.length;i++) {
-                if (this.nodes[i] == refNode) {
-                    //increment to append after ref node.  If this pushes us
-                    //past the end, it'll get appended below anyway
-                    i = i + 1;
-                    if (i < this.nodes.length) {
-                        this.nodes.splice(i, 0, node);
-                        this.subDomObj.insertBefore(node.domObj, this.subDomObj.childNodes[i]);
-                        b = true;
-                        break;
-                    }
-                }
-            }
-            //if the node wasn't inserted, it is because refNode didn't exist
-            //and so the fallback is to just append the node.
-            if (!b) {
-                this.nodes.push(node); 
-                this.subDomObj.appendChild(node.domObj); 
-            }
-        }
-        this.update(true);
-        //if (this.parent)
-        //    this.parent.update(true);        
-    },
-    /**
-     * Method: remove
-     * remove the specified node from the tree
-     *
-     * Parameters:
-     * node - {Object} the node to remove
-     */
-    remove : function(node) {
-        node.parent = null;
-        for(var i=0;i<this.nodes.length;i++) {
-            if (this.nodes[i] == node) {
-                this.nodes.splice(i, 1);
-                this.subDomObj.removeChild(this.subDomObj.childNodes[i]);
-                break;
-            }
-        }
-        this.update(true);
-        //if (this.parent)
-        //    this.parent.update(true);        
-    },
-    /**
-     * Method: replace
-     * Replace a node with another node
-     *
-     * Parameters:
-     * newNode - {Object} the node to put into the tree
-     * refNode - {Object} the node to replace
-     *
-     * Returns:
-     * {Boolean} true if the replacement was successful.
-     */
-    replace: function( newNode, refNode ) {
-        //walk all nodes looking for the ref node. 
-        var b = false;
-        for(var i=0;i<this.nodes.length;i++) {
-            if (this.nodes[i] == refNode) {
-                if (i < this.nodes.length) {
-                    newNode.parent = this;
-                    this.nodes.splice(i, 1, newNode);
-                    this.subDomObj.replaceChild(newNode.domObj, refNode.domObj);
-                    return true;
-                }
-            }
-        }
-        return false;
-    },
-    
-    /**
-     * Method: clicked
-     * handle the user clicking on this folder by expanding or
-     * collapsing it.
-     *
-     * Parameters: 
-     * e - {Event} the event object
-     */
-    clicked : function(e) {
-        e = e?e:event;
-        if (this.isOpen) {
-            this.collapse();
-        } else {
-            this.expand();
-        }
-    },
-    /**
-     * Method: expand
-     * Expands the folder
-     */
-    expand : function() {
-        this.isOpen = true;
-        this.subDomObj.style.display = 'block';
-        this.update(true);
-        this.processEvent(this.dl, 'disclosed', this);    
-    },
-    /**
-     * Method: collapse
-     * Collapses the folder
-     */
-    collapse : function() {
-        this.isOpen = false;
-        this.subDomObj.style.display = 'none';
-        this.update(true);
-        this.processEvent(this.dl, 'disclosed', this);
-    },
-    /**
-     * Method: addDisclosureListener
-     * Add a disclosure (when the folder is opened) listener
-     *
-     * Parameters:
-     * obj - {Object} a discloser listener to add
-     */
-    addDisclosureListener: function(obj){this.addListener(this.dl, obj);},
-    /**
-     * Method: removeDisclosureListener
-     * Remove a disclosure listener
-     *
-     * Parameters:
-     * obj - {Object} a discloser listener to remove
-     */
-    removeDisclosureListener: function(obj) {this.removeListener(this.dl, obj);},
-    /**
-     * Method: findChild
-     * Get a reference to a child node by recursively searching the tree
-     * 
-     * Parameters:
-     * path - {Array} an array of labels of nodes to search for
-     *
-     * Returns:
-     * {Object} the node or null if the path was not found
-     */
-    findChild : function(path) {
-        //path is empty - we are asking for this node
-        if (path.length == 0)
-            return this;
-        
-        //path has only one thing in it - looking for something in this folder
-        if (path.length == 1)
-        {
-            for (var i=0; i<this.nodes.length; i++)
-            {
-                if (this.nodes[i].getName() == path[0])
-                    return this.nodes[i];
-            }
-            return null;
-        }
-        //path has more than one thing in it, find a folder and descend into it    
-        var childName = path.shift();
-        for (var i=0; i<this.nodes.length; i++)
-        {
-            if (this.nodes[i].getName() == childName && this.nodes[i].findChild)
-                return this.nodes[i].findChild(path);
-        }
-        return null;
-    }
-});
-
-/**
- * Class: Jx.Tree
- * Jx.Tree displays hierarchical data in a tree structure of folders and nodes.
- *
- * Inherits From:
- * <Jx.TreeFolder>
- */
-Jx.Tree = Class.create();
-Object.extend( Jx.Tree.prototype, Jx.TreeFolder.prototype );
-Object.extend( Jx.Tree.prototype, {
-    /**
-     * Constructor: Jx.Tree
-     * Create a new instance of Jx.Tree
-     *
-     * Parameters:
-     * id - {String} the id of the DOM element to create the tree inside.
-     */
-    initialize : function( id ) {
-        this.subDomObj = document.createElement('ul');
-        this.subDomObj.className = 'jxTreeRoot';
-        $(id).appendChild(this.subDomObj);
-        this.nodes = [];
-        this.dl = [];
-        this.isOpen = true;
-    },
-    /**
-     * Method: finalize
-     * Clean up a Jx.Tree instance
-     */
-    finalize: function() { 
-        this.clear(); 
-        this.subDomObj.parentNode.removeChild(this.subDomObj); 
-    },
-    /**
-     * Method: clear
-     * Clear the tree of all child nodes
-     */
-    clear: function() {
-        for (var i=this.nodes.length-1; i>=0; i--) {
-            this.subDomObj.removeChild(this.nodes[i].domObj);
-            this.nodes[i].finalize();
-            this.nodes.pop();
-        }
-    },
-    /**
-     * Method: update
-     * Update the CSS of the Tree's DOM element in case it has changed
-     * position
-     *
-     * Parameters:
-     * shouldDescend - {Boolean} propagate changes to child nodes?
-     */
-    update: function(shouldDescend) {
-        var bLast = true;
-        if (this.subDomObj)
-        {
-            if (bLast) {
-                Element.removeClassName(this.subDomObj, 'jxTreeNest');
-            } else {
-                Element.addClassName(this.subDomObj, 'jxTreeNest');
-            }
-        }
-        if (this.nodes && shouldDescend) {
-            this.nodes.each(function(n){n.update(false);});
-        }
-    },
-    /**
-     * Method: append
-     * Append a node at the end of the sub-tree
-     * 
-     * Parameters:
-     * node - {Object} the node to append.
-     */
-    append: function( node ) {
-        node.parent = this;
-        this.nodes.push(node);
-        this.subDomObj.appendChild( node.domObj );
-        this.update(true);        
-    }
-});/**
- * this file is to be loaded/included after all other Jx files 
- *
- * Copyright &copy; 2008, DM Solutions Group Inc.
- */
-/******************************************************************************
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *****************************************************************************/ 
-
-if (Jx.COMBINED_CSS) {
-    //console.log('Jx.COMBINED_CSS');
-    document.write('<link type="text/css" rel="stylesheet" href="'+Jx.baseURL+'lib/jx_combined.css" />\n');
-} else {
-    //console.log('no Jx.COMBINED_CSS');
-    for (var styleSheet in Jx.importRules) {
-        var url = Jx.baseURL+styleSheet;
-        document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');
-    }
-    document.write('<!--[if IE]>');
-    for (var styleSheet in Jx.importRulesIE) {
-        var url = Jx.baseURL+styleSheet;
-        document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');
-    }
-    document.write('<![endif]-->\n');
-}
\ No newline at end of file

Copied: sandbox/aboudreault/jx/lib/jx_combined.js (from rev 1352, trunk/jx/lib/jx_combined.js)
===================================================================
--- sandbox/aboudreault/jx/lib/jx_combined.js	                        (rev 0)
+++ sandbox/aboudreault/jx/lib/jx_combined.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,14057 @@
+/******************************************************************************
+ *  Prototype JavaScript framework, version 1.5.0
+ *  (c) 2005-2007 Sam Stephenson
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ ******************************************************************************
+ * Jx UI Library, version 1.0
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ * Jx is freely distributable under the terms of an MIT-style license.
+ *****************************************************************************/
+/*  Prototype JavaScript framework, version 1.5.0
+ *  (c) 2005-2007 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.5.0',
+  BrowserFeatures: {
+    XPath: !!document.evaluate
+  },
+
+  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+  emptyFunction: function() {},
+  K: function(x) { return x }
+}
+
+var Class = {
+  create: function() {
+    return function() {
+      this.initialize.apply(this, arguments);
+    }
+  }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+  for (var property in source) {
+    destination[property] = source[property];
+  }
+  return destination;
+}
+
+Object.extend(Object, {
+  inspect: function(object) {
+    try {
+      if (object === undefined) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : object.toString();
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({}, object);
+  }
+});
+
+Function.prototype.bind = function() {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function() {
+    return __method.apply(object, args.concat($A(arguments)));
+  }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+  var __method = this, args = $A(arguments), object = args.shift();
+  return function(event) {
+    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+  }
+}
+
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    var digits = this.toString(16);
+    if (this < 16) return '0' + digits;
+    return digits;
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  }
+});
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.callback(this);
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+}
+String.interpret = function(value){
+  return value == null ? '' : String(value);
+}
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = count === undefined ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return this;
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = truncation === undefined ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : this;
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  stripTags: function() {
+    return this.replace(/<\/?[^>]+>/gi, '');
+  },
+
+  stripScripts: function() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  },
+
+  extractScripts: function() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
+
+  evalScripts: function() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var div = document.createElement('div');
+    var text = document.createTextNode(this);
+    div.appendChild(text);
+    return div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = document.createElement('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return {};
+
+    return match[1].split(separator || '&').inject({}, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var name = decodeURIComponent(pair[0]);
+        var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+        if (hash[name] !== undefined) {
+          if (hash[name].constructor != Array)
+            hash[name] = [hash[name]];
+          if (value) hash[name].push(value);
+        }
+        else hash[name] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function(){
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.replace(/\\/g, '\\\\');
+    if (useDoubleQuotes)
+      return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    else
+      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (typeof replacement == 'function') return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern  = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    return this.template.gsub(this.pattern, function(match) {
+      var before = match[1];
+      if (before == '\\') return match[2];
+      return before + String.interpret(object[match[3]]);
+    });
+  }
+}
+
+var $break    = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+  each: function(iterator) {
+    var index = 0;
+    try {
+      this._each(function(value) {
+        try {
+          iterator(value, index++);
+        } catch (e) {
+          if (e != $continue) throw e;
+        }
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator) {
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.map(iterator);
+  },
+
+  all: function(iterator) {
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!(iterator || Prototype.K)(value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
+
+  any: function(iterator) {
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!(iterator || Prototype.K)(value, index))
+        throw $break;
+    });
+    return result;
+  },
+
+  collect: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push((iterator || Prototype.K)(value, index));
+    });
+    return results;
+  },
+
+  detect: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      if (iterator(value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
+
+  findAll: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  grep: function(pattern, iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      var stringValue = value.toString();
+      if (stringValue.match(pattern))
+        results.push((iterator || Prototype.K)(value, index));
+    })
+    return results;
+  },
+
+  include: function(object) {
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = fillWith === undefined ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  inject: function(memo, iterator) {
+    this.each(function(value, index) {
+      memo = iterator(memo, value, index);
+    });
+    return memo;
+  },
+
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
+
+  max: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator) {
+    var result;
+    this.each(function(value, index) {
+      value = (iterator || Prototype.K)(value, index);
+      if (result == undefined || value < result)
+        result = value;
+    });
+    return result;
+  },
+
+  partition: function(iterator) {
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      ((iterator || Prototype.K)(value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
+
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value, index) {
+      results.push(value[property]);
+    });
+    return results;
+  },
+
+  reject: function(iterator) {
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  sortBy: function(iterator) {
+    return this.map(function(value, index) {
+      return {value: value, criteria: iterator(value, index)};
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.map();
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (typeof args.last() == 'function')
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+}
+
+Object.extend(Enumerable, {
+  map:     Enumerable.collect,
+  find:    Enumerable.detect,
+  select:  Enumerable.findAll,
+  member:  Enumerable.include,
+  entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) {
+    return iterable.toArray();
+  } else {
+    var results = [];
+    for (var i = 0, length = iterable.length; i < length; i++)
+      results.push(iterable[i]);
+    return results;
+  }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+  Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < length; i++)
+      iterator(this[i]);
+  },
+
+  clear: function() {
+    this.length = 0;
+    return this;
+  },
+
+  first: function() {
+    return this[0];
+  },
+
+  last: function() {
+    return this[this.length - 1];
+  },
+
+  compact: function() {
+    return this.select(function(value) {
+      return value != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(value && value.constructor == Array ?
+        value.flatten() : [value]);
+    });
+  },
+
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
+
+  indexOf: function(object) {
+    for (var i = 0, length = this.length; i < length; i++)
+      if (this[i] == object) return i;
+    return -1;
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function() {
+    return this.inject([], function(array, value) {
+      return array.include(value) ? array : array.concat([value]);
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string){
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if(window.opera){
+  Array.prototype.concat = function(){
+    var array = [];
+    for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      if(arguments[i].constructor == Array) {
+        for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  }
+}
+var Hash = function(obj) {
+  Object.extend(this, obj || {});
+};
+
+Object.extend(Hash, {
+  toQueryString: function(obj) {
+    var parts = [];
+
+	  this.prototype._each.call(obj, function(pair) {
+      if (!pair.key) return;
+
+      if (pair.value && pair.value.constructor == Array) {
+        var values = pair.value.compact();
+        if (values.length < 2) pair.value = values.reduce();
+        else {
+        	key = encodeURIComponent(pair.key);
+          values.each(function(value) {
+            value = value != undefined ? encodeURIComponent(value) : '';
+            parts.push(key + '=' + encodeURIComponent(value));
+          });
+          return;
+        }
+      }
+      if (pair.value == undefined) pair[1] = '';
+      parts.push(pair.map(encodeURIComponent).join('='));
+	  });
+
+    return parts.join('&');
+  }
+});
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+  _each: function(iterator) {
+    for (var key in this) {
+      var value = this[key];
+      if (value && value == Hash.prototype[key]) continue;
+
+      var pair = [key, value];
+      pair.key = key;
+      pair.value = value;
+      iterator(pair);
+    }
+  },
+
+  keys: function() {
+    return this.pluck('key');
+  },
+
+  values: function() {
+    return this.pluck('value');
+  },
+
+  merge: function(hash) {
+    return $H(hash).inject(this, function(mergedHash, pair) {
+      mergedHash[pair.key] = pair.value;
+      return mergedHash;
+    });
+  },
+
+  remove: function() {
+    var result;
+    for(var i = 0, length = arguments.length; i < length; i++) {
+      var value = this[arguments[i]];
+      if (value !== undefined){
+        if (result === undefined) result = value;
+        else {
+          if (result.constructor != Array) result = [result];
+          result.push(value)
+        }
+      }
+      delete this[arguments[i]];
+    }
+    return result;
+  },
+
+  toQueryString: function() {
+    return Hash.toQueryString(this);
+  },
+
+  inspect: function() {
+    return '#<Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}>';
+  }
+});
+
+function $H(object) {
+  if (object && object.constructor == Hash) return object;
+  return new Hash(object);
+};
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+  initialize: function(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
+
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+}
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (typeof responder[callback] == 'function') {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) {}
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate: function() {
+    Ajax.activeRequestCount++;
+  },
+  onComplete: function() {
+    Ajax.activeRequestCount--;
+  }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+  setOptions: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   ''
+    }
+    Object.extend(this.options, options || {});
+
+    this.options.method = this.options.method.toLowerCase();
+    if (typeof this.options.parameters == 'string')
+      this.options.parameters = this.options.parameters.toQueryParams();
+  }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+  _complete: false,
+
+  initialize: function(url, options) {
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = this.options.parameters;
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    params = Hash.toQueryString(params);
+    if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
+
+    // when GET, append parameters to URL
+    if (this.method == 'get' && params)
+      this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
+
+    try {
+      Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous)
+        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      var body = this.method == 'post' ? (this.options.postBody || params) : null;
+
+      this.transport.send(body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (typeof extras.push == 'function')
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    return !this.transport.status
+        || (this.transport.status >= 200 && this.transport.status < 300);
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState];
+    var transport = this.transport, json = this.evalJSON();
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + this.transport.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(transport, json);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      if ((this.getHeader('Content-type') || 'text/javascript').strip().
+        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+          this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+      Ajax.Responders.dispatch('on' + state, this, transport, json);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) { return null }
+  },
+
+  evalJSON: function() {
+    try {
+      var json = this.getHeader('X-JSON');
+      return json ? eval('(' + json + ')') : null;
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval(this.transport.responseText);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+  initialize: function(container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    }
+
+    this.transport = Ajax.getTransport();
+    this.setOptions(options);
+
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;
+    this.options.onComplete = (function(transport, param) {
+      this.updateContent();
+      onComplete(transport, param);
+    }).bind(this);
+
+    this.request(url);
+  },
+
+  updateContent: function() {
+    var receiver = this.container[this.success() ? 'success' : 'failure'];
+    var response = this.transport.responseText;
+
+    if (!this.options.evalScripts) response = response.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (this.options.insertion)
+        new this.options.insertion(receiver, response);
+      else
+        receiver.update(response);
+    }
+
+    if (this.success()) {
+      if (this.onComplete)
+        setTimeout(this.onComplete.bind(this), 10);
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+  initialize: function(container, url, options) {
+    this.setOptions(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = {};
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(request) {
+    if (this.options.decay) {
+      this.decay = (request.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = request.responseText;
+    }
+    this.timer = setTimeout(this.onTimerEvent.bind(this),
+      this.decay * this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (typeof element == 'string')
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(query.snapshotItem(i));
+    return results;
+  };
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+  if (Prototype.BrowserFeatures.XPath) {
+    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+    return document._getElementsByXPath(q, parentElement);
+  } else {
+    var children = ($(parentElement) || document.body).getElementsByTagName('*');
+    var elements = [], child;
+    for (var i = 0, length = children.length; i < length; i++) {
+      child = children[i];
+      if (Element.hasClassName(child, className))
+        elements.push(Element.extend(child));
+    }
+    return elements;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+  var Element = new Object();
+
+Element.extend = function(element) {
+  if (!element || _nativeExtensions || element.nodeType == 3) return element;
+
+  if (!element._extended && element.tagName && element != window) {
+    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+    if (element.tagName == 'FORM')
+      Object.extend(methods, Form.Methods);
+    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
+      Object.extend(methods, Form.Element.Methods);
+
+    Object.extend(methods, Element.Methods.Simulated);
+
+    for (var property in methods) {
+      var value = methods[property];
+      if (typeof value == 'function' && !(property in element))
+        element[property] = cache.findOrStore(value);
+    }
+  }
+
+  element._extended = true;
+  return element;
+};
+
+Element.extend.cache = {
+  findOrStore: function(value) {
+    return this[value] = this[value] || function() {
+      return value.apply(null, [this].concat($A(arguments)));
+    }
+  }
+};
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, html) {
+    html = typeof html == 'undefined' ? '' : html.toString();
+    $(element).innerHTML = html.stripScripts();
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  replace: function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    if (element.outerHTML) {
+      element.outerHTML = html.stripScripts();
+    } else {
+      var range = element.ownerDocument.createRange();
+      range.selectNodeContents(element);
+      element.parentNode.replaceChild(
+        range.createContextualFragment(html.stripScripts()), element);
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $A($(element).getElementsByTagName('*'));
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (typeof selector == 'string')
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    return Selector.findElement($(element).ancestors(), expression, index);
+  },
+
+  down: function(element, expression, index) {
+    return Selector.findElement($(element).descendants(), expression, index);
+  },
+
+  previous: function(element, expression, index) {
+    return Selector.findElement($(element).previousSiblings(), expression, index);
+  },
+
+  next: function(element, expression, index) {
+    return Selector.findElement($(element).nextSiblings(), expression, index);
+  },
+
+  getElementsBySelector: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  getElementsByClassName: function(element, className) {
+    return document.getElementsByClassName(className, element);
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (document.all && !window.opera) {
+      var t = Element._attributeTranslations;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name])  name = t.names[name];
+      var attribute = element.attributes[name];
+      if(attribute) return attribute.nodeValue;
+    }
+    return element.getAttribute(name);
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    if (elementClassName.length == 0) return false;
+    if (elementClassName == className ||
+        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+      return true;
+    return false;
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).add(className);
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element).remove(className);
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+    return element;
+  },
+
+  observe: function() {
+    Event.observe.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  stopObserving: function() {
+    Event.stopObserving.apply(Event, arguments);
+    return $A(arguments).first();
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.match(/^\s*$/);
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = Position.cumulativeOffset(element);
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    if (['float','cssFloat'].include(style))
+      style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
+    style = style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        var css = document.defaultView.getComputedStyle(element, null);
+        value = css ? css[style] : null;
+      } else if (element.currentStyle) {
+        value = element.currentStyle[style];
+      }
+    }
+
+    if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
+      value = element['offset'+style.capitalize()] + 'px';
+
+    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+    if(style == 'opacity') {
+      if(value) return parseFloat(value);
+      if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if(value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+    return value == 'auto' ? null : value;
+  },
+
+  setStyle: function(element, style) {
+    element = $(element);
+    for (var name in style) {
+      var value = style[name];
+      if(name == 'opacity') {
+        if (value == 1) {
+          value = (/Gecko/.test(navigator.userAgent) &&
+            !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+        } else if(value === '') {
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+        } else {
+          if(value < 0.00001) value = 0;
+          if(/MSIE/.test(navigator.userAgent) && !window.opera)
+            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
+              'alpha(opacity='+value*100+')';
+        }
+      } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
+      element.style[name.camelize()] = value;
+    }
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      return {width: element.offsetWidth, height: element.offsetHeight};
+
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      element.style.position = 'relative';
+      // Opera returns the offset relative to the positioning context, when an
+      // element is position relative but top and left have not been defined
+      if (window.opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+    return element;
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = element.style.overflow || 'auto';
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  }
+};
+
+Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
+
+Element._attributeTranslations = {};
+
+Element._attributeTranslations.names = {
+  colspan:   "colSpan",
+  rowspan:   "rowSpan",
+  valign:    "vAlign",
+  datetime:  "dateTime",
+  accesskey: "accessKey",
+  tabindex:  "tabIndex",
+  enctype:   "encType",
+  maxlength: "maxLength",
+  readonly:  "readOnly",
+  longdesc:  "longDesc"
+};
+
+Element._attributeTranslations.values = {
+  _getAttr: function(element, attribute) {
+    return element.getAttribute(attribute, 2);
+  },
+
+  _flag: function(element, attribute) {
+    return $(element).hasAttribute(attribute) ? attribute : null;
+  },
+
+  style: function(element) {
+    return element.style.cssText.toLowerCase();
+  },
+
+  title: function(element) {
+    var node = element.getAttributeNode('title');
+    return node.specified ? node.nodeValue : null;
+  }
+};
+
+Object.extend(Element._attributeTranslations.values, {
+  href: Element._attributeTranslations.values._getAttr,
+  src:  Element._attributeTranslations.values._getAttr,
+  disabled: Element._attributeTranslations.values._flag,
+  checked:  Element._attributeTranslations.values._flag,
+  readonly: Element._attributeTranslations.values._flag,
+  multiple: Element._attributeTranslations.values._flag
+});
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    var t = Element._attributeTranslations;
+    attribute = t.names[attribute] || attribute;
+    return $(element).getAttributeNode(attribute).specified;
+  }
+};
+
+// IE is missing .innerHTML support for TABLE-related elements
+if (document.all && !window.opera){
+  Element.Methods.update = function(element, html) {
+    element = $(element);
+    html = typeof html == 'undefined' ? '' : html.toString();
+    var tagName = element.tagName.toUpperCase();
+    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+      var div = document.createElement('div');
+      switch (tagName) {
+        case 'THEAD':
+        case 'TBODY':
+          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
+          depth = 2;
+          break;
+        case 'TR':
+          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
+          depth = 3;
+          break;
+        case 'TD':
+          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
+          depth = 4;
+      }
+      $A(element.childNodes).each(function(node){
+        element.removeChild(node)
+      });
+      depth.times(function(){ div = div.firstChild });
+
+      $A(div.childNodes).each(
+        function(node){ element.appendChild(node) });
+    } else {
+      element.innerHTML = html.stripScripts();
+    }
+    setTimeout(function() {html.evalScripts()}, 10);
+    return element;
+  }
+};
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
+    var className = 'HTML' + tag + 'Element';
+    if(window[className]) return;
+    var klass = window[className] = {};
+    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+  });
+
+Element.addMethods = function(methods) {
+  Object.extend(Element.Methods, methods || {});
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    var cache = Element.extend.cache;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = cache.findOrStore(value);
+    }
+  }
+
+  if (typeof HTMLElement != 'undefined') {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+    copy(Form.Methods, HTMLFormElement.prototype);
+    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
+      copy(Form.Element.Methods, klass.prototype);
+    });
+    _nativeExtensions = true;
+  }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+  this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+  initialize: function(element, content) {
+    this.element = $(element);
+    this.content = content.stripScripts();
+
+    if (this.adjacency && this.element.insertAdjacentHTML) {
+      try {
+        this.element.insertAdjacentHTML(this.adjacency, this.content);
+      } catch (e) {
+        var tagName = this.element.tagName.toUpperCase();
+        if (['TBODY', 'TR'].include(tagName)) {
+          this.insertContent(this.contentFromAnonymousTable());
+        } else {
+          throw e;
+        }
+      }
+    } else {
+      this.range = this.element.ownerDocument.createRange();
+      if (this.initializeRange) this.initializeRange();
+      this.insertContent([this.range.createContextualFragment(this.content)]);
+    }
+
+    setTimeout(function() {content.evalScripts()}, 10);
+  },
+
+  contentFromAnonymousTable: function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+    return $A(div.childNodes[0].childNodes[0].childNodes);
+  }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+  initializeRange: function() {
+    this.range.setStartBefore(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment, this.element);
+    }).bind(this));
+  }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(true);
+  },
+
+  insertContent: function(fragments) {
+    fragments.reverse(false).each((function(fragment) {
+      this.element.insertBefore(fragment, this.element.firstChild);
+    }).bind(this));
+  }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+  initializeRange: function() {
+    this.range.selectNodeContents(this.element);
+    this.range.collapse(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.appendChild(fragment);
+    }).bind(this));
+  }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+  initializeRange: function() {
+    this.range.setStartAfter(this.element);
+  },
+
+  insertContent: function(fragments) {
+    fragments.each((function(fragment) {
+      this.element.parentNode.insertBefore(fragment,
+        this.element.nextSibling);
+    }).bind(this));
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+  initialize: function(expression) {
+    this.params = {classNames: []};
+    this.expression = expression.toString().strip();
+    this.parseExpression();
+    this.compileMatcher();
+  },
+
+  parseExpression: function() {
+    function abort(message) { throw 'Parse error in selector: ' + message; }
+
+    if (this.expression == '')  abort('empty expression');
+
+    var params = this.params, expr = this.expression, match, modifier, clause, rest;
+    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+      params.attributes = params.attributes || [];
+      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+      expr = match[1];
+    }
+
+    if (expr == '*') return this.params.wildcard = true;
+
+    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+      modifier = match[1], clause = match[2], rest = match[3];
+      switch (modifier) {
+        case '#':       params.id = clause; break;
+        case '.':       params.classNames.push(clause); break;
+        case '':
+        case undefined: params.tagName = clause.toUpperCase(); break;
+        default:        abort(expr.inspect());
+      }
+      expr = rest;
+    }
+
+    if (expr.length > 0) abort(expr.inspect());
+  },
+
+  buildMatchExpression: function() {
+    var params = this.params, conditions = [], clause;
+
+    if (params.wildcard)
+      conditions.push('true');
+    if (clause = params.id)
+      conditions.push('element.readAttribute("id") == ' + clause.inspect());
+    if (clause = params.tagName)
+      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+    if ((clause = params.classNames).length > 0)
+      for (var i = 0, length = clause.length; i < length; i++)
+        conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
+    if (clause = params.attributes) {
+      clause.each(function(attribute) {
+        var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
+        var splitValueBy = function(delimiter) {
+          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+        }
+
+        switch (attribute.operator) {
+          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
+          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+          case '|=':      conditions.push(
+                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+                          ); break;
+          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
+          case '':
+          case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
+          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
+        }
+      });
+    }
+
+    return conditions.join(' && ');
+  },
+
+  compileMatcher: function() {
+    this.match = new Function('element', 'if (!element.tagName) return false; element = $(element); return ' + this.buildMatchExpression());
+  },
+
+  findElements: function(scope) {
+    var element;
+
+    if (element = $(this.params.id))
+      if (this.match(element))
+        if (!scope || Element.childOf(element, scope))
+          return [element];
+
+    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+    var results = [];
+    for (var i = 0, length = scope.length; i < length; i++)
+      if (this.match(element = scope[i]))
+        results.push(Element.extend(element));
+
+    return results;
+  },
+
+  toString: function() {
+    return this.expression;
+  }
+}
+
+Object.extend(Selector, {
+  matchElements: function(elements, expression) {
+    var selector = new Selector(expression);
+    return elements.select(selector.match.bind(selector)).map(Element.extend);
+  },
+
+  findElement: function(elements, expression, index) {
+    if (typeof expression == 'number') index = expression, expression = false;
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    return expressions.map(function(expression) {
+      return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
+        var selector = new Selector(expr);
+        return results.inject([], function(elements, result) {
+          return elements.concat(selector.findElements(result || element));
+        });
+      });
+    }).flatten();
+  }
+});
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, getHash) {
+    var data = elements.inject({}, function(result, element) {
+      if (!element.disabled && element.name) {
+        var key = element.name, value = $(element).getValue();
+        if (value != undefined) {
+          if (result[key]) {
+            if (result[key].constructor != Array) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return getHash ? data : Hash.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, getHash) {
+    return Form.serializeElements(Form.getElements(form), getHash);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    form.getElements().each(function(element) {
+      element.blur();
+      element.disabled = 'true';
+    });
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    form.getElements().each(function(element) {
+      element.disabled = '';
+    });
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    return $(form).getElements().find(function(element) {
+      return element.type != 'hidden' && !element.disabled &&
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+}
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = {};
+        pair[element.name] = value;
+        return Hash.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    element.focus();
+    if (element.select && ( element.tagName.toLowerCase() != 'input' ||
+      !['button', 'reset', 'submit'].include(element.type) ) )
+      element.select();
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.blur();
+    element.disabled = false;
+    return element;
+  }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element);
+      default:
+        return Form.Element.Serializers.textarea(element);
+    }
+  },
+
+  inputSelector: function(element) {
+    return element.checked ? element.value : null;
+  },
+
+  textarea: function(element) {
+    return element.value;
+  },
+
+  select: function(element) {
+    return this[element.type == 'select-one' ?
+      'selectOne' : 'selectMany'](element);
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+  initialize: function(element, frequency, callback) {
+    this.frequency = frequency;
+    this.element   = $(element);
+    this.callback  = callback;
+
+    this.lastValue = this.getValue();
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  onTimerEvent: function() {
+    var value = this.getValue();
+    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+      ? this.lastValue != value : String(this.lastValue) != String(value));
+    if (changed) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+  initialize: function(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback.bind(this));
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) {
+  var Event = new Object();
+}
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+  KEY_HOME:     36,
+  KEY_END:      35,
+  KEY_PAGEUP:   33,
+  KEY_PAGEDOWN: 34,
+
+  element: function(event) {
+    return event.target || event.srcElement;
+  },
+
+  isLeftClick: function(event) {
+    return (((event.which) && (event.which == 1)) ||
+            ((event.button) && (event.button == 1)));
+  },
+
+  pointerX: function(event) {
+    return event.pageX || (event.clientX +
+      (document.documentElement.scrollLeft || document.body.scrollLeft));
+  },
+
+  pointerY: function(event) {
+    return event.pageY || (event.clientY +
+      (document.documentElement.scrollTop || document.body.scrollTop));
+  },
+
+  stop: function(event) {
+    if (event.preventDefault) {
+      event.preventDefault();
+      event.stopPropagation();
+    } else {
+      event.returnValue = false;
+      event.cancelBubble = true;
+    }
+  },
+
+  // find the first node with the given tagName, starting from the
+  // node the event was triggered on; traverses the DOM upwards
+  findElement: function(event, tagName) {
+    var element = Event.element(event);
+    while (element.parentNode && (!element.tagName ||
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))
+      element = element.parentNode;
+    return element;
+  },
+
+  observers: false,
+
+  _observeAndCache: function(element, name, observer, useCapture) {
+    if (!this.observers) this.observers = [];
+    if (element.addEventListener) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.addEventListener(name, observer, useCapture);
+    } else if (element.attachEvent) {
+      this.observers.push([element, name, observer, useCapture]);
+      element.attachEvent('on' + name, observer);
+    }
+  },
+
+  unloadCache: function() {
+    if (!Event.observers) return;
+    for (var i = 0, length = Event.observers.length; i < length; i++) {
+      Event.stopObserving.apply(this, Event.observers[i]);
+      Event.observers[i][0] = null;
+    }
+    Event.observers = false;
+  },
+
+  observe: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.attachEvent))
+      name = 'keydown';
+
+    Event._observeAndCache(element, name, observer, useCapture);
+  },
+
+  stopObserving: function(element, name, observer, useCapture) {
+    element = $(element);
+    useCapture = useCapture || false;
+
+    if (name == 'keypress' &&
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+        || element.detachEvent))
+      name = 'keydown';
+
+    if (element.removeEventListener) {
+      element.removeEventListener(name, observer, useCapture);
+    } else if (element.detachEvent) {
+      try {
+        element.detachEvent('on' + name, observer);
+      } catch (e) {}
+    }
+  }
+});
+
+/* prevent memory leaks in IE */
+if (navigator.appVersion.match(/\bMSIE\b/))
+  Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+  // set to true if needed, warning: firefox performance problems
+  // NOT neeeded for page scrolling, only if draggable contained in
+  // scrollable elements
+  includeScrollOffsets: false,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  realOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  positionedOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        if(element.tagName=='BODY') break;
+        var p = Element.getStyle(element, 'position');
+        if (p == 'relative' || p == 'absolute') break;
+      }
+    } while (element);
+    return [valueL, valueT];
+  },
+
+  offsetParent: function(element) {
+    if (element.offsetParent) return element.offsetParent;
+    if (element == document.body) return element;
+
+    while ((element = element.parentNode) && element != document.body)
+      if (Element.getStyle(element, 'position') != 'static')
+        return element;
+
+    return document.body;
+  },
+
+  // caches x/y coordinate pair to use with overlap
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = this.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = this.realOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = this.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  // within must be called directly before
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  page: function(forElement) {
+    var valueT = 0, valueL = 0;
+
+    var element = forElement;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+
+      // Safari fix
+      if (element.offsetParent==document.body)
+        if (Element.getStyle(element,'position')=='absolute') break;
+
+    } while (element = element.offsetParent);
+
+    element = forElement;
+    do {
+      if (!window.opera || element.tagName=='BODY') {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+      }
+    } while (element = element.parentNode);
+
+    return [valueL, valueT];
+  },
+
+  clone: function(source, target) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || {})
+
+    // find page position of source
+    source = $(source);
+    var p = Position.page(source);
+
+    // find coordinate system to use
+    target = $(target);
+    var delta = [0, 0];
+    var parent = null;
+    // delta [0,0] will do fine with position: fixed elements,
+    // position:absolute needs offsetParent deltas
+    if (Element.getStyle(target,'position') == 'absolute') {
+      parent = Position.offsetParent(target);
+      delta = Position.page(parent);
+    }
+
+    // correct by body offsets (fixes Safari)
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    // set position
+    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
+    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+  },
+
+  absolutize: function(element) {
+    element = $(element);
+    if (element.style.position == 'absolute') return;
+    Position.prepare();
+
+    var offsets = Position.positionedOffset(element);
+    var top     = offsets[1];
+    var left    = offsets[0];
+    var width   = element.clientWidth;
+    var height  = element.clientHeight;
+
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);
+    element._originalTop    = top  - parseFloat(element.style.top || 0);
+    element._originalWidth  = element.style.width;
+    element._originalHeight = element.style.height;
+
+    element.style.position = 'absolute';
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.width  = width + 'px';
+    element.style.height = height + 'px';
+  },
+
+  relativize: function(element) {
+    element = $(element);
+    if (element.style.position == 'relative') return;
+    Position.prepare();
+
+    element.style.position = 'relative';
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.height = element._originalHeight;
+    element.style.width  = element._originalWidth;
+  }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned.  For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+  Position.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == document.body)
+        if (Element.getStyle(element, 'position') == 'absolute') break;
+
+      element = element.offsetParent;
+    } while (element);
+
+    return [valueL, valueT];
+  }
+}
+
+Element.addMethods();// script.aculo.us builder.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+  NODEMAP: {
+    AREA: 'map',
+    CAPTION: 'table',
+    COL: 'table',
+    COLGROUP: 'table',
+    LEGEND: 'fieldset',
+    OPTGROUP: 'select',
+    OPTION: 'select',
+    PARAM: 'object',
+    TBODY: 'table',
+    TD: 'table',
+    TFOOT: 'table',
+    TH: 'table',
+    THEAD: 'table',
+    TR: 'table'
+  },
+  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+  //       due to a Firefox bug
+  node: function(elementName) {
+    elementName = elementName.toUpperCase();
+    
+    // try innerHTML approach
+    var parentTag = this.NODEMAP[elementName] || 'div';
+    var parentElement = document.createElement(parentTag);
+    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+    } catch(e) {}
+    var element = parentElement.firstChild || null;
+      
+    // see if browser added wrapping tags
+    if(element && (element.tagName.toUpperCase() != elementName))
+      element = element.getElementsByTagName(elementName)[0];
+    
+    // fallback to createElement approach
+    if(!element) element = document.createElement(elementName);
+    
+    // abort if nothing could be created
+    if(!element) return;
+
+    // attributes (or text)
+    if(arguments[1])
+      if(this._isStringOrNumber(arguments[1]) ||
+        (arguments[1] instanceof Array)) {
+          this._children(element, arguments[1]);
+        } else {
+          var attrs = this._attributes(arguments[1]);
+          if(attrs.length) {
+            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+              parentElement.innerHTML = "<" +elementName + " " +
+                attrs + "></" + elementName + ">";
+            } catch(e) {}
+            element = parentElement.firstChild || null;
+            // workaround firefox 1.0.X bug
+            if(!element) {
+              element = document.createElement(elementName);
+              for(attr in arguments[1]) 
+                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+            }
+            if(element.tagName.toUpperCase() != elementName)
+              element = parentElement.getElementsByTagName(elementName)[0];
+            }
+        } 
+
+    // text, or array of children
+    if(arguments[2])
+      this._children(element, arguments[2]);
+
+     return element;
+  },
+  _text: function(text) {
+     return document.createTextNode(text);
+  },
+
+  ATTR_MAP: {
+    'className': 'class',
+    'htmlFor': 'for'
+  },
+
+  _attributes: function(attributes) {
+    var attrs = [];
+    for(attribute in attributes)
+      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+          '="' + attributes[attribute].toString().escapeHTML() + '"');
+    return attrs.join(" ");
+  },
+  _children: function(element, children) {
+    if(typeof children=='object') { // array can hold nodes and text
+      children.flatten().each( function(e) {
+        if(typeof e=='object')
+          element.appendChild(e)
+        else
+          if(Builder._isStringOrNumber(e))
+            element.appendChild(Builder._text(e));
+      });
+    } else
+      if(Builder._isStringOrNumber(children)) 
+         element.appendChild(Builder._text(children));
+  },
+  _isStringOrNumber: function(param) {
+    return(typeof param=='string' || typeof param=='number');
+  },
+  build: function(html) {
+    var element = this.node('div');
+    $(element).update(html.strip());
+    return element.down();
+  },
+  dump: function(scope) { 
+    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
+  
+    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+  
+    tags.each( function(tag){ 
+      scope[tag] = function() { 
+        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
+      } 
+    });
+  }
+}
+// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+//  Justin Palmer (http://encytemedia.com/)
+//  Mark Pilgrim (http://diveintomark.org/)
+//  Martin Bialasinki
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/ 
+
+// converts rgb() and #xxx to #xxxxxx format,  
+// returns self (or first argument) if not convertable  
+String.prototype.parseColor = function() {  
+  var color = '#';
+  if(this.slice(0,4) == 'rgb(') {  
+    var cols = this.slice(4,this.length-1).split(',');  
+    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
+  } else {  
+    if(this.slice(0,1) == '#') {  
+      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
+      if(this.length==7) color = this.toLowerCase();  
+    }  
+  }  
+  return(color.length==7 ? color : (arguments[0] || this));  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {  
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue : 
+      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+  }).flatten().join('');
+}
+
+Element.collectTextNodesIgnoreClass = function(element, className) {  
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue : 
+      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
+        Element.collectTextNodesIgnoreClass(node, className) : ''));
+  }).flatten().join('');
+}
+
+Element.setContentZoom = function(element, percent) {
+  element = $(element);  
+  element.setStyle({fontSize: (percent/100) + 'em'});   
+  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+  return element;
+}
+
+Element.getOpacity = function(element){
+  return $(element).getStyle('opacity');
+}
+
+Element.setOpacity = function(element, value){
+  return $(element).setStyle({opacity:value});
+}
+
+Element.getInlineOpacity = function(element){
+  return $(element).style.opacity || '';
+}
+
+Element.forceRerendering = function(element) {
+  try {
+    element = $(element);
+    var n = document.createTextNode(' ');
+    element.appendChild(n);
+    element.removeChild(n);
+  } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Array.prototype.call = function() {
+  var args = arguments;
+  this.each(function(f){ f.apply(this, args) });
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+  _elementDoesNotExistError: {
+    name: 'ElementDoesNotExistError',
+    message: 'The specified DOM element does not exist, but is required for this effect to operate'
+  },
+  tagifyText: function(element) {
+    if(typeof Builder == 'undefined')
+      throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
+      
+    var tagifyStyle = 'position:relative';
+    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
+    
+    element = $(element);
+    $A(element.childNodes).each( function(child) {
+      if(child.nodeType==3) {
+        child.nodeValue.toArray().each( function(character) {
+          element.insertBefore(
+            Builder.node('span',{style: tagifyStyle},
+              character == ' ' ? String.fromCharCode(160) : character), 
+              child);
+        });
+        Element.remove(child);
+      }
+    });
+  },
+  multiple: function(element, effect) {
+    var elements;
+    if(((typeof element == 'object') || 
+        (typeof element == 'function')) && 
+       (element.length))
+      elements = element;
+    else
+      elements = $(element).childNodes;
+      
+    var options = Object.extend({
+      speed: 0.1,
+      delay: 0.0
+    }, arguments[2] || {});
+    var masterDelay = options.delay;
+
+    $A(elements).each( function(element, index) {
+      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+    });
+  },
+  PAIRS: {
+    'slide':  ['SlideDown','SlideUp'],
+    'blind':  ['BlindDown','BlindUp'],
+    'appear': ['Appear','Fade']
+  },
+  toggle: function(element, effect) {
+    element = $(element);
+    effect = (effect || 'appear').toLowerCase();
+    var options = Object.extend({
+      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+    }, arguments[2] || {});
+    Effect[element.visible() ? 
+      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+  }
+};
+
+var Effect2 = Effect; // deprecated
+
+/* ------------- transitions ------------- */
+
+Effect.Transitions = {
+  linear: Prototype.K,
+  sinoidal: function(pos) {
+    return (-Math.cos(pos*Math.PI)/2) + 0.5;
+  },
+  reverse: function(pos) {
+    return 1-pos;
+  },
+  flicker: function(pos) {
+    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+  },
+  wobble: function(pos) {
+    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+  },
+  pulse: function(pos, pulses) { 
+    pulses = pulses || 5; 
+    return (
+      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
+            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
+        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
+      );
+  },
+  none: function(pos) {
+    return 0;
+  },
+  full: function(pos) {
+    return 1;
+  }
+};
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create();
+Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
+  initialize: function() {
+    this.effects  = [];
+    this.interval = null;
+  },
+  _each: function(iterator) {
+    this.effects._each(iterator);
+  },
+  add: function(effect) {
+    var timestamp = new Date().getTime();
+    
+    var position = (typeof effect.options.queue == 'string') ? 
+      effect.options.queue : effect.options.queue.position;
+    
+    switch(position) {
+      case 'front':
+        // move unstarted effects after this effect  
+        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+            e.startOn  += effect.finishOn;
+            e.finishOn += effect.finishOn;
+          });
+        break;
+      case 'with-last':
+        timestamp = this.effects.pluck('startOn').max() || timestamp;
+        break;
+      case 'end':
+        // start effect after last queued effect has finished
+        timestamp = this.effects.pluck('finishOn').max() || timestamp;
+        break;
+    }
+    
+    effect.startOn  += timestamp;
+    effect.finishOn += timestamp;
+
+    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+      this.effects.push(effect);
+    
+    if(!this.interval) 
+      this.interval = setInterval(this.loop.bind(this), 15);
+  },
+  remove: function(effect) {
+    this.effects = this.effects.reject(function(e) { return e==effect });
+    if(this.effects.length == 0) {
+      clearInterval(this.interval);
+      this.interval = null;
+    }
+  },
+  loop: function() {
+    var timePos = new Date().getTime();
+    for(var i=0, len=this.effects.length;i<len;i++) 
+      if(this.effects[i]) this.effects[i].loop(timePos);
+  }
+});
+
+Effect.Queues = {
+  instances: $H(),
+  get: function(queueName) {
+    if(typeof queueName != 'string') return queueName;
+    
+    if(!this.instances[queueName])
+      this.instances[queueName] = new Effect.ScopedQueue();
+      
+    return this.instances[queueName];
+  }
+}
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.DefaultOptions = {
+  transition: Effect.Transitions.sinoidal,
+  duration:   1.0,   // seconds
+  fps:        60.0,  // max. 60fps due to Effect.Queue implementation
+  sync:       false, // true for combining
+  from:       0.0,
+  to:         1.0,
+  delay:      0.0,
+  queue:      'parallel'
+}
+
+Effect.Base = function() {};
+Effect.Base.prototype = {
+  position: null,
+  start: function(options) {
+    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
+    this.currentFrame = 0;
+    this.state        = 'idle';
+    this.startOn      = this.options.delay*1000;
+    this.finishOn     = this.startOn + (this.options.duration*1000);
+    this.event('beforeStart');
+    if(!this.options.sync)
+      Effect.Queues.get(typeof this.options.queue == 'string' ? 
+        'global' : this.options.queue.scope).add(this);
+  },
+  loop: function(timePos) {
+    if(timePos >= this.startOn) {
+      if(timePos >= this.finishOn) {
+        this.render(1.0);
+        this.cancel();
+        this.event('beforeFinish');
+        if(this.finish) this.finish(); 
+        this.event('afterFinish');
+        return;  
+      }
+      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
+      var frame = Math.round(pos * this.options.fps * this.options.duration);
+      if(frame > this.currentFrame) {
+        this.render(pos);
+        this.currentFrame = frame;
+      }
+    }
+  },
+  render: function(pos) {
+    if(this.state == 'idle') {
+      this.state = 'running';
+      this.event('beforeSetup');
+      if(this.setup) this.setup();
+      this.event('afterSetup');
+    }
+    if(this.state == 'running') {
+      if(this.options.transition) pos = this.options.transition(pos);
+      pos *= (this.options.to-this.options.from);
+      pos += this.options.from;
+      this.position = pos;
+      this.event('beforeUpdate');
+      if(this.update) this.update(pos);
+      this.event('afterUpdate');
+    }
+  },
+  cancel: function() {
+    if(!this.options.sync)
+      Effect.Queues.get(typeof this.options.queue == 'string' ? 
+        'global' : this.options.queue.scope).remove(this);
+    this.state = 'finished';
+  },
+  event: function(eventName) {
+    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+    if(this.options[eventName]) this.options[eventName](this);
+  },
+  inspect: function() {
+    var data = $H();
+    for(property in this)
+      if(typeof this[property] != 'function') data[property] = this[property];
+    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+  }
+}
+
+Effect.Parallel = Class.create();
+Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
+  initialize: function(effects) {
+    this.effects = effects || [];
+    this.start(arguments[1]);
+  },
+  update: function(position) {
+    this.effects.invoke('render', position);
+  },
+  finish: function(position) {
+    this.effects.each( function(effect) {
+      effect.render(1.0);
+      effect.cancel();
+      effect.event('beforeFinish');
+      if(effect.finish) effect.finish(position);
+      effect.event('afterFinish');
+    });
+  }
+});
+
+Effect.Event = Class.create();
+Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
+  initialize: function() {
+    var options = Object.extend({
+      duration: 0
+    }, arguments[0] || {});
+    this.start(options);
+  },
+  update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create();
+Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
+  initialize: function(element) {
+    this.element = $(element);
+    if(!this.element) throw(Effect._elementDoesNotExistError);
+    // make this work on IE on elements without 'layout'
+    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
+      this.element.setStyle({zoom: 1});
+    var options = Object.extend({
+      from: this.element.getOpacity() || 0.0,
+      to:   1.0
+    }, arguments[1] || {});
+    this.start(options);
+  },
+  update: function(position) {
+    this.element.setOpacity(position);
+  }
+});
+
+Effect.Move = Class.create();
+Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
+  initialize: function(element) {
+    this.element = $(element);
+    if(!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      x:    0,
+      y:    0,
+      mode: 'relative'
+    }, arguments[1] || {});
+    this.start(options);
+  },
+  setup: function() {
+    // Bug in Opera: Opera returns the "real" position of a static element or
+    // relative element that does not have top/left explicitly set.
+    // ==> Always set top and left for position relative elements in your stylesheets 
+    // (to 0 if you do not need them) 
+    this.element.makePositioned();
+    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
+    if(this.options.mode == 'absolute') {
+      // absolute movement, so we need to calc deltaX and deltaY
+      this.options.x = this.options.x - this.originalLeft;
+      this.options.y = this.options.y - this.originalTop;
+    }
+  },
+  update: function(position) {
+    this.element.setStyle({
+      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
+      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
+    });
+  }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+  return new Effect.Move(element, 
+    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
+};
+
+Effect.Scale = Class.create();
+Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
+  initialize: function(element, percent) {
+    this.element = $(element);
+    if(!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      scaleX: true,
+      scaleY: true,
+      scaleContent: true,
+      scaleFromCenter: false,
+      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
+      scaleFrom: 100.0,
+      scaleTo:   percent
+    }, arguments[2] || {});
+    this.start(options);
+  },
+  setup: function() {
+    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+    this.elementPositioning = this.element.getStyle('position');
+    
+    this.originalStyle = {};
+    ['top','left','width','height','fontSize'].each( function(k) {
+      this.originalStyle[k] = this.element.style[k];
+    }.bind(this));
+      
+    this.originalTop  = this.element.offsetTop;
+    this.originalLeft = this.element.offsetLeft;
+    
+    var fontSize = this.element.getStyle('font-size') || '100%';
+    ['em','px','%','pt'].each( function(fontSizeType) {
+      if(fontSize.indexOf(fontSizeType)>0) {
+        this.fontSize     = parseFloat(fontSize);
+        this.fontSizeType = fontSizeType;
+      }
+    }.bind(this));
+    
+    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+    
+    this.dims = null;
+    if(this.options.scaleMode=='box')
+      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+    if(/^content/.test(this.options.scaleMode))
+      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+    if(!this.dims)
+      this.dims = [this.options.scaleMode.originalHeight,
+                   this.options.scaleMode.originalWidth];
+  },
+  update: function(position) {
+    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+    if(this.options.scaleContent && this.fontSize)
+      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+  },
+  finish: function(position) {
+    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+  },
+  setDimensions: function(height, width) {
+    var d = {};
+    if(this.options.scaleX) d.width = Math.round(width) + 'px';
+    if(this.options.scaleY) d.height = Math.round(height) + 'px';
+    if(this.options.scaleFromCenter) {
+      var topd  = (height - this.dims[0])/2;
+      var leftd = (width  - this.dims[1])/2;
+      if(this.elementPositioning == 'absolute') {
+        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
+        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+      } else {
+        if(this.options.scaleY) d.top = -topd + 'px';
+        if(this.options.scaleX) d.left = -leftd + 'px';
+      }
+    }
+    this.element.setStyle(d);
+  }
+});
+
+Effect.Highlight = Class.create();
+Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
+  initialize: function(element) {
+    this.element = $(element);
+    if(!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
+    this.start(options);
+  },
+  setup: function() {
+    // Prevent executing on elements not in the layout flow
+    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
+    // Disable background image during the effect
+    this.oldStyle = {};
+    if (!this.options.keepBackgroundImage) {
+      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+      this.element.setStyle({backgroundImage: 'none'});
+    }
+    if(!this.options.endcolor)
+      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+    if(!this.options.restorecolor)
+      this.options.restorecolor = this.element.getStyle('background-color');
+    // init color calculations
+    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+  },
+  update: function(position) {
+    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
+  },
+  finish: function() {
+    this.element.setStyle(Object.extend(this.oldStyle, {
+      backgroundColor: this.options.restorecolor
+    }));
+  }
+});
+
+Effect.ScrollTo = Class.create();
+Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
+  initialize: function(element) {
+    this.element = $(element);
+    this.start(arguments[1] || {});
+  },
+  setup: function() {
+    Position.prepare();
+    var offsets = Position.cumulativeOffset(this.element);
+    if(this.options.offset) offsets[1] += this.options.offset;
+    var max = window.innerHeight ? 
+      window.height - window.innerHeight :
+      document.body.scrollHeight - 
+        (document.documentElement.clientHeight ? 
+          document.documentElement.clientHeight : document.body.clientHeight);
+    this.scrollStart = Position.deltaY;
+    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
+  },
+  update: function(position) {
+    Position.prepare();
+    window.scrollTo(Position.deltaX, 
+      this.scrollStart + (position*this.delta));
+  }
+});
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  var options = Object.extend({
+  from: element.getOpacity() || 1.0,
+  to:   0.0,
+  afterFinishInternal: function(effect) { 
+    if(effect.options.to!=0) return;
+    effect.element.hide().setStyle({opacity: oldOpacity}); 
+  }}, arguments[1] || {});
+  return new Effect.Opacity(element,options);
+}
+
+Effect.Appear = function(element) {
+  element = $(element);
+  var options = Object.extend({
+  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+  to:   1.0,
+  // force Safari to render floated elements properly
+  afterFinishInternal: function(effect) {
+    effect.element.forceRerendering();
+  },
+  beforeSetup: function(effect) {
+    effect.element.setOpacity(effect.options.from).show(); 
+  }}, arguments[1] || {});
+  return new Effect.Opacity(element,options);
+}
+
+Effect.Puff = function(element) {
+  element = $(element);
+  var oldStyle = { 
+    opacity: element.getInlineOpacity(), 
+    position: element.getStyle('position'),
+    top:  element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height
+  };
+  return new Effect.Parallel(
+   [ new Effect.Scale(element, 200, 
+      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
+     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
+     Object.extend({ duration: 1.0, 
+      beforeSetupInternal: function(effect) {
+        Position.absolutize(effect.effects[0].element)
+      },
+      afterFinishInternal: function(effect) {
+         effect.effects[0].element.hide().setStyle(oldStyle); }
+     }, arguments[1] || {})
+   );
+}
+
+Effect.BlindUp = function(element) {
+  element = $(element);
+  element.makeClipping();
+  return new Effect.Scale(element, 0,
+    Object.extend({ scaleContent: false, 
+      scaleX: false, 
+      restoreAfterFinish: true,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping();
+      } 
+    }, arguments[1] || {})
+  );
+}
+
+Effect.BlindDown = function(element) {
+  element = $(element);
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({ 
+    scaleContent: false, 
+    scaleX: false,
+    scaleFrom: 0,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
+    },  
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping();
+    }
+  }, arguments[1] || {}));
+}
+
+Effect.SwitchOff = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  return new Effect.Appear(element, Object.extend({
+    duration: 0.4,
+    from: 0,
+    transition: Effect.Transitions.flicker,
+    afterFinishInternal: function(effect) {
+      new Effect.Scale(effect.element, 1, { 
+        duration: 0.3, scaleFromCenter: true,
+        scaleX: false, scaleContent: false, restoreAfterFinish: true,
+        beforeSetup: function(effect) { 
+          effect.element.makePositioned().makeClipping();
+        },
+        afterFinishInternal: function(effect) {
+          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+        }
+      })
+    }
+  }, arguments[1] || {}));
+}
+
+Effect.DropOut = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left'),
+    opacity: element.getInlineOpacity() };
+  return new Effect.Parallel(
+    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
+      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+    Object.extend(
+      { duration: 0.5,
+        beforeSetup: function(effect) {
+          effect.effects[0].element.makePositioned(); 
+        },
+        afterFinishInternal: function(effect) {
+          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+        } 
+      }, arguments[1] || {}));
+}
+
+Effect.Shake = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left') };
+    return new Effect.Move(element, 
+      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
+        effect.element.undoPositioned().setStyle(oldStyle);
+  }}) }}) }}) }}) }}) }});
+}
+
+Effect.SlideDown = function(element) {
+  element = $(element).cleanWhitespace();
+  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+  var oldInnerBottom = element.down().getStyle('bottom');
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({ 
+    scaleContent: false, 
+    scaleX: false, 
+    scaleFrom: window.opera ? 0 : 1,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if(window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
+    },
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping().undoPositioned();
+      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+    }, arguments[1] || {})
+  );
+}
+
+Effect.SlideUp = function(element) {
+  element = $(element).cleanWhitespace();
+  var oldInnerBottom = element.down().getStyle('bottom');
+  return new Effect.Scale(element, window.opera ? 0 : 1,
+   Object.extend({ scaleContent: false, 
+    scaleX: false, 
+    scaleMode: 'box',
+    scaleFrom: 100,
+    restoreAfterFinish: true,
+    beforeStartInternal: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if(window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().show();
+    },  
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' });
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
+      effect.element.down().undoPositioned();
+    }
+   }, arguments[1] || {})
+  );
+}
+
+// Bug in opera makes the TD containing this element expand for a instance after finish 
+Effect.Squish = function(element) {
+  return new Effect.Scale(element, window.opera ? 1 : 0, { 
+    restoreAfterFinish: true,
+    beforeSetup: function(effect) {
+      effect.element.makeClipping(); 
+    },  
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping(); 
+    }
+  });
+}
+
+Effect.Grow = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.full
+  }, arguments[1] || {});
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();    
+  var initialMoveX, initialMoveY;
+  var moveX, moveY;
+  
+  switch (options.direction) {
+    case 'top-left':
+      initialMoveX = initialMoveY = moveX = moveY = 0; 
+      break;
+    case 'top-right':
+      initialMoveX = dims.width;
+      initialMoveY = moveY = 0;
+      moveX = -dims.width;
+      break;
+    case 'bottom-left':
+      initialMoveX = moveX = 0;
+      initialMoveY = dims.height;
+      moveY = -dims.height;
+      break;
+    case 'bottom-right':
+      initialMoveX = dims.width;
+      initialMoveY = dims.height;
+      moveX = -dims.width;
+      moveY = -dims.height;
+      break;
+    case 'center':
+      initialMoveX = dims.width / 2;
+      initialMoveY = dims.height / 2;
+      moveX = -dims.width / 2;
+      moveY = -dims.height / 2;
+      break;
+  }
+  
+  return new Effect.Move(element, {
+    x: initialMoveX,
+    y: initialMoveY,
+    duration: 0.01, 
+    beforeSetup: function(effect) {
+      effect.element.hide().makeClipping().makePositioned();
+    },
+    afterFinishInternal: function(effect) {
+      new Effect.Parallel(
+        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+          new Effect.Scale(effect.element, 100, {
+            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
+            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+        ], Object.extend({
+             beforeSetup: function(effect) {
+               effect.effects[0].element.setStyle({height: '0px'}).show(); 
+             },
+             afterFinishInternal: function(effect) {
+               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
+             }
+           }, options)
+      )
+    }
+  });
+}
+
+Effect.Shrink = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.none
+  }, arguments[1] || {});
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();
+  var moveX, moveY;
+  
+  switch (options.direction) {
+    case 'top-left':
+      moveX = moveY = 0;
+      break;
+    case 'top-right':
+      moveX = dims.width;
+      moveY = 0;
+      break;
+    case 'bottom-left':
+      moveX = 0;
+      moveY = dims.height;
+      break;
+    case 'bottom-right':
+      moveX = dims.width;
+      moveY = dims.height;
+      break;
+    case 'center':  
+      moveX = dims.width / 2;
+      moveY = dims.height / 2;
+      break;
+  }
+  
+  return new Effect.Parallel(
+    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+    ], Object.extend({            
+         beforeStartInternal: function(effect) {
+           effect.effects[0].element.makePositioned().makeClipping(); 
+         },
+         afterFinishInternal: function(effect) {
+           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+       }, options)
+  );
+}
+
+Effect.Pulsate = function(element) {
+  element = $(element);
+  var options    = arguments[1] || {};
+  var oldOpacity = element.getInlineOpacity();
+  var transition = options.transition || Effect.Transitions.sinoidal;
+  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
+  reverser.bind(transition);
+  return new Effect.Opacity(element, 
+    Object.extend(Object.extend({  duration: 2.0, from: 0,
+      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+    }, options), {transition: reverser}));
+}
+
+Effect.Fold = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height };
+  element.makeClipping();
+  return new Effect.Scale(element, 5, Object.extend({   
+    scaleContent: false,
+    scaleX: false,
+    afterFinishInternal: function(effect) {
+    new Effect.Scale(element, 1, { 
+      scaleContent: false, 
+      scaleY: false,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping().setStyle(oldStyle);
+      } });
+  }}, arguments[1] || {}));
+};
+
+Effect.Morph = Class.create();
+Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
+  initialize: function(element) {
+    this.element = $(element);
+    if(!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      style: {}
+    }, arguments[1] || {});
+    if (typeof options.style == 'string') {
+      if(options.style.indexOf(':') == -1) {
+        var cssText = '', selector = '.' + options.style;
+        $A(document.styleSheets).reverse().each(function(styleSheet) {
+          if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
+          else if (styleSheet.rules) cssRules = styleSheet.rules;
+          $A(cssRules).reverse().each(function(rule) {
+            if (selector == rule.selectorText) {
+              cssText = rule.style.cssText;
+              throw $break;
+            }
+          });
+          if (cssText) throw $break;
+        });
+        this.style = cssText.parseStyle();
+        options.afterFinishInternal = function(effect){
+          effect.element.addClassName(effect.options.style);
+          effect.transforms.each(function(transform) {
+            if(transform.style != 'opacity')
+              effect.element.style[transform.style.camelize()] = '';
+          });
+        }
+      } else this.style = options.style.parseStyle();
+    } else this.style = $H(options.style)
+    this.start(options);
+  },
+  setup: function(){
+    function parseColor(color){
+      if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+      color = color.parseColor();
+      return $R(0,2).map(function(i){
+        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
+      });
+    }
+    this.transforms = this.style.map(function(pair){
+      var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
+
+      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
+        value = value.parseColor();
+        unit  = 'color';
+      } else if(property == 'opacity') {
+        value = parseFloat(value);
+        if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
+          this.element.setStyle({zoom: 1});
+      } else if(Element.CSS_LENGTH.test(value)) 
+        var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
+          value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
+
+      var originalValue = this.element.getStyle(property);
+      return $H({ 
+        style: property, 
+        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
+        targetValue: unit=='color' ? parseColor(value) : value,
+        unit: unit
+      });
+    }.bind(this)).reject(function(transform){
+      return (
+        (transform.originalValue == transform.targetValue) ||
+        (
+          transform.unit != 'color' &&
+          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+        )
+      )
+    });
+  },
+  update: function(position) {
+    var style = $H(), value = null;
+    this.transforms.each(function(transform){
+      value = transform.unit=='color' ?
+        $R(0,2).inject('#',function(m,v,i){
+          return m+(Math.round(transform.originalValue[i]+
+            (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : 
+        transform.originalValue + Math.round(
+          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
+      style[transform.style] = value;
+    });
+    this.element.setStyle(style);
+  }
+});
+
+Effect.Transform = Class.create();
+Object.extend(Effect.Transform.prototype, {
+  initialize: function(tracks){
+    this.tracks  = [];
+    this.options = arguments[1] || {};
+    this.addTracks(tracks);
+  },
+  addTracks: function(tracks){
+    tracks.each(function(track){
+      var data = $H(track).values().first();
+      this.tracks.push($H({
+        ids:     $H(track).keys().first(),
+        effect:  Effect.Morph,
+        options: { style: data }
+      }));
+    }.bind(this));
+    return this;
+  },
+  play: function(){
+    return new Effect.Parallel(
+      this.tracks.map(function(track){
+        var elements = [$(track.ids) || $$(track.ids)].flatten();
+        return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
+      }).flatten(),
+      this.options
+    );
+  }
+});
+
+Element.CSS_PROPERTIES = $w(
+  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
+  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+  'fontSize fontWeight height left letterSpacing lineHeight ' +
+  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+  'right textIndent top width wordSpacing zIndex');
+  
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.prototype.parseStyle = function(){
+  var element = Element.extend(document.createElement('div'));
+  element.innerHTML = '<div style="' + this + '"></div>';
+  var style = element.down().style, styleRules = $H();
+  
+  Element.CSS_PROPERTIES.each(function(property){
+    if(style[property]) styleRules[property] = style[property]; 
+  });
+  if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
+    styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
+  }
+  return styleRules;
+};
+
+Element.morph = function(element, style) {
+  new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
+  return element;
+};
+
+['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
+ 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
+  function(f) { Element.Methods[f] = Element[f]; }
+);
+
+Element.Methods.visualEffect = function(element, effect, options) {
+  s = effect.gsub(/_/, '-').camelize();
+  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
+  new Effect[effect_class](element, options);
+  return $(element);
+};
+
+Element.addMethods();// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi at oriontransfer.co.nz)
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(typeof Effect == 'undefined')
+  throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+  drops: [],
+
+  remove: function(element) {
+    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+  },
+
+  add: function(element) {
+    element = $(element);
+    var options = Object.extend({
+      greedy:     true,
+      hoverclass: null,
+      tree:       false
+    }, arguments[1] || {});
+
+    // cache containers
+    if(options.containment) {
+      options._containers = [];
+      var containment = options.containment;
+      if((typeof containment == 'object') && 
+        (containment.constructor == Array)) {
+        containment.each( function(c) { options._containers.push($(c)) });
+      } else {
+        options._containers.push($(containment));
+      }
+    }
+    
+    if(options.accept) options.accept = [options.accept].flatten();
+
+    Element.makePositioned(element); // fix IE
+    options.element = element;
+
+    this.drops.push(options);
+  },
+  
+  findDeepestChild: function(drops) {
+    deepest = drops[0];
+      
+    for (i = 1; i < drops.length; ++i)
+      if (Element.isParent(drops[i].element, deepest.element))
+        deepest = drops[i];
+    
+    return deepest;
+  },
+
+  isContained: function(element, drop) {
+    var containmentNode;
+    if(drop.tree) {
+      containmentNode = element.treeNode; 
+    } else {
+      containmentNode = element.parentNode;
+    }
+    return drop._containers.detect(function(c) { return containmentNode == c });
+  },
+  
+  isAffected: function(point, element, drop) {
+    return (
+      (drop.element!=element) &&
+      ((!drop._containers) ||
+        this.isContained(element, drop)) &&
+      ((!drop.accept) ||
+        (Element.classNames(element).detect( 
+          function(v) { return drop.accept.include(v) } ) )) &&
+      Position.within(drop.element, point[0], point[1]) );
+  },
+
+  deactivate: function(drop) {
+    if(drop.hoverclass)
+      Element.removeClassName(drop.element, drop.hoverclass);
+    this.last_active = null;
+  },
+
+  activate: function(drop) {
+    if(drop.hoverclass)
+      Element.addClassName(drop.element, drop.hoverclass);
+    this.last_active = drop;
+  },
+
+  show: function(point, element) {
+    if(!this.drops.length) return;
+    var affected = [];
+    
+    if(this.last_active) this.deactivate(this.last_active);
+    this.drops.each( function(drop) {
+      if(Droppables.isAffected(point, element, drop))
+        affected.push(drop);
+    });
+        
+    if(affected.length>0) {
+      drop = Droppables.findDeepestChild(affected);
+      Position.within(drop.element, point[0], point[1]);
+      if(drop.onHover)
+        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+      
+      Droppables.activate(drop);
+    }
+  },
+
+  fire: function(event, element) {
+    if(!this.last_active) return;
+    Position.prepare();
+
+    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+      if (this.last_active.onDrop) 
+        this.last_active.onDrop(element, this.last_active.element, event);
+  },
+
+  reset: function() {
+    if(this.last_active)
+      this.deactivate(this.last_active);
+  }
+}
+
+var Draggables = {
+  drags: [],
+  observers: [],
+  
+  register: function(draggable) {
+    if(this.drags.length == 0) {
+      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
+      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
+      
+      Event.observe(document, "mouseup", this.eventMouseUp);
+      Event.observe(document, "mousemove", this.eventMouseMove);
+      Event.observe(document, "keypress", this.eventKeypress);
+    }
+    this.drags.push(draggable);
+  },
+  
+  unregister: function(draggable) {
+    this.drags = this.drags.reject(function(d) { return d==draggable });
+    if(this.drags.length == 0) {
+      Event.stopObserving(document, "mouseup", this.eventMouseUp);
+      Event.stopObserving(document, "mousemove", this.eventMouseMove);
+      Event.stopObserving(document, "keypress", this.eventKeypress);
+    }
+  },
+  
+  activate: function(draggable) {
+    if(draggable.options.delay) { 
+      this._timeout = setTimeout(function() { 
+        Draggables._timeout = null; 
+        window.focus(); 
+        Draggables.activeDraggable = draggable; 
+      }.bind(this), draggable.options.delay); 
+    } else {
+      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+      this.activeDraggable = draggable;
+    }
+  },
+  
+  deactivate: function() {
+    this.activeDraggable = null;
+  },
+  
+  updateDrag: function(event) {
+    if(!this.activeDraggable) return;
+    var pointer = [Event.pointerX(event), Event.pointerY(event)];
+    // Mozilla-based browsers fire successive mousemove events with
+    // the same coordinates, prevent needless redrawing (moz bug?)
+    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+    this._lastPointer = pointer;
+    
+    this.activeDraggable.updateDrag(event, pointer);
+  },
+  
+  endDrag: function(event) {
+    if(this._timeout) { 
+      clearTimeout(this._timeout); 
+      this._timeout = null; 
+    }
+    if(!this.activeDraggable) return;
+    this._lastPointer = null;
+    this.activeDraggable.endDrag(event);
+    this.activeDraggable = null;
+  },
+  
+  keyPress: function(event) {
+    if(this.activeDraggable)
+      this.activeDraggable.keyPress(event);
+  },
+  
+  addObserver: function(observer) {
+    this.observers.push(observer);
+    this._cacheObserverCallbacks();
+  },
+  
+  removeObserver: function(element) {  // element instead of observer fixes mem leaks
+    this.observers = this.observers.reject( function(o) { return o.element==element });
+    this._cacheObserverCallbacks();
+  },
+  
+  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
+    if(this[eventName+'Count'] > 0)
+      this.observers.each( function(o) {
+        if(o[eventName]) o[eventName](eventName, draggable, event);
+      });
+    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+  },
+  
+  _cacheObserverCallbacks: function() {
+    ['onStart','onEnd','onDrag'].each( function(eventName) {
+      Draggables[eventName+'Count'] = Draggables.observers.select(
+        function(o) { return o[eventName]; }
+      ).length;
+    });
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create();
+Draggable._dragging    = {};
+
+Draggable.prototype = {
+  initialize: function(element) {
+    var defaults = {
+      handle: false,
+      reverteffect: function(element, top_offset, left_offset) {
+        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+          queue: {scope:'_draggable', position:'end'}
+        });
+      },
+      endeffect: function(element) {
+        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
+        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
+          queue: {scope:'_draggable', position:'end'},
+          afterFinish: function(){ 
+            Draggable._dragging[element] = false 
+          }
+        }); 
+      },
+      zindex: 1000,
+      revert: false,
+      scroll: false,
+      scrollSensitivity: 20,
+      scrollSpeed: 15,
+      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
+      delay: 0
+    };
+    
+    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
+      Object.extend(defaults, {
+        starteffect: function(element) {
+          element._opacity = Element.getOpacity(element);
+          Draggable._dragging[element] = true;
+          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
+        }
+      });
+    
+    var options = Object.extend(defaults, arguments[1] || {});
+
+    this.element = $(element);
+    
+    if(options.handle && (typeof options.handle == 'string'))
+      this.handle = this.element.down('.'+options.handle, 0);
+    
+    if(!this.handle) this.handle = $(options.handle);
+    if(!this.handle) this.handle = this.element;
+    
+    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+      options.scroll = $(options.scroll);
+      this._isScrollChild = Element.childOf(this.element, options.scroll);
+    }
+
+    Element.makePositioned(this.element); // fix IE    
+
+    this.delta    = this.currentDelta();
+    this.options  = options;
+    this.dragging = false;   
+
+    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+    Event.observe(this.handle, "mousedown", this.eventMouseDown);
+    
+    Draggables.register(this);
+  },
+  
+  destroy: function() {
+    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+    Draggables.unregister(this);
+  },
+  
+  currentDelta: function() {
+    return([
+      parseInt(Element.getStyle(this.element,'left') || '0'),
+      parseInt(Element.getStyle(this.element,'top') || '0')]);
+  },
+  
+  initDrag: function(event) {
+    if(typeof Draggable._dragging[this.element] != 'undefined' &&
+      Draggable._dragging[this.element]) return;
+    if(Event.isLeftClick(event)) {    
+      // abort on form elements, fixes a Firefox issue
+      var src = Event.element(event);
+      if((tag_name = src.tagName.toUpperCase()) && (
+        tag_name=='INPUT' ||
+        tag_name=='SELECT' ||
+        tag_name=='OPTION' ||
+        tag_name=='BUTTON' ||
+        tag_name=='TEXTAREA')) return;
+        
+      var pointer = [Event.pointerX(event), Event.pointerY(event)];
+      var pos     = Position.cumulativeOffset(this.element);
+      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+      
+      Draggables.activate(this);
+      Event.stop(event);
+    }
+  },
+  
+  startDrag: function(event) {
+    this.dragging = true;
+    
+    if(this.options.zindex) {
+      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+      this.element.style.zIndex = this.options.zindex;
+    }
+    
+    if(this.options.ghosting) {
+      this._clone = this.element.cloneNode(true);
+      Position.absolutize(this.element);
+      this.element.parentNode.insertBefore(this._clone, this.element);
+    }
+    
+    if(this.options.scroll) {
+      if (this.options.scroll == window) {
+        var where = this._getWindowScroll(this.options.scroll);
+        this.originalScrollLeft = where.left;
+        this.originalScrollTop = where.top;
+      } else {
+        this.originalScrollLeft = this.options.scroll.scrollLeft;
+        this.originalScrollTop = this.options.scroll.scrollTop;
+      }
+    }
+    
+    Draggables.notify('onStart', this, event);
+        
+    if(this.options.starteffect) this.options.starteffect(this.element);
+  },
+  
+  updateDrag: function(event, pointer) {
+    if(!this.dragging) this.startDrag(event);
+    Position.prepare();
+    Droppables.show(pointer, this.element);
+    Draggables.notify('onDrag', this, event);
+    
+    this.draw(pointer);
+    if(this.options.change) this.options.change(this);
+    
+    if(this.options.scroll) {
+      this.stopScrolling();
+      
+      var p;
+      if (this.options.scroll == window) {
+        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+      } else {
+        p = Position.page(this.options.scroll);
+        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+        p[1] += this.options.scroll.scrollTop + Position.deltaY;
+        p.push(p[0]+this.options.scroll.offsetWidth);
+        p.push(p[1]+this.options.scroll.offsetHeight);
+      }
+      var speed = [0,0];
+      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+      this.startScrolling(speed);
+    }
+    
+    // fix AppleWebKit rendering
+    if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+    
+    Event.stop(event);
+  },
+  
+  finishDrag: function(event, success) {
+    this.dragging = false;
+
+    if(this.options.ghosting) {
+      Position.relativize(this.element);
+      Element.remove(this._clone);
+      this._clone = null;
+    }
+
+    if(success) Droppables.fire(event, this.element);
+    Draggables.notify('onEnd', this, event);
+
+    var revert = this.options.revert;
+    if(revert && typeof revert == 'function') revert = revert(this.element);
+    
+    var d = this.currentDelta();
+    if(revert && this.options.reverteffect) {
+      this.options.reverteffect(this.element, 
+        d[1]-this.delta[1], d[0]-this.delta[0]);
+    } else {
+      this.delta = d;
+    }
+
+    if(this.options.zindex)
+      this.element.style.zIndex = this.originalZ;
+
+    if(this.options.endeffect) 
+      this.options.endeffect(this.element);
+      
+    Draggables.deactivate(this);
+    Droppables.reset();
+  },
+  
+  keyPress: function(event) {
+    if(event.keyCode!=Event.KEY_ESC) return;
+    this.finishDrag(event, false);
+    Event.stop(event);
+  },
+  
+  endDrag: function(event) {
+    if(!this.dragging) return;
+    this.stopScrolling();
+    this.finishDrag(event, true);
+    Event.stop(event);
+  },
+  
+  draw: function(point) {
+    var pos = Position.cumulativeOffset(this.element);
+    if(this.options.ghosting) {
+      var r   = Position.realOffset(this.element);
+      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+    }
+    
+    var d = this.currentDelta();
+    pos[0] -= d[0]; pos[1] -= d[1];
+    
+    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+    }
+    
+    var p = [0,1].map(function(i){ 
+      return (point[i]-pos[i]-this.offset[i]) 
+    }.bind(this));
+    
+    if(this.options.snap) {
+      if(typeof this.options.snap == 'function') {
+        p = this.options.snap(p[0],p[1],this);
+      } else {
+      if(this.options.snap instanceof Array) {
+        p = p.map( function(v, i) {
+          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+      } else {
+        p = p.map( function(v) {
+          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+      }
+    }}
+    
+    var style = this.element.style;
+    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+      style.left = p[0] + "px";
+    if((!this.options.constraint) || (this.options.constraint=='vertical'))
+      style.top  = p[1] + "px";
+    
+    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+  },
+  
+  stopScrolling: function() {
+    if(this.scrollInterval) {
+      clearInterval(this.scrollInterval);
+      this.scrollInterval = null;
+      Draggables._lastScrollPointer = null;
+    }
+  },
+  
+  startScrolling: function(speed) {
+    if(!(speed[0] || speed[1])) return;
+    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+    this.lastScrolled = new Date();
+    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+  },
+  
+  scroll: function() {
+    var current = new Date();
+    var delta = current - this.lastScrolled;
+    this.lastScrolled = current;
+    if(this.options.scroll == window) {
+      with (this._getWindowScroll(this.options.scroll)) {
+        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+          var d = delta / 1000;
+          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+        }
+      }
+    } else {
+      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
+    }
+    
+    Position.prepare();
+    Droppables.show(Draggables._lastPointer, this.element);
+    Draggables.notify('onDrag', this);
+    if (this._isScrollChild) {
+      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+      if (Draggables._lastScrollPointer[0] < 0)
+        Draggables._lastScrollPointer[0] = 0;
+      if (Draggables._lastScrollPointer[1] < 0)
+        Draggables._lastScrollPointer[1] = 0;
+      this.draw(Draggables._lastScrollPointer);
+    }
+    
+    if(this.options.change) this.options.change(this);
+  },
+  
+  _getWindowScroll: function(w) {
+    var T, L, W, H;
+    with (w.document) {
+      if (w.document.documentElement && documentElement.scrollTop) {
+        T = documentElement.scrollTop;
+        L = documentElement.scrollLeft;
+      } else if (w.document.body) {
+        T = body.scrollTop;
+        L = body.scrollLeft;
+      }
+      if (w.innerWidth) {
+        W = w.innerWidth;
+        H = w.innerHeight;
+      } else if (w.document.documentElement && documentElement.clientWidth) {
+        W = documentElement.clientWidth;
+        H = documentElement.clientHeight;
+      } else {
+        W = body.offsetWidth;
+        H = body.offsetHeight
+      }
+    }
+    return { top: T, left: L, width: W, height: H };
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create();
+SortableObserver.prototype = {
+  initialize: function(element, observer) {
+    this.element   = $(element);
+    this.observer  = observer;
+    this.lastValue = Sortable.serialize(this.element);
+  },
+  
+  onStart: function() {
+    this.lastValue = Sortable.serialize(this.element);
+  },
+  
+  onEnd: function() {
+    Sortable.unmark();
+    if(this.lastValue != Sortable.serialize(this.element))
+      this.observer(this.element)
+  }
+}
+
+var Sortable = {
+  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+  
+  sortables: {},
+  
+  _findRootElement: function(element) {
+    while (element.tagName.toUpperCase() != "BODY") {  
+      if(element.id && Sortable.sortables[element.id]) return element;
+      element = element.parentNode;
+    }
+  },
+
+  options: function(element) {
+    element = Sortable._findRootElement($(element));
+    if(!element) return;
+    return Sortable.sortables[element.id];
+  },
+  
+  destroy: function(element){
+    var s = Sortable.options(element);
+    
+    if(s) {
+      Draggables.removeObserver(s.element);
+      s.droppables.each(function(d){ Droppables.remove(d) });
+      s.draggables.invoke('destroy');
+      
+      delete Sortable.sortables[s.element.id];
+    }
+  },
+
+  create: function(element) {
+    element = $(element);
+    var options = Object.extend({ 
+      element:     element,
+      tag:         'li',       // assumes li children, override with tag: 'tagname'
+      dropOnEmpty: false,
+      tree:        false,
+      treeTag:     'ul',
+      overlap:     'vertical', // one of 'vertical', 'horizontal'
+      constraint:  'vertical', // one of 'vertical', 'horizontal', false
+      containment: element,    // also takes array of elements (or id's); or false
+      handle:      false,      // or a CSS class
+      only:        false,
+      delay:       0,
+      hoverclass:  null,
+      ghosting:    false,
+      scroll:      false,
+      scrollSensitivity: 20,
+      scrollSpeed: 15,
+      format:      this.SERIALIZE_RULE,
+      onChange:    Prototype.emptyFunction,
+      onUpdate:    Prototype.emptyFunction
+    }, arguments[1] || {});
+
+    // clear any old sortable with same element
+    this.destroy(element);
+
+    // build options for the draggables
+    var options_for_draggable = {
+      revert:      true,
+      scroll:      options.scroll,
+      scrollSpeed: options.scrollSpeed,
+      scrollSensitivity: options.scrollSensitivity,
+      delay:       options.delay,
+      ghosting:    options.ghosting,
+      constraint:  options.constraint,
+      handle:      options.handle };
+
+    if(options.starteffect)
+      options_for_draggable.starteffect = options.starteffect;
+
+    if(options.reverteffect)
+      options_for_draggable.reverteffect = options.reverteffect;
+    else
+      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+        element.style.top  = 0;
+        element.style.left = 0;
+      };
+
+    if(options.endeffect)
+      options_for_draggable.endeffect = options.endeffect;
+
+    if(options.zindex)
+      options_for_draggable.zindex = options.zindex;
+
+    // build options for the droppables  
+    var options_for_droppable = {
+      overlap:     options.overlap,
+      containment: options.containment,
+      tree:        options.tree,
+      hoverclass:  options.hoverclass,
+      onHover:     Sortable.onHover
+    }
+    
+    var options_for_tree = {
+      onHover:      Sortable.onEmptyHover,
+      overlap:      options.overlap,
+      containment:  options.containment,
+      hoverclass:   options.hoverclass
+    }
+
+    // fix for gecko engine
+    Element.cleanWhitespace(element); 
+
+    options.draggables = [];
+    options.droppables = [];
+
+    // drop on empty handling
+    if(options.dropOnEmpty || options.tree) {
+      Droppables.add(element, options_for_tree);
+      options.droppables.push(element);
+    }
+
+    (this.findElements(element, options) || []).each( function(e) {
+      // handles are per-draggable
+      var handle = options.handle ? 
+        $(e).down('.'+options.handle,0) : e;    
+      options.draggables.push(
+        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+      Droppables.add(e, options_for_droppable);
+      if(options.tree) e.treeNode = element;
+      options.droppables.push(e);      
+    });
+    
+    if(options.tree) {
+      (Sortable.findTreeElements(element, options) || []).each( function(e) {
+        Droppables.add(e, options_for_tree);
+        e.treeNode = element;
+        options.droppables.push(e);
+      });
+    }
+
+    // keep reference
+    this.sortables[element.id] = options;
+
+    // for onupdate
+    Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+  },
+
+  // return all suitable-for-sortable elements in a guaranteed order
+  findElements: function(element, options) {
+    return Element.findChildren(
+      element, options.only, options.tree ? true : false, options.tag);
+  },
+  
+  findTreeElements: function(element, options) {
+    return Element.findChildren(
+      element, options.only, options.tree ? true : false, options.treeTag);
+  },
+
+  onHover: function(element, dropon, overlap) {
+    if(Element.isParent(dropon, element)) return;
+
+    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+      return;
+    } else if(overlap>0.5) {
+      Sortable.mark(dropon, 'before');
+      if(dropon.previousSibling != element) {
+        var oldParentNode = element.parentNode;
+        element.style.visibility = "hidden"; // fix gecko rendering
+        dropon.parentNode.insertBefore(element, dropon);
+        if(dropon.parentNode!=oldParentNode) 
+          Sortable.options(oldParentNode).onChange(element);
+        Sortable.options(dropon.parentNode).onChange(element);
+      }
+    } else {
+      Sortable.mark(dropon, 'after');
+      var nextElement = dropon.nextSibling || null;
+      if(nextElement != element) {
+        var oldParentNode = element.parentNode;
+        element.style.visibility = "hidden"; // fix gecko rendering
+        dropon.parentNode.insertBefore(element, nextElement);
+        if(dropon.parentNode!=oldParentNode) 
+          Sortable.options(oldParentNode).onChange(element);
+        Sortable.options(dropon.parentNode).onChange(element);
+      }
+    }
+  },
+  
+  onEmptyHover: function(element, dropon, overlap) {
+    var oldParentNode = element.parentNode;
+    var droponOptions = Sortable.options(dropon);
+        
+    if(!Element.isParent(dropon, element)) {
+      var index;
+      
+      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+      var child = null;
+            
+      if(children) {
+        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+        
+        for (index = 0; index < children.length; index += 1) {
+          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+            offset -= Element.offsetSize (children[index], droponOptions.overlap);
+          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+            child = index + 1 < children.length ? children[index + 1] : null;
+            break;
+          } else {
+            child = children[index];
+            break;
+          }
+        }
+      }
+      
+      dropon.insertBefore(element, child);
+      
+      Sortable.options(oldParentNode).onChange(element);
+      droponOptions.onChange(element);
+    }
+  },
+
+  unmark: function() {
+    if(Sortable._marker) Sortable._marker.hide();
+  },
+
+  mark: function(dropon, position) {
+    // mark on ghosting only
+    var sortable = Sortable.options(dropon.parentNode);
+    if(sortable && !sortable.ghosting) return; 
+
+    if(!Sortable._marker) {
+      Sortable._marker = 
+        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+          hide().addClassName('dropmarker').setStyle({position:'absolute'});
+      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+    }    
+    var offsets = Position.cumulativeOffset(dropon);
+    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+    
+    if(position=='after')
+      if(sortable.overlap == 'horizontal') 
+        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+      else
+        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+    
+    Sortable._marker.show();
+  },
+  
+  _tree: function(element, options, parent) {
+    var children = Sortable.findElements(element, options) || [];
+  
+    for (var i = 0; i < children.length; ++i) {
+      var match = children[i].id.match(options.format);
+
+      if (!match) continue;
+      
+      var child = {
+        id: encodeURIComponent(match ? match[1] : null),
+        element: element,
+        parent: parent,
+        children: [],
+        position: parent.children.length,
+        container: $(children[i]).down(options.treeTag)
+      }
+      
+      /* Get the element containing the children and recurse over it */
+      if (child.container)
+        this._tree(child.container, options, child)
+      
+      parent.children.push (child);
+    }
+
+    return parent; 
+  },
+
+  tree: function(element) {
+    element = $(element);
+    var sortableOptions = this.options(element);
+    var options = Object.extend({
+      tag: sortableOptions.tag,
+      treeTag: sortableOptions.treeTag,
+      only: sortableOptions.only,
+      name: element.id,
+      format: sortableOptions.format
+    }, arguments[1] || {});
+    
+    var root = {
+      id: null,
+      parent: null,
+      children: [],
+      container: element,
+      position: 0
+    }
+    
+    return Sortable._tree(element, options, root);
+  },
+
+  /* Construct a [i] index for a particular node */
+  _constructIndex: function(node) {
+    var index = '';
+    do {
+      if (node.id) index = '[' + node.position + ']' + index;
+    } while ((node = node.parent) != null);
+    return index;
+  },
+
+  sequence: function(element) {
+    element = $(element);
+    var options = Object.extend(this.options(element), arguments[1] || {});
+    
+    return $(this.findElements(element, options) || []).map( function(item) {
+      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+    });
+  },
+
+  setSequence: function(element, new_sequence) {
+    element = $(element);
+    var options = Object.extend(this.options(element), arguments[2] || {});
+    
+    var nodeMap = {};
+    this.findElements(element, options).each( function(n) {
+        if (n.id.match(options.format))
+            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+        n.parentNode.removeChild(n);
+    });
+   
+    new_sequence.each(function(ident) {
+      var n = nodeMap[ident];
+      if (n) {
+        n[1].appendChild(n[0]);
+        delete nodeMap[ident];
+      }
+    });
+  },
+  
+  serialize: function(element) {
+    element = $(element);
+    var options = Object.extend(Sortable.options(element), arguments[1] || {});
+    var name = encodeURIComponent(
+      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+    
+    if (options.tree) {
+      return Sortable.tree(element, arguments[1]).children.map( function (item) {
+        return [name + Sortable._constructIndex(item) + "[id]=" + 
+                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+      }).flatten().join('&');
+    } else {
+      return Sortable.sequence(element, arguments[1]).map( function(item) {
+        return name + "[]=" + encodeURIComponent(item);
+      }).join('&');
+    }
+  }
+}
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+  if (!child.parentNode || child == element) return false;
+  if (child.parentNode == element) return true;
+  return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {    
+  if(!element.hasChildNodes()) return null;
+  tagName = tagName.toUpperCase();
+  if(only) only = [only].flatten();
+  var elements = [];
+  $A(element.childNodes).each( function(e) {
+    if(e.tagName && e.tagName.toUpperCase()==tagName &&
+      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+        elements.push(e);
+    if(recursive) {
+      var grandchildren = Element.findChildren(e, only, recursive, tagName);
+      if(grandchildren) elements.push(grandchildren);
+    }
+  });
+
+  return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}
+// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+//  Richard Livsey
+//  Rahul Bhargava
+//  Rob Wills
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality 
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least, 
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method 
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most 
+// useful when one of the tokens is \n (a newline), as it 
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+  throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = {}
+Autocompleter.Base = function() {};
+Autocompleter.Base.prototype = {
+  baseInitialize: function(element, update, options) {
+    this.element     = $(element); 
+    this.update      = $(update);  
+    this.hasFocus    = false; 
+    this.changed     = false; 
+    this.active      = false; 
+    this.index       = 0;     
+    this.entryCount  = 0;
+
+    if(this.setOptions)
+      this.setOptions(options);
+    else
+      this.options = options || {};
+
+    this.options.paramName    = this.options.paramName || this.element.name;
+    this.options.tokens       = this.options.tokens || [];
+    this.options.frequency    = this.options.frequency || 0.4;
+    this.options.minChars     = this.options.minChars || 1;
+    this.options.onShow       = this.options.onShow || 
+      function(element, update){ 
+        if(!update.style.position || update.style.position=='absolute') {
+          update.style.position = 'absolute';
+          Position.clone(element, update, {
+            setHeight: false, 
+            offsetTop: element.offsetHeight
+          });
+        }
+        Effect.Appear(update,{duration:0.15});
+      };
+    this.options.onHide = this.options.onHide || 
+      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+    if(typeof(this.options.tokens) == 'string') 
+      this.options.tokens = new Array(this.options.tokens);
+
+    this.observer = null;
+    
+    this.element.setAttribute('autocomplete','off');
+
+    Element.hide(this.update);
+
+    Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
+    Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+  },
+
+  show: function() {
+    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+    if(!this.iefix && 
+      (navigator.appVersion.indexOf('MSIE')>0) &&
+      (navigator.userAgent.indexOf('Opera')<0) &&
+      (Element.getStyle(this.update, 'position')=='absolute')) {
+      new Insertion.After(this.update, 
+       '<iframe id="' + this.update.id + '_iefix" '+
+       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+      this.iefix = $(this.update.id+'_iefix');
+    }
+    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+  },
+  
+  fixIEOverlapping: function() {
+    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+    this.iefix.style.zIndex = 1;
+    this.update.style.zIndex = 2;
+    Element.show(this.iefix);
+  },
+
+  hide: function() {
+    this.stopIndicator();
+    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+    if(this.iefix) Element.hide(this.iefix);
+  },
+
+  startIndicator: function() {
+    if(this.options.indicator) Element.show(this.options.indicator);
+  },
+
+  stopIndicator: function() {
+    if(this.options.indicator) Element.hide(this.options.indicator);
+  },
+
+  onKeyPress: function(event) {
+    if(this.active)
+      switch(event.keyCode) {
+       case Event.KEY_TAB:
+       case Event.KEY_RETURN:
+         this.selectEntry();
+         Event.stop(event);
+       case Event.KEY_ESC:
+         this.hide();
+         this.active = false;
+         Event.stop(event);
+         return;
+       case Event.KEY_LEFT:
+       case Event.KEY_RIGHT:
+         return;
+       case Event.KEY_UP:
+         this.markPrevious();
+         this.render();
+         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+         return;
+       case Event.KEY_DOWN:
+         this.markNext();
+         this.render();
+         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+         return;
+      }
+     else 
+       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
+         (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
+
+    this.changed = true;
+    this.hasFocus = true;
+
+    if(this.observer) clearTimeout(this.observer);
+      this.observer = 
+        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+  },
+
+  activate: function() {
+    this.changed = false;
+    this.hasFocus = true;
+    this.getUpdatedChoices();
+  },
+
+  onHover: function(event) {
+    var element = Event.findElement(event, 'LI');
+    if(this.index != element.autocompleteIndex) 
+    {
+        this.index = element.autocompleteIndex;
+        this.render();
+    }
+    Event.stop(event);
+  },
+  
+  onClick: function(event) {
+    var element = Event.findElement(event, 'LI');
+    this.index = element.autocompleteIndex;
+    this.selectEntry();
+    this.hide();
+  },
+  
+  onBlur: function(event) {
+    // needed to make click events working
+    setTimeout(this.hide.bind(this), 250);
+    this.hasFocus = false;
+    this.active = false;     
+  }, 
+  
+  render: function() {
+    if(this.entryCount > 0) {
+      for (var i = 0; i < this.entryCount; i++)
+        this.index==i ? 
+          Element.addClassName(this.getEntry(i),"selected") : 
+          Element.removeClassName(this.getEntry(i),"selected");
+        
+      if(this.hasFocus) { 
+        this.show();
+        this.active = true;
+      }
+    } else {
+      this.active = false;
+      this.hide();
+    }
+  },
+  
+  markPrevious: function() {
+    if(this.index > 0) this.index--
+      else this.index = this.entryCount-1;
+    this.getEntry(this.index).scrollIntoView(true);
+  },
+  
+  markNext: function() {
+    if(this.index < this.entryCount-1) this.index++
+      else this.index = 0;
+    this.getEntry(this.index).scrollIntoView(false);
+  },
+  
+  getEntry: function(index) {
+    return this.update.firstChild.childNodes[index];
+  },
+  
+  getCurrentEntry: function() {
+    return this.getEntry(this.index);
+  },
+  
+  selectEntry: function() {
+    this.active = false;
+    this.updateElement(this.getCurrentEntry());
+  },
+
+  updateElement: function(selectedElement) {
+    if (this.options.updateElement) {
+      this.options.updateElement(selectedElement);
+      return;
+    }
+    var value = '';
+    if (this.options.select) {
+      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
+      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+    } else
+      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+    
+    var lastTokenPos = this.findLastToken();
+    if (lastTokenPos != -1) {
+      var newValue = this.element.value.substr(0, lastTokenPos + 1);
+      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+      if (whitespace)
+        newValue += whitespace[0];
+      this.element.value = newValue + value;
+    } else {
+      this.element.value = value;
+    }
+    this.element.focus();
+    
+    if (this.options.afterUpdateElement)
+      this.options.afterUpdateElement(this.element, selectedElement);
+  },
+
+  updateChoices: function(choices) {
+    if(!this.changed && this.hasFocus) {
+      this.update.innerHTML = choices;
+      Element.cleanWhitespace(this.update);
+      Element.cleanWhitespace(this.update.down());
+
+      if(this.update.firstChild && this.update.down().childNodes) {
+        this.entryCount = 
+          this.update.down().childNodes.length;
+        for (var i = 0; i < this.entryCount; i++) {
+          var entry = this.getEntry(i);
+          entry.autocompleteIndex = i;
+          this.addObservers(entry);
+        }
+      } else { 
+        this.entryCount = 0;
+      }
+
+      this.stopIndicator();
+      this.index = 0;
+      
+      if(this.entryCount==1 && this.options.autoSelect) {
+        this.selectEntry();
+        this.hide();
+      } else {
+        this.render();
+      }
+    }
+  },
+
+  addObservers: function(element) {
+    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+  },
+
+  onObserverEvent: function() {
+    this.changed = false;   
+    if(this.getToken().length>=this.options.minChars) {
+      this.startIndicator();
+      this.getUpdatedChoices();
+    } else {
+      this.active = false;
+      this.hide();
+    }
+  },
+
+  getToken: function() {
+    var tokenPos = this.findLastToken();
+    if (tokenPos != -1)
+      var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
+    else
+      var ret = this.element.value;
+
+    return /\n/.test(ret) ? '' : ret;
+  },
+
+  findLastToken: function() {
+    var lastTokenPos = -1;
+
+    for (var i=0; i<this.options.tokens.length; i++) {
+      var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
+      if (thisTokenPos > lastTokenPos)
+        lastTokenPos = thisTokenPos;
+    }
+    return lastTokenPos;
+  }
+}
+
+Ajax.Autocompleter = Class.create();
+Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
+  initialize: function(element, update, url, options) {
+    this.baseInitialize(element, update, options);
+    this.options.asynchronous  = true;
+    this.options.onComplete    = this.onComplete.bind(this);
+    this.options.defaultParams = this.options.parameters || null;
+    this.url                   = url;
+  },
+
+  getUpdatedChoices: function() {
+    entry = encodeURIComponent(this.options.paramName) + '=' + 
+      encodeURIComponent(this.getToken());
+
+    this.options.parameters = this.options.callback ?
+      this.options.callback(this.element, entry) : entry;
+
+    if(this.options.defaultParams) 
+      this.options.parameters += '&' + this.options.defaultParams;
+
+    new Ajax.Request(this.url, this.options);
+  },
+
+  onComplete: function(request) {
+    this.updateChoices(request.responseText);
+  }
+
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+//                    text only at the beginning of strings in the 
+//                    autocomplete array. Defaults to true, which will
+//                    match text at the beginning of any *word* in the
+//                    strings in the autocomplete array. If you want to
+//                    search anywhere in the string, additionally set
+//                    the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+//                   a partial match (unlike minChars, which defines
+//                   how many characters are required to do any match
+//                   at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+//                 Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector' 
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create();
+Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
+  initialize: function(element, update, array, options) {
+    this.baseInitialize(element, update, options);
+    this.options.array = array;
+  },
+
+  getUpdatedChoices: function() {
+    this.updateChoices(this.options.selector(this));
+  },
+
+  setOptions: function(options) {
+    this.options = Object.extend({
+      choices: 10,
+      partialSearch: true,
+      partialChars: 2,
+      ignoreCase: true,
+      fullSearch: false,
+      selector: function(instance) {
+        var ret       = []; // Beginning matches
+        var partial   = []; // Inside matches
+        var entry     = instance.getToken();
+        var count     = 0;
+
+        for (var i = 0; i < instance.options.array.length &&  
+          ret.length < instance.options.choices ; i++) { 
+
+          var elem = instance.options.array[i];
+          var foundPos = instance.options.ignoreCase ? 
+            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
+            elem.indexOf(entry);
+
+          while (foundPos != -1) {
+            if (foundPos == 0 && elem.length != entry.length) { 
+              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
+                elem.substr(entry.length) + "</li>");
+              break;
+            } else if (entry.length >= instance.options.partialChars && 
+              instance.options.partialSearch && foundPos != -1) {
+              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+                  foundPos + entry.length) + "</li>");
+                break;
+              }
+            }
+
+            foundPos = instance.options.ignoreCase ? 
+              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
+              elem.indexOf(entry, foundPos + 1);
+
+          }
+        }
+        if (partial.length)
+          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+        return "<ul>" + ret.join('') + "</ul>";
+      }
+    }, options || {});
+  }
+});
+
+// AJAX in-place editor
+//
+// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+  setTimeout(function() {
+    Field.activate(field);
+  }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create();
+Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
+Ajax.InPlaceEditor.prototype = {
+  initialize: function(element, url, options) {
+    this.url = url;
+    this.element = $(element);
+
+    this.options = Object.extend({
+      paramName: "value",
+      okButton: true,
+      okText: "ok",
+      cancelLink: true,
+      cancelText: "cancel",
+      savingText: "Saving...",
+      clickToEditText: "Click to edit",
+      okText: "ok",
+      rows: 1,
+      onComplete: function(transport, element) {
+        new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
+      },
+      onFailure: function(transport) {
+        alert("Error communicating with the server: " + transport.responseText.stripTags());
+      },
+      callback: function(form) {
+        return Form.serialize(form);
+      },
+      handleLineBreaks: true,
+      loadingText: 'Loading...',
+      savingClassName: 'inplaceeditor-saving',
+      loadingClassName: 'inplaceeditor-loading',
+      formClassName: 'inplaceeditor-form',
+      highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
+      highlightendcolor: "#FFFFFF",
+      externalControl: null,
+      submitOnBlur: false,
+      ajaxOptions: {},
+      evalScripts: false
+    }, options || {});
+
+    if(!this.options.formId && this.element.id) {
+      this.options.formId = this.element.id + "-inplaceeditor";
+      if ($(this.options.formId)) {
+        // there's already a form with that name, don't specify an id
+        this.options.formId = null;
+      }
+    }
+    
+    if (this.options.externalControl) {
+      this.options.externalControl = $(this.options.externalControl);
+    }
+    
+    this.originalBackground = Element.getStyle(this.element, 'background-color');
+    if (!this.originalBackground) {
+      this.originalBackground = "transparent";
+    }
+    
+    this.element.title = this.options.clickToEditText;
+    
+    this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+    this.mouseoverListener = this.enterHover.bindAsEventListener(this);
+    this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
+    Event.observe(this.element, 'click', this.onclickListener);
+    Event.observe(this.element, 'mouseover', this.mouseoverListener);
+    Event.observe(this.element, 'mouseout', this.mouseoutListener);
+    if (this.options.externalControl) {
+      Event.observe(this.options.externalControl, 'click', this.onclickListener);
+      Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
+      Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
+    }
+  },
+  enterEditMode: function(evt) {
+    if (this.saving) return;
+    if (this.editing) return;
+    this.editing = true;
+    this.onEnterEditMode();
+    if (this.options.externalControl) {
+      Element.hide(this.options.externalControl);
+    }
+    Element.hide(this.element);
+    this.createForm();
+    this.element.parentNode.insertBefore(this.form, this.element);
+    if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
+    // stop the event to avoid a page refresh in Safari
+    if (evt) {
+      Event.stop(evt);
+    }
+    return false;
+  },
+  createForm: function() {
+    this.form = document.createElement("form");
+    this.form.id = this.options.formId;
+    Element.addClassName(this.form, this.options.formClassName)
+    this.form.onsubmit = this.onSubmit.bind(this);
+
+    this.createEditField();
+
+    if (this.options.textarea) {
+      var br = document.createElement("br");
+      this.form.appendChild(br);
+    }
+
+    if (this.options.okButton) {
+      okButton = document.createElement("input");
+      okButton.type = "submit";
+      okButton.value = this.options.okText;
+      okButton.className = 'editor_ok_button';
+      this.form.appendChild(okButton);
+    }
+
+    if (this.options.cancelLink) {
+      cancelLink = document.createElement("a");
+      cancelLink.href = "javascript:void(0)";
+      cancelLink.appendChild(document.createTextNode(this.options.cancelText));
+      cancelLink.onclick = this.onclickCancel.bind(this);
+      cancelLink.className = 'editor_cancel';      
+      this.form.appendChild(cancelLink);
+    }
+  },
+  hasHTMLLineBreaks: function(string) {
+    if (!this.options.handleLineBreaks) return false;
+    return string.match(/<br/i) || string.match(/<p>/i);
+  },
+  convertHTMLLineBreaks: function(string) {
+    return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
+  },
+  createEditField: function() {
+    var text;
+    if(this.options.loadTextURL) {
+      text = this.options.loadingText;
+    } else {
+      text = this.getText();
+    }
+
+    var obj = this;
+    
+    if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
+      this.options.textarea = false;
+      var textField = document.createElement("input");
+      textField.obj = this;
+      textField.type = "text";
+      textField.name = this.options.paramName;
+      textField.value = text;
+      textField.style.backgroundColor = this.options.highlightcolor;
+      textField.className = 'editor_field';
+      var size = this.options.size || this.options.cols || 0;
+      if (size != 0) textField.size = size;
+      if (this.options.submitOnBlur)
+        textField.onblur = this.onSubmit.bind(this);
+      this.editField = textField;
+    } else {
+      this.options.textarea = true;
+      var textArea = document.createElement("textarea");
+      textArea.obj = this;
+      textArea.name = this.options.paramName;
+      textArea.value = this.convertHTMLLineBreaks(text);
+      textArea.rows = this.options.rows;
+      textArea.cols = this.options.cols || 40;
+      textArea.className = 'editor_field';      
+      if (this.options.submitOnBlur)
+        textArea.onblur = this.onSubmit.bind(this);
+      this.editField = textArea;
+    }
+    
+    if(this.options.loadTextURL) {
+      this.loadExternalText();
+    }
+    this.form.appendChild(this.editField);
+  },
+  getText: function() {
+    return this.element.innerHTML;
+  },
+  loadExternalText: function() {
+    Element.addClassName(this.form, this.options.loadingClassName);
+    this.editField.disabled = true;
+    new Ajax.Request(
+      this.options.loadTextURL,
+      Object.extend({
+        asynchronous: true,
+        onComplete: this.onLoadedExternalText.bind(this)
+      }, this.options.ajaxOptions)
+    );
+  },
+  onLoadedExternalText: function(transport) {
+    Element.removeClassName(this.form, this.options.loadingClassName);
+    this.editField.disabled = false;
+    this.editField.value = transport.responseText.stripTags();
+    Field.scrollFreeActivate(this.editField);
+  },
+  onclickCancel: function() {
+    this.onComplete();
+    this.leaveEditMode();
+    return false;
+  },
+  onFailure: function(transport) {
+    this.options.onFailure(transport);
+    if (this.oldInnerHTML) {
+      this.element.innerHTML = this.oldInnerHTML;
+      this.oldInnerHTML = null;
+    }
+    return false;
+  },
+  onSubmit: function() {
+    // onLoading resets these so we need to save them away for the Ajax call
+    var form = this.form;
+    var value = this.editField.value;
+    
+    // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
+    // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
+    // to be displayed indefinitely
+    this.onLoading();
+    
+    if (this.options.evalScripts) {
+      new Ajax.Request(
+        this.url, Object.extend({
+          parameters: this.options.callback(form, value),
+          onComplete: this.onComplete.bind(this),
+          onFailure: this.onFailure.bind(this),
+          asynchronous:true, 
+          evalScripts:true
+        }, this.options.ajaxOptions));
+    } else  {
+      new Ajax.Updater(
+        { success: this.element,
+          // don't update on failure (this could be an option)
+          failure: null }, 
+        this.url, Object.extend({
+          parameters: this.options.callback(form, value),
+          onComplete: this.onComplete.bind(this),
+          onFailure: this.onFailure.bind(this)
+        }, this.options.ajaxOptions));
+    }
+    // stop the event to avoid a page refresh in Safari
+    if (arguments.length > 1) {
+      Event.stop(arguments[0]);
+    }
+    return false;
+  },
+  onLoading: function() {
+    this.saving = true;
+    this.removeForm();
+    this.leaveHover();
+    this.showSaving();
+  },
+  showSaving: function() {
+    this.oldInnerHTML = this.element.innerHTML;
+    this.element.innerHTML = this.options.savingText;
+    Element.addClassName(this.element, this.options.savingClassName);
+    this.element.style.backgroundColor = this.originalBackground;
+    Element.show(this.element);
+  },
+  removeForm: function() {
+    if(this.form) {
+      if (this.form.parentNode) Element.remove(this.form);
+      this.form = null;
+    }
+  },
+  enterHover: function() {
+    if (this.saving) return;
+    this.element.style.backgroundColor = this.options.highlightcolor;
+    if (this.effect) {
+      this.effect.cancel();
+    }
+    Element.addClassName(this.element, this.options.hoverClassName)
+  },
+  leaveHover: function() {
+    if (this.options.backgroundColor) {
+      this.element.style.backgroundColor = this.oldBackground;
+    }
+    Element.removeClassName(this.element, this.options.hoverClassName)
+    if (this.saving) return;
+    this.effect = new Effect.Highlight(this.element, {
+      startcolor: this.options.highlightcolor,
+      endcolor: this.options.highlightendcolor,
+      restorecolor: this.originalBackground
+    });
+  },
+  leaveEditMode: function() {
+    Element.removeClassName(this.element, this.options.savingClassName);
+    this.removeForm();
+    this.leaveHover();
+    this.element.style.backgroundColor = this.originalBackground;
+    Element.show(this.element);
+    if (this.options.externalControl) {
+      Element.show(this.options.externalControl);
+    }
+    this.editing = false;
+    this.saving = false;
+    this.oldInnerHTML = null;
+    this.onLeaveEditMode();
+  },
+  onComplete: function(transport) {
+    this.leaveEditMode();
+    this.options.onComplete.bind(this)(transport, this.element);
+  },
+  onEnterEditMode: function() {},
+  onLeaveEditMode: function() {},
+  dispose: function() {
+    if (this.oldInnerHTML) {
+      this.element.innerHTML = this.oldInnerHTML;
+    }
+    this.leaveEditMode();
+    Event.stopObserving(this.element, 'click', this.onclickListener);
+    Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
+    Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
+    if (this.options.externalControl) {
+      Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
+      Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
+      Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+    }
+  }
+};
+
+Ajax.InPlaceCollectionEditor = Class.create();
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
+Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
+  createEditField: function() {
+    if (!this.cached_selectTag) {
+      var selectTag = document.createElement("select");
+      var collection = this.options.collection || [];
+      var optionTag;
+      collection.each(function(e,i) {
+        optionTag = document.createElement("option");
+        optionTag.value = (e instanceof Array) ? e[0] : e;
+        if((typeof this.options.value == 'undefined') && 
+          ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
+        if(this.options.value==optionTag.value) optionTag.selected = true;
+        optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
+        selectTag.appendChild(optionTag);
+      }.bind(this));
+      this.cached_selectTag = selectTag;
+    }
+
+    this.editField = this.cached_selectTag;
+    if(this.options.loadTextURL) this.loadExternalText();
+    this.form.appendChild(this.editField);
+    this.options.callback = function(form, value) {
+      return "value=" + encodeURIComponent(value);
+    }
+  }
+});
+
+// Delayed observer, like Form.Element.Observer, 
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create();
+Form.Element.DelayedObserver.prototype = {
+  initialize: function(element, delay, callback) {
+    this.delay     = delay || 0.5;
+    this.element   = $(element);
+    this.callback  = callback;
+    this.timer     = null;
+    this.lastValue = $F(this.element); 
+    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+  },
+  delayedListener: function(event) {
+    if(this.lastValue == $F(this.element)) return;
+    if(this.timer) clearTimeout(this.timer);
+    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+    this.lastValue = $F(this.element);
+  },
+  onTimerEvent: function() {
+    this.timer = null;
+    this.callback(this.element, $F(this.element));
+  }
+};
+// script.aculo.us slider.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
+
+// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs 
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(!Control) var Control = {};
+Control.Slider = Class.create();
+
+// options:
+//  axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+//  onChange(value)
+//  onSlide(value)
+Control.Slider.prototype = {
+  initialize: function(handle, track, options) {
+    var slider = this;
+    
+    if(handle instanceof Array) {
+      this.handles = handle.collect( function(e) { return $(e) });
+    } else {
+      this.handles = [$(handle)];
+    }
+    
+    this.track   = $(track);
+    this.options = options || {};
+
+    this.axis      = this.options.axis || 'horizontal';
+    this.increment = this.options.increment || 1;
+    this.step      = parseInt(this.options.step || '1');
+    this.range     = this.options.range || $R(0,1);
+    
+    this.value     = 0; // assure backwards compat
+    this.values    = this.handles.map( function() { return 0 });
+    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+    this.options.startSpan = $(this.options.startSpan || null);
+    this.options.endSpan   = $(this.options.endSpan || null);
+
+    this.restricted = this.options.restricted || false;
+
+    this.maximum   = this.options.maximum || this.range.end;
+    this.minimum   = this.options.minimum || this.range.start;
+
+    // Will be used to align the handle onto the track, if necessary
+    this.alignX = parseInt(this.options.alignX || '0');
+    this.alignY = parseInt(this.options.alignY || '0');
+    
+    this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+    this.handleLength = this.isVertical() ? 
+      (this.handles[0].offsetHeight != 0 ? 
+        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
+      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
+        this.handles[0].style.width.replace(/px$/,""));
+
+    this.active   = false;
+    this.dragging = false;
+    this.disabled = false;
+
+    if(this.options.disabled) this.setDisabled();
+
+    // Allowed values array
+    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+    if(this.allowedValues) {
+      this.minimum = this.allowedValues.min();
+      this.maximum = this.allowedValues.max();
+    }
+
+    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
+    this.eventMouseMove = this.update.bindAsEventListener(this);
+
+    // Initialize handles in reverse (make sure first handle is active)
+    this.handles.each( function(h,i) {
+      i = slider.handles.length-1-i;
+      slider.setValue(parseFloat(
+        (slider.options.sliderValue instanceof Array ? 
+          slider.options.sliderValue[i] : slider.options.sliderValue) || 
+         slider.range.start), i);
+      Element.makePositioned(h); // fix IE
+      Event.observe(h, "mousedown", slider.eventMouseDown);
+    });
+    
+    Event.observe(this.track, "mousedown", this.eventMouseDown);
+    Event.observe(document, "mouseup", this.eventMouseUp);
+    Event.observe(document, "mousemove", this.eventMouseMove);
+    
+    this.initialized = true;
+  },
+  dispose: function() {
+    var slider = this;    
+    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+    Event.stopObserving(document, "mouseup", this.eventMouseUp);
+    Event.stopObserving(document, "mousemove", this.eventMouseMove);
+    this.handles.each( function(h) {
+      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+    });
+  },
+  setDisabled: function(){
+    this.disabled = true;
+  },
+  setEnabled: function(){
+    this.disabled = false;
+  },  
+  getNearestValue: function(value){
+    if(this.allowedValues){
+      if(value >= this.allowedValues.max()) return(this.allowedValues.max());
+      if(value <= this.allowedValues.min()) return(this.allowedValues.min());
+      
+      var offset = Math.abs(this.allowedValues[0] - value);
+      var newValue = this.allowedValues[0];
+      this.allowedValues.each( function(v) {
+        var currentOffset = Math.abs(v - value);
+        if(currentOffset <= offset){
+          newValue = v;
+          offset = currentOffset;
+        } 
+      });
+      return newValue;
+    }
+    if(value > this.range.end) return this.range.end;
+    if(value < this.range.start) return this.range.start;
+    return value;
+  },
+  setValue: function(sliderValue, handleIdx){
+    if(!this.active) {
+      this.activeHandleIdx = handleIdx || 0;
+      this.activeHandle    = this.handles[this.activeHandleIdx];
+      this.updateStyles();
+    }
+    handleIdx = handleIdx || this.activeHandleIdx || 0;
+    if(this.initialized && this.restricted) {
+      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+        sliderValue = this.values[handleIdx-1];
+      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+        sliderValue = this.values[handleIdx+1];
+    }
+    sliderValue = this.getNearestValue(sliderValue);
+    this.values[handleIdx] = sliderValue;
+    this.value = this.values[0]; // assure backwards compat
+    
+    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
+      this.translateToPx(sliderValue);
+    
+    this.drawSpans();
+    if(!this.dragging || !this.event) this.updateFinished();
+  },
+  setValueBy: function(delta, handleIdx) {
+    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
+      handleIdx || this.activeHandleIdx || 0);
+  },
+  translateToPx: function(value) {
+    return Math.round(
+      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
+      (value - this.range.start)) + "px";
+  },
+  translateToValue: function(offset) {
+    return ((offset/(this.trackLength-this.handleLength) * 
+      (this.range.end-this.range.start)) + this.range.start);
+  },
+  getRange: function(range) {
+    var v = this.values.sortBy(Prototype.K); 
+    range = range || 0;
+    return $R(v[range],v[range+1]);
+  },
+  minimumOffset: function(){
+    return(this.isVertical() ? this.alignY : this.alignX);
+  },
+  maximumOffset: function(){
+    return(this.isVertical() ? 
+      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+        this.track.style.height.replace(/px$/,"")) - this.alignY : 
+      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
+        this.track.style.width.replace(/px$/,"")) - this.alignY);
+  },  
+  isVertical:  function(){
+    return (this.axis == 'vertical');
+  },
+  drawSpans: function() {
+    var slider = this;
+    if(this.spans)
+      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
+    if(this.options.startSpan)
+      this.setSpan(this.options.startSpan,
+        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
+    if(this.options.endSpan)
+      this.setSpan(this.options.endSpan, 
+        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
+  },
+  setSpan: function(span, range) {
+    if(this.isVertical()) {
+      span.style.top = this.translateToPx(range.start);
+      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+    } else {
+      span.style.left = this.translateToPx(range.start);
+      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+    }
+  },
+  updateStyles: function() {
+    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
+    Element.addClassName(this.activeHandle, 'selected');
+  },
+  startDrag: function(event) {
+    if(Event.isLeftClick(event)) {
+      if(!this.disabled){
+        this.active = true;
+        
+        var handle = Event.element(event);
+        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
+        var track = handle;
+        if(track==this.track) {
+          var offsets  = Position.cumulativeOffset(this.track); 
+          this.event = event;
+          this.setValue(this.translateToValue( 
+           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
+          ));
+          var offsets  = Position.cumulativeOffset(this.activeHandle);
+          this.offsetX = (pointer[0] - offsets[0]);
+          this.offsetY = (pointer[1] - offsets[1]);
+        } else {
+          // find the handle (prevents issues with Safari)
+          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
+            handle = handle.parentNode;
+            
+          if(this.handles.indexOf(handle)!=-1) {
+            this.activeHandle    = handle;
+            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+            this.updateStyles();
+            
+            var offsets  = Position.cumulativeOffset(this.activeHandle);
+            this.offsetX = (pointer[0] - offsets[0]);
+            this.offsetY = (pointer[1] - offsets[1]);
+          }
+        }
+      }
+      Event.stop(event);
+    }
+  },
+  update: function(event) {
+   if(this.active) {
+      if(!this.dragging) this.dragging = true;
+      this.draw(event);
+      // fix AppleWebKit rendering
+      if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+      Event.stop(event);
+   }
+  },
+  draw: function(event) {
+    var pointer = [Event.pointerX(event), Event.pointerY(event)];
+    var offsets = Position.cumulativeOffset(this.track);
+    pointer[0] -= this.offsetX + offsets[0];
+    pointer[1] -= this.offsetY + offsets[1];
+    this.event = event;
+    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+    if(this.initialized && this.options.onSlide)
+      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
+  },
+  endDrag: function(event) {
+    if(this.active && this.dragging) {
+      this.finishDrag(event, true);
+      Event.stop(event);
+    }
+    this.active = false;
+    this.dragging = false;
+  },  
+  finishDrag: function(event, success) {
+    this.active = false;
+    this.dragging = false;
+    this.updateFinished();
+  },
+  updateFinished: function() {
+    if(this.initialized && this.options.onChange) 
+      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
+    this.event = null;
+  }
+}/**
+ * $Id: jxcore.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx Core
+ *
+ * Purpose: 
+ * Implementation of core and base classes for Jx components.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/ 
+/**
+ * Class: Jx
+ * Jx is a global singleton object that contains the entire Jx library
+ * within it.  All Jx functions, attributes and classes are accessed
+ * through the global Jx object.  Jx should not create any other
+ * global variables, if you discover that it does then please report
+ * it as a bug
+ */
+ 
+/* LEAVE THIS SEMI-COLON, IT PREVENTS PROBLEMS WITH COMPRESSION */
+;
+
+/* firebug console supressor for IE/Safari/Opera */
+if (!("console" in window) || !("firebug" in console)) {
+    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+    window.console = {};
+    for (var i = 0; i < names.length; ++i) {
+        window.console[names[i]] = function() {};
+    }
+}
+/* inspired by extjs, removes css image flicker and related problems in IE 6 */
+var ua = navigator.userAgent.toLowerCase();
+var isIE = ua.indexOf("msie") > -1,
+    isIE7 = ua.indexOf("msie 7") > -1;
+if(isIE && !isIE7) {
+    try {
+        document.execCommand("BackgroundImageCache", false, true);
+    } catch(e) {}
+}
+
+/* Setup global namespace
+ * If jxcore is loaded by jx.js, then the namespace and baseURL are
+ * already established
+ */
+if (typeof Jx == 'undefined') {
+    var Jx = {};
+    /**
+     * Property: {Boolean} COMBINED_CSS
+     * controls whether Jx uses a single, combined CSS file or
+     * individual ones.  The combined version is used automatically
+     * if the combined or compressed version of Jx is used,
+     * otherwise separate ones are used.
+     */ 
+    Jx.COMBINED_CSS = true;
+    var aScripts = document.getElementsByTagName('SCRIPT');
+    for (var i=0; i<aScripts.length; i++) {
+        var s = aScripts[i].src;
+        //only check for lib/jx because we were loaded by 
+        var n = s.indexOf('lib/jx');
+        if (n != -1) {
+            /**
+             * Property: {String} baseURL
+             * This is the URL that Jx was loaded from, it is 
+             * automatically calculated from the script tag
+             * src property that included Jx.
+             */ 
+            Jx.baseURL = s.substring(0,n);
+            break;
+        }
+    }
+} 
+
+/**
+ * Property: {Object} importRules
+ *
+ * an object containing a list of CSS files to be included
+ * to make the loaded Jx components function correctly
+ */
+Jx.importRules = {};
+/**
+ * Property: {Object} importRules
+ *
+ * an object containing a list of CSS files to be included
+ * to make the loaded Jx components function correctly
+ */
+Jx.importRulesIE = {};
+
+/**
+ * Method: addStyleSheet
+ *
+ * Individual components of Jx call this function to get their
+ * style sheets imported at run time.
+ *
+ * Parameters:
+ *
+ *   styleSheet {String} the relative path to the CSS file (relative
+ *              to <Jx.baseURL>).
+ *
+ *   ieOnly {Boolean} if true, then the style sheet is only loaded 
+ *          if the browser is Internet Explorer.
+ */
+Jx.addStyleSheet = function(styleSheet, ieOnly) { 
+    if (ieOnly) {
+        this.importRulesIE[styleSheet] = styleSheet; 
+    } else {
+        this.importRules[styleSheet] = styleSheet; 
+    }
+};
+
+/* everything needs reset.css */
+Jx.addStyleSheet('reset.css');
+
+/**
+ * Method: applyPNGFilter
+ *
+ * Static method that applies the PNG Filter Hack for IE browsers
+ * when showing 24bit PNG's.  Used automatically for img tags with
+ * a class of png24.
+ *
+ * The filter is applied using a nifty feature of IE that allows javascript to
+ * be executed as part of a CSS style rule - this ensures that the hack only
+ * gets applied on IE browsers.
+ *
+ * Parameters:
+ *
+ *   object {Object} the object (img) to which the filter needs to be applied.
+ */
+Jx.applyPNGFilter = function(o)  {
+   var t=Jx.baseURL + "images/a_pixel.png";
+   if( o.src != t ) {
+       var s=o.src;
+       o.src = t;
+       o.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";
+   }
+};
+
+Jx.imgQueue = [];   //The queue of images to be loaded
+Jx.imgLoaded = {};  //a hash table of images that have been loaded and cached
+Jx.imagesLoading = 0; //counter for number of concurrent image loads 
+
+/**
+ * Method: addToImgQueue
+ *
+ * request that an image be set to a DOM IMG element src attribute.  This puts 
+ * the image into a queue and there are private methods to manage that queue
+ * and limit image loading to 2 at a time.
+ */
+Jx.addToImgQueue = function(obj) {
+    if (Jx.imgLoaded[obj.src]) {
+        //if this image was already requested (i.e. it's in cache) just set it directly
+        obj.domElement.src = obj.src;
+    } else {
+        //otherwise stick it in te queue
+        Jx.imgQueue.push(obj);
+        Jx.imgLoaded[obj.src] = true;
+    }
+    //start the queue management process
+    Jx.checkImgQueue();
+};
+
+/**
+ * Method: checkImgQueue
+ *
+ * An internal method that ensures no more than 2 images are loading at a time.
+ */
+Jx.checkImgQueue = function() {
+    //console.log(this.imgQueue.length+":"+this.imagesLoading);
+    while (Jx.imagesLoading < 2 && Jx.imgQueue.length > 0) {
+        Jx.loadNextImg();
+    }
+};
+
+/**
+ * Method: loadNextImg
+ *
+ * An internal method actually populate the DOM element with the image source.
+ */
+Jx.loadNextImg = function() {
+    var obj = Jx.imgQueue.shift();
+    if (obj) {
+        ++Jx.imagesLoading;
+        obj.domElement.onload = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
+        obj.domElement.onerror = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
+        obj.domElement.src = obj.src;
+    }
+}; 
+
+
+/**
+  * Class: Jx.Listener
+ *
+ * Jx.Listener is a mix-in class that performs common listener functions
+ * for objects that support listeners.  It is intended to be added to
+ * existing classes using the following syntax:
+ *
+ * (code)
+ * Object.extends( MyClass.prototype, Jx.Listener.prototype)
+ * (end)
+ *
+ * The Jx.Listener class functions provide support for managing a list of
+ * listeners (add, remove) and dispatching events to listeners (processEvent).
+ */
+Jx.Listener = Class.create();
+Jx.Listener.prototype = {
+    /**
+     * Method: addListener
+     *
+     * add a listener to the provided list.
+     *
+     * Parameters:
+     *
+     *   list {Array} the array of listeners to add the listener to.
+     *
+     *   object {Object} the object to add as a listener.
+     */
+    addListener: function (list,obj) {list.push(obj);},
+    /**
+     * Method: removeListener
+     *
+     * remove a listener from the provided list.
+     *
+     * Parameters:
+     *
+     * list {Array} the array of listeners to remove the listener from.
+     *
+     * obj {Object} the object to remove as a listener.
+     */
+    removeListener: function(list,obj) {
+        for(var i=0;i<list.length;i++) {if (list[i] == obj) {list.splice(i,1); break;}}},
+    /**
+     * Method: processEvent
+     *
+     * call each listener with a given method and event.
+     *
+     * Parameters:
+     *
+     *   list {Array} the array of listeners to call.
+     *
+     *   fnName {String} the name of a function to call on each listener.
+     *
+     *   obj {Object} an object to pass to each listener.
+     */
+    processEvent: function(list,fnName,obj){list.each(function(o){if (o[fnName]) {o[fnName](obj);}});}
+};
+
+/**
+ * Class: Jx.UniqueId
+ *
+ * Jx.UniqueId is used to assign unique ids to selected elements
+ * This is used to solve a problem where multiple external html
+ * fragments are loaded into the DOM via ajax at runtime.  It is
+ * not always possible to ensure that every element has a unique
+ * id.  This is not a problem if you are using id for CSS styling
+ * but if you are using it to access elements using $() then
+ * you may get unexpected results.
+ *
+ * Jx.UniqueId is a mix-in class.  Extend an existing class to
+ * enable it to handle unique ids.  Register the ids that you
+ * want to be unique and then get a reference to those objects
+ * through the interface exposed by this class.
+ *
+ * The class retrieves the elements by id by walking a dom object
+ * and retains references to each of the actual DOM objects
+ * you have registered.
+ */
+Jx.UniqueId = Class.create();
+Jx.UniqueId.prototype = {
+    /**
+     * Property: {Array} uniqueIdRefs
+     *
+     * an array of references obtained from by registering ids
+     */
+    uniqueIdRefs: null,
+    /**
+     * Method: initUniqueId
+     * 
+     * initialize the UniqueId object.  This must be called prior to
+     * calling the <registerIds> function.  Typically, it is called
+     * in the constructor of an object that includes Jx.UniqueId.
+     */
+    initUniqueId: function() { 
+        this.uniqueIdRefs = [];
+    },
+    /**
+     * Method: deregisterIds
+     *
+     * removes all registered ids
+     */
+    deregisterIds: function() {
+        this.uniqueIdRefs.length = 0;
+    },
+    /**
+     * Method: registerIds
+     *
+     * searches the domObj for each of the ids passed in and
+     * obtains a unique reference to them so that subsequent
+     * calls to <getObj> will return the right object.
+     *
+     * Parameters:
+     *
+     * aIds {Array} an array of strings containing ids of DOM elements
+     *      to register.
+     *
+     * domObj {Object} an HTML element reference to search for unique
+     *        ids within
+     */
+    registerIds: function (aIds, domObj) {
+        if (aIds.indexOf(domObj.id) != -1) {
+            this.uniqueIdRefs[domObj.id] = domObj;
+        }
+        for (var i=0; i<domObj.childNodes.length; i++) {
+            this.registerIds(aIds, domObj.childNodes[i]);
+        }
+    },
+    /**
+     * Method: getObj
+     *
+     * return an object by id if it was previously registered
+     *
+     * Parameters:
+     * 
+     * id {String} the original registered id to get the DOM object for
+     *
+     * Returns:
+     *
+     * {Object} returns an object or null if the requested id did not
+     * exist in the original DOM object or if the id was not registered.
+     */
+    getObj: function(id) {
+        return this.uniqueIdRefs[id] || null;
+    }
+};
+
+/**
+ * Class: Jx.Action
+ *
+ * Jx.Action is a utility class that provides a mechanism to separate
+ * the user interface code from the implementation code for a particular
+ * piece of functionality.  A Jx.Action is used primarily as the basis for
+ * clickable UI elements such as Jx.Button and Jx.MenuItem that need to
+ * execute a particular function when the user clicks them.  The Jx.Action
+ * includes a mechanism for controlling the state of the action, allowing
+ * an application to enable or disable an action at any time.  A single
+ * Jx.Action may be used with multiple buttons and menu items, allowing 
+ * the application to easily keep various user interface elements
+ * synchronized without having to explicitly maintain all of them.
+ *
+ * A new instance of Jx.Action is created by passing a function object
+ * to the constructor.  The function object may be a function name or
+ * the result of using the Prototype bind() function.
+ *
+ * For example:
+ *
+ * (code)
+ * //Example 1:
+ * //use a function reference directly
+ * function myFunction() { alert('my function'); }
+ * var action = new Jx.Action(myFunction);
+ *
+ * //Example 2:
+ * //use a function bound to an object through bind()
+ * var myClass = Class.create();
+ * myClass.prototype = { 
+ *   initialize: function() {this.x = 1;}, 
+ *   getX: function() {alert(this.x); }
+ * };
+ *
+ * var myInstance = new myClass();
+ * var action = new Jx.Action(myInstance.getX.bind(myInstance));
+ *
+ * (end)
+ *
+ * To enable or disable a Jx.Action (and consequently update any associated
+ * buttons or menu items), use the setEnabled([true|false]) method.
+ *
+ * For example:
+ *
+ * (code)
+ * //disable an action
+ * action.setEnabled(false);
+ * (end)
+ */
+Jx.Action = Class.create();
+Jx.Action.prototype = {
+    /**
+     * Property: {Array} pcl
+     * an array of property change listeners attached to this action
+     */
+    pcl: null,
+    /**
+     * Property: {Boolean} enabled
+     *
+     * whether the action (and its associated interface object) is
+     * currently enabled or not.  This is controlled through the
+     * setEnabled function
+     */
+    enabled : null,
+    /**
+     * Constructor: Jx.Action
+     * 
+     * construct a new instance of Jx.Action that invokes a function
+     * when activated
+     *
+     * Parameters: 
+     *
+     * f - {Function} the function that this action triggers
+     */
+    initialize: function(f) {
+        this.pcl = [];
+        this.enabled = true;
+        this.actionPerformed = f;
+    },
+    /**
+     * Method: addPropertyChangeListener
+     *
+     * add a property change listener to this action.  When the enabled
+     * state of the action changes, all property change listeners are
+     * notified through their propertyChanged method.
+     *
+     * Parameters: 
+     *
+     * obj - {Object} the object to notify of property changes
+     */
+    addPropertyChangeListener: function(obj){this.addListener(this.pcl, obj);},
+    /**
+     * Method: removePropertyChangeListener
+     *
+     * remove a property change listener from this action.
+     *
+     * Parameters: 
+     *
+     * obj - {Object} the property change listener to remove.
+     */
+    removePropertyChangeListener: function(obj) {
+        this.removeListener(this.pcl, obj);
+    },
+    /**
+     * Method: isEnabled
+     * 
+     * return whether the action is currently enabled or not.
+     *
+     * Return: {Boolean}
+     */
+    isEnabled: function() {return this.enabled;},
+    /**
+     * Method: setEnabled
+     *
+     * set the state of this action.
+     *
+     * Parameters: 
+     *
+     * b - {Boolean} a boolean value to set enabled state of this action to.
+     */
+    setEnabled: function(b){
+        /* prevent unnecessary propogation of propertyChanged */
+        if (this.enabled == b) {
+            return;
+        }
+        this.enabled = b;
+        this.processEvent(this.pcl,'propertyChanged',this);
+    },
+    /**
+     * Method: bindTo
+     *
+     * convenience function to bind an item to this action.  This
+     * adds the item as a property change listener to the action
+     * and adds the action as an ActionListener to the item.
+     *
+     * Parameters: 
+     *
+     * item - {Object} the object to bind the action to.
+     */
+    bindTo : function( item ) {
+        this.addPropertyChangeListener(item);
+        item.addActionListener(this);
+    },
+    /**
+     * Method: unbindFrom
+     *
+     * convenience function to undo a binding between an object and
+     * this action.
+     *
+     * Parameters: 
+     *
+     * item - {Object} the object to unbind from this action.
+     */
+    unbindFrom: function(item) {
+        this.removePropertyChangeListener(item);
+        item.removeActionListener(this);
+    },
+    /**
+     * Method: actionPerformed
+     *
+     * placeholder function to conform to the ActionListener interface.
+     *
+     * Parameters: 
+     *
+     * obj - {Object} the object that performed the action.
+     */
+    actionPerformed : function(obj) { alert('actionPerformed'); }
+};
+Object.extend(Jx.Action.prototype, Jx.Listener.prototype);
+
+/**
+ * Class: Element
+ *
+ * Element is a global object provided by the prototype.js library.  The
+ * functions documented here are extensions to the Element object provided
+ * by Jx to make cross-browser compatibility easier to achieve.
+ */
+Object.extend( Element, {
+    /**
+     * Method: getBoxSizing
+     *
+     * return the box sizing of an element, one of 'content-box' or 
+     *'border-box'.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to get the box sizing of.
+     *
+     * Return: {String} the box sizing of the element.
+     */
+    getBoxSizing : function(elem) {
+      var result = 'content-box';
+      elem = $(elem);
+      if (elem.currentStyle || window.opera) { 
+          var cm = document["compatMode"];
+          if (cm == "BackCompat" || cm == "QuirksMode") { 
+              result = 'border-box'; 
+          } else {
+              result = 'content-box'; 
+        }
+      } else {
+          if (arguments.length == 0) {
+              node = document.documentElement; 
+          }
+          var sizing = Element.getStyle(elem, "-moz-box-sizing");
+          if (!sizing) { 
+              sizing = Element.getStyle(elem, "box-sizing"); 
+          }
+          result = (sizing ? sizing : 'content-box');
+      }
+      return result;
+    },
+    /**
+     * Method: getContentBoxSize
+     *
+     * return the size of the content area of an element.  This is the size of
+     * the element less margins, padding, and borders.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to get the content size of.
+     *
+     * Return: {Object} an object with two properties, width and height, that
+     * are the size of the content area of the measured element.
+     */
+    getContentBoxSize : function(elem) {
+      elem = $(elem);
+      Element.toggleMeasurable(elem);
+      var w = elem.offsetWidth;
+      var h = elem.offsetHeight;
+      var padding = Element.getPaddingSize(elem);
+      var border = Element.getBorderSize(elem);
+      Element.toggleMeasurable(elem);
+      w = w - padding.left - padding.right - border.left - border.right;
+      h = h - padding.bottom - padding.top - border.bottom - border.top;
+      return {width: w, height: h};
+    },
+    /**
+     * Method: getBorderBoxSize
+     *
+     * return the size of the border area of an element.  This is the size of
+     * the element less margins.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to get the border sizing of.
+     *
+     * Return: {Object} an object with two properties, width and height, that
+     * are the size of the border area of the measured element.
+     */
+    getBorderBoxSize: function(elem) {
+      elem = $(elem);
+      Element.toggleMeasurable(elem);
+      var w = elem.offsetWidth;
+      var h = elem.offsetHeight;
+      Element.toggleMeasurable(elem);
+      return {width: w, height: h}; 
+    },
+    /**
+     * Method: setContentBoxSize
+     *
+     * set either or both of the width and height of an element to
+     * the provided size.  This function ensures that the content
+     * area of the element is the requested size and the resulting
+     * size of the element may be larger depending on padding and
+     * borders.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to set the content area of.
+     *
+     * size - {Object} an object with a width and/or height property that is the size to set
+     * the content area of the element to.
+     */
+    setContentBoxSize : function(elem, size) {
+        elem = $(elem);
+        if (Element.getBoxSizing(elem) == 'border-box') {
+            var padding = Element.getPaddingSize(elem);
+            var border = Element.getBorderSize(elem);
+            if (typeof size.width != 'undefined') {
+                var width = (size.width + padding.left + padding.right + border.left + border.right);
+                if (width < 0) {
+                    width = 0;
+                }
+                elem.style.width = width + 'px';
+            }
+            if (typeof size.height != 'undefined') {
+                var height = (size.height + padding.top + padding.bottom + border.top + border.bottom);
+                if (height < 0) {
+                    height = 0;
+                }
+                elem.style.height = height + 'px';
+            }
+        } else {
+            if (typeof size.width != 'undefined') {
+                elem.style.width = size.width + 'px';
+            }
+            if (typeof size.height != 'undefined') {
+                elem.style.height = size.height + 'px';
+            }
+        }
+    },
+    /**
+     * Method: setBorderBoxSize
+     *
+     * set either or both of the width and height of an element to
+     * the provided size.  This function ensures that the border
+     * size of the element is the requested size and the resulting
+     * content areaof the element may be larger depending on padding and
+     * borders.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to set the border size of.
+     *
+     * size - {Object} an object with a width and/or height property that is the size to set
+     * the content area of the element to.
+     */
+    setBorderBoxSize : function(elem, size) {
+      elem = $(elem);
+      if (Element.getBoxSizing(elem) == 'content-box') {
+        var padding = Element.getPaddingSize(elem);
+        var border = Element.getBorderSize(elem);
+        var margin = Element.getMarginSize(elem);
+        if (typeof size.width != 'undefined') {
+          var width = (size.width - padding.left - padding.right - border.left - border.right - margin.left - margin.right);
+          if (width < 0) {
+            width = 0;
+          }
+          elem.style.width = width + 'px';
+        }
+        if (typeof size.height != 'undefined') {
+          var height = (size.height - padding.top - padding.bottom - border.top - border.bottom - margin.top - margin.bottom);
+          if (height < 0) {
+            height = 0;
+          }
+          elem.style.height = height + 'px';
+        }
+      } else {
+        if (typeof size.width != 'undefined' && size.width >= 0) {
+          elem.style.width = size.width + 'px';
+        }
+        if (typeof size.height != 'undefined' && size.height >= 0) {
+          elem.style.height = size.height + 'px';
+        }
+      }
+    },
+    /**
+     * Method: getPaddingSize
+     *
+     * returns the padding for each edge of an element
+     *
+     * Parameters: 
+     *
+     * elem - {Object} The element to get the padding for.
+     *
+     * Return: {Object} an object with properties left, top, right and bottom
+     * that contain the associated padding values.
+     */
+    getPaddingSize : function (elem) {
+      elem = $(elem);
+      Element.toggleMeasurable(elem);
+      var l = Element.getNumber(Element.getStyle(elem, 'padding-left'));
+      var t = Element.getNumber(Element.getStyle(elem, 'padding-top'));
+      var r = Element.getNumber(Element.getStyle(elem, 'padding-right'));
+      var b = Element.getNumber(Element.getStyle(elem, 'padding-bottom'));
+      Element.toggleMeasurable(elem);
+      return {left:l, top:t, right: r, bottom: b};
+    },
+    /**
+     * Method: getBorderSize
+     *
+     * returns the border size for each edge of an element
+     *
+     * Parameters: 
+     *
+     * elem - {Object} The element to get the borders for.
+     *
+     * Return: {Object} an object with properties left, top, right and bottom
+     * that contain the associated border values.
+     */
+    getBorderSize : function(elem) {
+      elem = $(elem);
+      Element.toggleMeasurable(elem);
+      var l = Element.getNumber(Element.getStyle(elem, 'border-left-width'));
+      var t = Element.getNumber(Element.getStyle(elem, 'border-top-width'));
+      var r = Element.getNumber(Element.getStyle(elem, 'border-right-width'));
+      var b = Element.getNumber(Element.getStyle(elem, 'border-bottom-width'));
+      Element.toggleMeasurable(elem);
+      return {left:l, top:t, right: r, bottom: b};
+    },
+    /**
+     * Method: getMarginSize
+     *
+     * returns the margin size for each edge of an element
+     *
+     * Parameters: 
+     *
+     * elem - {Object} The element to get the margins for.
+     *
+     * Return: {Object} an object with properties left, top, right and bottom
+     * that contain the associated margin values.
+     */
+    getMarginSize : function(elem) {
+      elem = $(elem);
+      Element.toggleMeasurable(elem);
+      var l = Element.getNumber(Element.getStyle(elem, 'margin-left'));
+      var t = Element.getNumber(Element.getStyle(elem, 'margin-top'));
+      var r = Element.getNumber(Element.getStyle(elem, 'margin-right'));
+      var b = Element.getNumber(Element.getStyle(elem, 'margin-bottom'));
+      Element.toggleMeasurable(elem);
+      return {left:l, top:t, right: r, bottom: b};
+    },
+    /**
+     * Method: getNumber
+     *
+     * safely parse a number and return its integer value.  A NaN value 
+     * returns 0.  CSS size values are also parsed correctly.
+     *
+     * Parameters: 
+     *
+     * n - {Mixed} the string or object to parse.
+     *
+     * Return: {Integer} the integer value that the parameter represents
+     */
+    getNumber: function(n) {
+      var result = n==null||isNaN(parseInt(n))?0:parseInt(n);
+      return result;
+    },
+    /**
+     * Method: getPageDimensions
+     *
+     * return the dimensions of the browser client area.
+     *
+     * Return: {Object} an object containing a width and height property 
+     * that represent the width and height of the browser client area.
+     */
+    getPageDimensions: function() {
+        return {width: Element.getInsideWindowWidth(), height: Element.getInsideWindowHeight()};
+    },
+    /**
+     * Method: getInsideWindowWidth
+     *
+     * returns the width of the browser client area
+     *
+     * Return: {Integer} the width of the browser client area
+     */
+    getInsideWindowWidth: function() {
+        if (window.innerWidth) {
+            return window.innerWidth;
+        } else if (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) {
+            // measure the html element's clientWidth
+            return document.body.parentElement.clientWidth;
+        } else if (document.body && document.body.clientWidth) {
+            return document.body.clientWidth;
+        }
+        return 0; 
+    },
+    /**
+     * Method: getInsideWindowHeight
+     *
+     * returns the height of the browser client area
+     *
+     * Return: {Integer} the height of the browser client area
+     */
+    getInsideWindowHeight: function() {
+        if (window.innerHeight) {
+            return window.innerHeight;
+        } else if (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) {
+            // measure the html element's clientHeight
+            return document.body.parentElement.clientHeight;
+        } else if (document.body && document.body.clientHeight) {
+            return document.body.clientHeight;
+        }
+        return 0; 
+    },
+    /**
+     * Method: toggleMeasurable
+     *
+     * toggles an element's display style property so it can be
+     * measured.  If the element has display: none, it is
+     * changed to display: block and made temporarily visible
+     * so that it can be measured.  Calling this function
+     * a second time with the same element will revert the
+     * changes.  This allows an element to be measured in
+     * various ways.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to measure.
+     */
+    toggleMeasurable: function(elem) {
+        if (Element.getStyle(elem, 'display') == 'none') {
+            elem.old = {};
+            elem.old.display = elem.style.display;
+            elem.old.visibility = elem.style.visibility;
+            elem.old.position = elem.style.position;
+            elem.style.position = 'absolute';
+            elem.style.visibility = 'hidden';
+            elem.style.display = 'block';
+        } else {
+            if (elem.old) {
+                elem.style.display = elem.old.display;
+                elem.style.visibility = elem.old.visibility;
+                elem.style.position = elem.old.position;
+                elem.old = null;
+            }
+        }
+    }
+} );
+
+/**
+ * Class: Jx.ContentLoader
+ * 
+ * ContentLoader is a mix-in class that provides a consistent
+ * mechanism for other Jx controls to load content in one of
+ * four different ways:
+ *
+ * o using an existing element, by id
+ *
+ * o using an existing element, by object reference
+ *
+ * o using an HTML string
+ *
+ * o using a URL to get the content remotely
+ */
+Jx.ContentLoader = Class.create();
+Jx.ContentLoader.prototype = {
+    /**
+     * Property: bContentLoaded
+     *
+     * tracks the load state of the content, specifically useful
+     * in the case of remote content.
+     */ 
+    bContentLoaded: false,
+    /**
+     * Method: contentLoaded
+     * 
+     * callback function that handles remote content
+     *
+     * Parameters: 
+     *
+     * element - {Object} the element to put the content into
+     *
+     * options - {Object} the options that were passed to loadContent originally, only
+     * used to get the optional onContentLoaded callback function.
+     *
+     * r - {XmlHttpRequest} the XmlHttpRequest object that has the content.
+     */
+    contentLoaded: function(element, options, r) { 
+        element.innerHTML = r.responseText;
+        this.bContentLoaded = true;
+        if (options.onContentLoaded) {
+            options.onContentLoaded();
+        }
+    },
+    /**
+     * Method: contentLoadFailed
+     * 
+     * callback function that handles failure to load remote content
+     *
+     * Parameters: 
+     *
+     * options - {Object} the options that were passed to loadContent originally, only
+     * used to get the optional onContentLoadedFailed callback function.
+     *
+     * r - {XmlHttpRequest} the XmlHttpRequest object that has the failure code
+     */
+    contentLoadFailed: function(options, r) {
+        this.bContentLoaded = false;
+        if (options.onContentLoadFailed) {
+            options.onContentLoadFailed();
+        }
+    },
+    /**
+     * Method: loadContent
+     *
+     * triggers loading of content based on parameters passed in the
+     * options parameter.  The options parameter can have the following
+     * attributes:
+     *
+     * Parameters: 
+     * element - {Object} the element to insert the content into
+     * options - {Object} an object containing the attributes indicating what 
+     * content to load.
+     *
+     * Options:
+     * content - {HTMLElement} an HTML element that becomes the content
+     * contentID - {String} the id of an element to use as the content
+     * contentURL - {String} URL to get the content remotely
+     * contentHTML - {String} some HTML to use as the innerHTML of the content
+     *      area.
+     * onContentLoaded - {Function} a function to call when the content is 
+     *      loaded.
+     * onContentLoadFailed - a function object that is called if the content
+     *      fails to load, primarily useful when using the contentURL method of
+     *      loading content.
+     */     
+    loadContent: function(element, options) {
+        options = options || {};
+        element = $(element);
+        if (options.content) {
+            element.appendChild(options.content);
+            this.bContentLoaded = true;
+        } else if (options.contentID) {
+            var c = $(options.contentID);
+            if (c) {
+                element.appendChild(c);
+                this.bContentLoaded = true;                
+            }
+        } else if (options.contentURL) {
+            this.bContentLoaded = false;
+            var ts = '';//'ts=' + (new Date()).getTime();
+            var a = new Ajax.Request( options.contentURL, 
+                Object.extend({method:'get',
+                               onSuccess:this.contentLoaded.bind(this, element, options), 
+                               onFailure: this.contentLoadFailed.bind(this, options),
+                               requestHeaders: ['If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT'],
+                               parameters: ts}));
+        } else if (options.contentHTML) {
+            element.innerHTML = options.contentHTML;
+            this.bContentLoaded = true;
+        } else {
+            this.bContentLoaded = true;
+        }
+        if (this.bContentLoaded && options.onContentLoaded) {
+            options.onContentLoaded();
+        }
+    }
+};/**
+ * $Id: jxbutton.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Button
+ *
+ * Purpose: 
+ * Implementation of a generic button widget and several
+ * useful subclasses.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+/**
+ * Class: Jx.Button
+ *
+ * Jx.Button creates a clickable element in the application that is hooked
+ * to an instance of Jx.Action.  When the button is clicked, it activates
+ * its associated Jx.Action instance.  When the Jx.Action associated with
+ * the button is enabled or disabled, the Jx.Button updates its visual
+ * appearance to reflect the current state of the Jx.Action.
+ *
+ * Visually, a Jx.Button consists of an <A> tag that may contain either
+ * an image, a label, or both (the label appears to the right of the button
+ * if both are present).  The default styles for Jx.Button expect the
+ * image to be 16 x 16 pixels, with a padding of 4px and a border of 1px
+ * which results in an element that is 26 pixels high.  The width of the
+ * button automatically accomodates the image and label as required.
+ *
+ * When you construct a new instance of Jx.Button, the button does not
+ * automatically get inserted into the application.  Typically a button
+ * is used as part of building another capability such as a Jx.Toolbar.
+ * However, if you want to manually insert the button into your
+ * application, you may use the domObj property of the Jx.Button instance.
+ * In this case, you will use one of the DOM manipulation functions such
+ * as appendChild, and pass button.domObj.  For example:
+ *
+ * (code)
+ * var button = new Jx.Button(myAction, options);
+ * var li = $('myListItem'); //obtain a reference to a DOM element
+ * li.appendChild(button.domObj);
+ * (end)
+ *
+ * To use a Jx.Button in an application, you must first create an instance
+ * of Jx.Action and then pass it as the first parameter to the Jx.Button
+ * constructor.  The second argument to a Jx.Button constructor is an options 
+ * object allows configuring the button.
+ *
+ * (code)
+ * Example:
+ * function myFunc() { alert('you clicked me'); }
+ * var action = new Jx.Action(myFunc);
+ * var options = {
+ *     imgPath: 'images/mybutton.png',
+ *     tooltip: 'click me!',
+ *     label: 'click me'
+ * }
+ * var button = new Jx.Button(action, options);
+ * (end)
+ */
+ 
+Jx.addStyleSheet('button/button.css');
+
+Jx.Button = Class.create();
+Object.extend(Jx.Button.prototype, Jx.Listener.prototype);
+Object.extend(Jx.Button.prototype, {
+    /**
+     * Property: {Array} al
+     * an array of action listeners that are attached to the button.
+     */
+    al: null,
+    /**
+     * Property: {Object} domObj
+     * the HTML element that is inserted into the DOM for this button
+     */
+    domObj: null,
+    /**
+     * Property: {Boolean} enabled
+     * whether the button is enabled or not.  This is controlled by
+     * the Action object that the button is associated with.
+     */
+    enabled:null,
+    /**
+     * Constructor: Jx.Button
+     * create a new button.
+     *
+     * Parameters:
+     * action - {Object} the action to trigger for this button.
+     * options - {Object} an object containing optional properties for this
+     * button as below.
+     *
+     * Options:
+     * image - optional.  A string value that is the url to load the image to
+     *      display in this button.  The default styles size this image to 16 x 16.
+     *      If not provided, then the button will have no icon.
+     * tooltip - optional.  A string value to use as the alt/title attribute of
+     *      the <A> tag that wraps the button, resulting in a tooltip that appears 
+     *      when the user hovers the mouse over a button in most browsers.  If 
+     *      not provided, the button will have no tooltip.
+     * label - optional.  A string value that is used as a label on the button.
+     * disabledClass - optional.  A string value that is the name of a CSS class
+     *      to put on the <A> tag if the button is in a disabled state. If not 
+     *      provided, the default class jxDisabled is used. You may provide 
+     *      your own class or override jxDisabled.
+     * imgClass - optional.  A string value that is the name of a CSS class to
+     *      put on the <IMG> element.  The default value is jxButtonIcon.
+     */
+    initialize : function( action, options ) {
+        options = options || {};
+        this.al = [];
+        this.action = action; //TODO move action into options
+        
+        var imgPath = (options.imgPath || options.image) || '';
+        var tooltip = options.tooltip || '';
+        var label = options.label || '';
+        this.disabledClass = options.disabledClass || 'jxDisabled';
+        
+        this.domA = document.createElement('a');
+        this.domA.className = 'jxButton';
+        this.domA.href='javascript:void(0)'; //make hover effects work in IE
+        this.domA.onclick = this.onclick.bindAsEventListener(this);
+        this.domA.title = tooltip;
+        this.domA.alt = tooltip;
+        
+        var span = document.createElement('span');
+        span.className = 'jxButtonSpan';
+        this.domA.appendChild(span);
+        
+        
+        // if (imgPath != '') {
+        //             this.domImg = document.createElement('span');
+        //             this.domImg.className = 'jxButtonIcon';
+        //             if (options.imageClass && options.imageClass != '') {
+        //                 Element.addClassName(this.domImg, options.imageClass);
+        //             }
+        //             this.domImg.style.backgroundImage = "url("+imgPath+")";
+        //             this.domImg.innerHTML = '&nbsp;&nbsp;';
+        //             span.appendChild(this.domImg);
+        //         }
+        
+        this.domLabel = document.createElement('span');
+        this.domLabel.className = 'jxButtonContent';
+        //this.domLabel.className = label != '' ? 'jxButtonLabel' : ''; //jxButtonLabel jxButtonEmptyLabel';
+        this.domLabel.innerHTML = label != '' ? label : '&nbsp;';
+        span.appendChild(this.domLabel);
+
+        if (label != '') {
+            Element.addClassName(this.domLabel, 'jxButtonLabel');
+        }
+        
+        if (imgPath != '') {
+            Element.addClassName(this.domLabel, 'jxButtonIcon');
+            this.domLabel.style.backgroundImage = "url("+imgPath+")";
+        }
+        
+        /* if this is an action button, then hook to the action */
+        if (this.action) {
+            this.action.bindTo(this);
+            this.propertyChanged(this.action);            
+        }
+        
+        this.domObj = document.createElement('div');
+        this.domObj.className = 'jxButtonContainer';
+        this.domObj.appendChild(this.domA);
+        
+        if (options.halign && options.halign == 'left') {
+                Element.addClassName(this.domObj, 'jxButtonContentLeft');                
+        }
+        if (options.valign && options.valign == 'top') {
+            Element.addClassName(this.domObj, 'jxButtonContentTop');
+        }
+    },
+    /**
+     * Method: onclick
+     * triggered when the user clicks the button, processes the
+     * actionPerformed event
+     */
+    onclick : function() {
+        if (this.enabled) {
+            this.processEvent(this.al, 'actionPerformed', this);
+        }
+        return false;
+    },
+    /**
+     * Method: addActionListener
+     * add an action listener to the button
+     *
+     * Parameters: 
+     * obj - {Object} the object to add as an action listener
+     */
+    addActionListener: function(obj) { 
+        this.addListener(this.al,obj); 
+    },
+    /**
+     * Method: removeActionListener
+     * remove an action listener from the button
+     *
+     * Parameters: 
+     * obj - {Object} the object to remove.
+     */
+    removeActionListener : function(obj) { 
+        this.removeListener(this.al, obj);
+    },
+    /**
+     * Method: propertyChanged
+     * implements the PropertyChangeListener interface
+     * for handling the enabled state changing on the action
+     * associated with this button
+     *
+     * Parameters:
+     * obj - {Object} the action that is changing state
+     */
+    propertyChanged: function(obj) {
+        this.enabled = obj.isEnabled();
+        if (this.enabled) {
+            Element.removeClassName( this.domObj, this.disabledClass );
+        } else {
+            Element.addClassName( this.domObj, this.disabledClass );
+        }
+    },
+    /**
+     * Method: setImage
+     * set the image of this button to a new image URL
+     *
+     * Parameters:
+     * path - {String} the new url to use as the image for this button
+     */
+    setImage: function(path) {
+        if (this.domImg) {
+            this.domImg.src = path;
+        }
+    },
+    /**
+     * Method: setLabel
+     * 
+     * sets the text of the button.  Only works if a label was supplied
+     * when the button was constructed
+     *
+     * Parametera: 
+     *
+     * label - {String} the new label for the button
+     */
+    setLabel: function(label) {
+        if (this.domLabel) {
+            this.domLabel.innerHTML = label;
+        }
+    },
+    /**
+     * Method: setTooltip
+     * sets the tooltip displayed by the button
+     *
+     * Parameters: 
+     * tooltip - {String} the new tooltip
+     */
+    setTooltip: function(tooltip) {
+        if (this.domImg) {
+            this.domImg.title = tooltip;
+            this.domImg.alt = tooltip;
+        }
+    }
+} );
+
+/**
+ * Class: Jx.Button.Flyout
+ *
+ * Flyout buttons expose a panel when the user clicks the button.  The
+ * panel can have arbitrary content.
+ *
+ * The button itself does not trigger an external action.  You must provide
+ * any necessary code to hook up elements in the panel to your application.
+ */
+Jx.Button.Flyout = Class.create();
+Object.extend(Jx.Button.Flyout.prototype, Jx.Button.prototype);
+Object.extend(Jx.Button.Flyout.prototype, Jx.ContentLoader.prototype);
+Object.extend(Jx.Button.Flyout.prototype, {
+    /**
+     * Property: content
+     * {HTMLElement} a reference to the DOM node that contains the flyout 
+     * content
+     */
+    content: null,
+    /**
+     * Constructor: Jx.Button.Flyout
+     * construct a new instance of a flyout button.  The single options
+     * argument takes the same parameters as <Jx.Button.initialize> plus
+     * content loading options as per <Jx.ContentLoader>.
+     *
+     * Parameters: 
+     * options - {Object} an options object used to initialize the button.
+     * See <Jx.Button::Jx.Button>
+     */
+    initialize: function(options) {
+        options = options || {};
+        var a = new Jx.Action(this.show.bind(this));
+        Jx.Button.prototype.initialize.apply(this, [a, options]);
+        Element.addClassName(this.domA, 'jxButtonFlyout');
+        
+        /* iframe shim to prevent scrollbars and 
+           inputs from showing through the menu */
+        this.iframe = document.createElement('iframe');
+        this.iframe.className = 'jxMenuShim';
+        this.iframe.scrolling = 'no';
+        this.iframe.frameborder = 0;
+        
+        this.content = document.createElement('div');
+        Element.addClassName(this.content, 'jxFlyout');
+        this.loadContent(this.content, options);
+        this.domObj.appendChild(this.content);
+        this.content.style.display = 'none';
+        
+        this.keypressWatcher = this.keypressHandler.bindAsEventListener(this);
+        this.hideWatcher = this.clickHandler.bindAsEventListener(this);
+    },
+    
+    /**
+     * Method: show
+     * Show the flyout content
+     */
+    show: function() {
+        if (!window.opera && !this.iframe.parentNode) {
+            this.content.appendChild(this.iframe);
+        }
+        this.content.style.display = 'block';
+        Event.observe(window, 'keypress', this.keypressWatcher);
+        Event.observe(document, 'click', this.hideWatcher);
+    },
+    
+    /**
+     * Method: hide
+     * Hide the flyout content
+     */
+    hide: function() {
+        this.content.style.display = 'none';
+        Event.stopObserving(window, 'keypress', this.keypressWatcher);    
+        Event.stopObserving(document, 'click', this.hideWatcher);
+    },
+    /**
+     * Method: clickHandler
+     * hide flyout if the user clicks outside of the flyout 
+     */
+    clickHandler: function(e) {
+        var elm = Event.element(e);
+        if (!Element.descendantOf(elm, this.domObj.parentNode)) {
+            this.hide();
+        }
+    },
+    /**
+     * Method: keypressHandler
+     * hide flyout if the user presses the ESC key 
+     */
+    keypressHandler: function(e) {
+        var charCode=(e.charCode)?e.charCode:e.keyCode;
+        if (charCode == Event.KEY_ESC) {
+            this.hide();
+        }
+    }
+});
+
+/**
+ * Class: Jx.Button.Multi
+ * 
+ * Multi buttons are used to contain multiple buttons in a drop down list
+ * where only one button is actually visible and clickable in the interface.
+ * 
+ * When the user clicks the active button, it performs its normal action.
+ * The user may also click a drop-down arrow to the right of the button and
+ * access the full list of buttons.  Clicking a button in the list causes
+ * that button to replace the active button in the toolbar and performs
+ * the button's regular action.
+ *
+ * Other buttons can be added to the Multi button using the <add> function.
+ */
+Jx.Button.Multi = Class.create();
+Jx.Button.Multi.prototype = {
+    /**
+     * Property: {<Jx.Button>} activeButton
+     * the currently selected button
+     */
+    activeButton: null,
+    /**
+     * Property: {Array} buttons
+     * an array of all available buttons
+     */
+    buttons: null,
+    /**
+     * Constructor: Jx.Button.Multi
+     * construct a new instance of Jx.Button.Multi.
+     */
+    initialize: function() {
+        this.buttons = [];
+        this.content = document.createElement('div');
+        this.tb = new Jx.Toolbar(this.content, 'right');
+        this.flyout = new Jx.Button.Flyout({content: this.content, label: '&nbsp;'});
+        Element.addClassName(this.flyout.domObj.firstChild, 'jxButtonMulti');
+        
+        this.domObj = document.createElement('div');
+        //this.domObj.className = 'jxButtonMulti';
+        this.buttonContainer = document.createElement('div');
+        this.buttonContainer.className = 'jxButtonMultiContainer';
+        this.domObj.appendChild(this.buttonContainer);
+        this.domObj.appendChild(this.flyout.domObj);
+    },
+    /**
+     * Method: add
+     * adds one or more buttons to the Multi button.  The first button
+     * added becomes the active button initialize.  This function 
+     * takes a variable number of arguments, each of which is expected
+     * to be an instance of <Jx.Button>.
+     *
+     * Parameters: 
+     * button - {<Jx.Button>} a <Jx.Button> instance, may be repeated in the parameter list
+     */
+    add: function() {
+        for (var i=0; i<arguments.length; i++) {
+            var theButton = arguments[i];
+            var action = new Jx.Action(this.setButton.bind(this, theButton));
+            var button = new Jx.Button(action, {});
+            var click = button.domA.onclick;
+            button.domObj = theButton.domObj.cloneNode(true);
+            button.domObj.onclick = click;
+            this.tb.add(button);
+            if (!this.activeButton) {
+                this.buttonContainer.appendChild(theButton.domObj);
+                this.activeButton = theButton;
+            }
+        }
+    },
+    /**
+     * Method: setActiveButton
+     * update the menu item to be the requested button.
+     *
+     * Parameters: 
+     * button - {<Jx.Button>} a <Jx.Button> instance that was added to this multi button.
+     */
+    setActiveButton: function(button) {
+        while(this.buttonContainer.childNodes.length > 0) {
+            this.buttonContainer.removeChild(this.buttonContainer.firstChild);
+        }
+        this.buttonContainer.appendChild(button.domObj);
+    },
+    /**
+     * Method: setButton
+     * update the active button in the menu item, trigger the button's action
+     * and hide the flyout that contains the buttons.
+     *
+     * Parameters: 
+     * button - {<Jx.Button>} The button to set as the active button
+     */
+    setButton: function(button) {
+        this.setActiveButton(button);
+        button.onclick();
+        this.flyout.hide();
+    }
+};
+
+/**
+ * Class: Jx.Button.Picker
+ * 
+ * A Picker button allows the user to choose an item from a list of items.
+ * The items can be any HTML element.  The chosen item is placed into the 
+ * menu item.
+ */
+Jx.Button.Picker = Class.create();
+Object.extend(Jx.Button.Picker.prototype, Jx.Button.Flyout.prototype);
+Object.extend(Jx.Button.Picker.prototype, {
+    /**
+     * Property: {HTMLElement} ul
+     * the UL element that contains the items to pick from
+     */
+    ul: null,
+    /**
+     * Property {HTMLElement} selectedItem
+     * the currently selected item
+     */
+    selectedItem: null,
+    /**
+     * Constructor: Jx.Button.Picker
+     * construct a new instance of <Jx.Button.Picker>
+     */
+    initialize: function() {
+        Jx.Button.Flyout.prototype.initialize.apply(this, arguments);
+        this.ul = document.createElement('ul');
+        this.content.appendChild(this.ul);
+        Element.removeClassName(this.domLabel, 'jxButtonEmptyLabel');
+    },
+    /**
+     * Method: add
+     * adds one or more items to the picker, passed as separate arguments.
+     *
+     * Parameters: 
+     * item - {Object} can be present one or more times in the argument list.  The item
+     * to be added can be a Jx object with a domObj property, a string,
+     * or an HTML element reference.
+     */
+    add: function() {
+        for (var i=0; i<arguments.length; i++) {
+            var thing = arguments[i];
+            if (thing.domObj) {
+                thing = thing.domObj;
+            }
+            var li = document.createElement('li');
+            var a = document.createElement('a');
+            
+            li.appendChild(a);
+            if (typeof(thing) == 'string') {
+                a.innerHTML = thing;
+            } else {
+                a.appendChild(thing);
+            }
+            this.ul.appendChild(li);
+            
+            if (!this.selectedItem) {
+                this.updateButton(a);
+            }
+        }
+    },
+    /**
+     * Method: clickHandler
+     * handle the user selecting an item in the list
+     *
+     * Parameters: 
+     * e - {Event} the event object associated with the click event
+     */
+    clickHandler: function(e) {
+        var elm = Event.element(e);
+        if (!Element.descendantOf(elm, this.domObj.parentNode)) {
+            this.hide();
+            return;
+        }
+        var a = Event.findElement(e, 'A');
+        if (a && Element.descendantOf(a, this.ul)) {
+            this.updateButton(a);
+            this.hide();
+        }
+    },
+    /**
+     * Method: updateButton
+     * updates the button to contain the picked item
+     *
+     * Parameters: 
+     * a - {HTMLElement} the A tag that the user clicked on
+     */
+    updateButton: function(a) {
+        while(this.domLabel.childNodes.length > 0) {
+            this.domLabel.removeChild(this.domLabel.firstChild);
+        }
+        this.domLabel.appendChild(a.firstChild.cloneNode(true));
+        this.selectedItem = a.firstChild;
+    }
+    
+});/**
+ * $Id: jxcolor.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Color
+ *
+ * Purpose: 
+ * Implementation of a color selection panel.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+ 
+Jx.addStyleSheet('color/color.css');
+
+/**
+ * Class: Jx.ColorPanel
+ *
+ * A Jx.ColorPanel presents a user interface for selecting colors.  Currently,
+ * the user can either enter a HEX colour value or select from a palette of
+ * web-safe colours.  The user can also enter an opacity value.
+ *
+ * A Jx.ColorPanel can be embedded anywhere in a web page by appending its
+ * <Jx.ColorPanel.domObj> property to an HTML element.  However, a
+ * a Jx.Button subclass  is provided ( <Jx.Button.Color> ) that embeds a
+ * colour panel inside a button for easy use in toolbars.
+ *
+ * Colour changes are propogated via a colorChanged listener pattern.  To
+ * be notified of changes in a Jx.ColorPanel, register a color change
+ * listener that implements a colorChanged method.  For instance:
+ *
+ * (code)
+ * var colorChangeListener = {
+ * colorChanged: function(colorPanel) {
+ *     alert('the color changed to: ' + colorPanel.color);
+ *   }
+ * }
+ *
+ * var colorPanel = new Jx.ColorPanel();
+ * colorPanel.addColorChangeListener(colorChangeListener);
+ *
+ * document.getElementsByTagName('BODY')[0].appendChild(colorPanel.domObj);
+ * (end)
+ */
+Jx.ColorPanel = Class.create();
+
+Jx.ColorPanel.prototype = {
+    /**
+     * Property: {HTMLElement} domObj
+     * the HTML element representing the color panel
+     */
+    domObj: null,
+    /**
+     * Property {String} color
+     * the currently selected colour, in hex format
+     */
+    color: null,
+    /**
+     * Property: {Float} alpha
+     * the current alpha value, between 0 (transparent) and 1 (opaque)
+     */
+    alpha: null,
+    /**
+     * Property: {Array} ccl
+     * color change property listeners
+     */
+    ccl: null,
+    /**
+     * Property: {Array} hexColors
+     * an array of valid hex values that are used to build a web-safe
+     * palette
+     */
+    hexColors: ['00', '33', '66', '99', 'CC', 'FF'],
+    /**
+     * Constructor: Jx.ColorPanel
+     * initialize a new instance of Jx.ColorPanel
+     *
+     * Parameters: 
+     * options - {Object} an object containing a variable list of optional initialization
+     * parameters.
+     *
+     * Options:
+     * color - a colour to initialize the panel with, defaults to #000000
+     *         (black) if not specified.
+     * alpha - an alpha value to initialize the panel with, defaults to 1
+     *         (opaque) if not specified.
+     */
+    initialize: function(options) {
+        
+        options = options || {};
+        this.keypressWatcher = this.keypressHandler.bind(this);
+        
+        this.ccl = [];
+        
+        this.color = options.color || '#000000';
+        this.alpha = options.alpha || 1;
+        
+        this.domObj = document.createElement('div');
+        this.domObj.className = 'jxColorPanel';
+        
+        var top = document.createElement('div');
+        top.className = 'jxColorBar';
+        
+        var d = document.createElement('div');
+        d.className = 'jxColorPreview';
+        
+        // var img = document.createElement('img');
+        // img.src = Jx.baseURL + '/color/grid.png';        
+        // d.appendChild(img);
+        
+        this.selectedSwatch = document.createElement('div');
+        d.appendChild(this.selectedSwatch);
+        
+        top.appendChild(d);
+        
+        this.colorInputLabel = document.createElement('label');
+        this.colorInputLabel.className = 'jxColorLabel';
+        this.colorInputLabel.innerHTML = '#';
+        top.appendChild(this.colorInputLabel);
+        
+        this.colorInput = document.createElement('input');
+        this.colorInput.className = 'jxHexInput';
+        this.colorInput.type = 'text';
+        this.colorInput.maxLength = 6;
+        Event.observe(this.colorInput, 'keyup', this.colorChanged.bind(this));
+        Event.observe(this.colorInput, 'blur', this.colorChanged.bind(this));
+        Event.observe(this.colorInput, 'change', this.colorChanged.bind(this));
+        top.appendChild(this.colorInput);
+        
+        this.alphaLabel = document.createElement('label');
+        this.alphaLabel.className = 'jxAlphaLabel';
+        this.alphaLabel.innerHTML = 'alpha (%)';
+        top.appendChild(this.alphaLabel);
+        
+        this.alphaInput = document.createElement('input');
+        this.alphaInput.className = 'jxAlphaInput';
+        this.alphaInput.type = 'text';
+        this.alphaInput.maxLength = 3;
+        Event.observe(this.alphaInput, 'keyup', this.alphaChanged.bind(this));
+        top.appendChild(this.alphaInput);
+        
+        this.domObj.appendChild(top);
+        
+        var a = document.createElement('a');
+        a.href="javascript:void(0)";
+        a.className = 'jxColorClose';
+        a.alt = 'Close';
+        a.title = 'Close';
+        Event.observe(a, 'click', this.hide.bind(this));
+        
+        img = document.createElement('img');
+        img.className = 'png24';
+        img.src = Jx.baseURL + 'images/close.png';
+        a.appendChild(img);
+        
+        this.domObj.appendChild(a);
+        
+        d = document.createElement('div');
+        d.className = 'jxClearer';
+        this.domObj.appendChild(d);
+        
+        var swatchClick = this.swatchClick.bindAsEventListener(this);
+        var swatchOver = this.swatchOver.bindAsEventListener(this);
+        
+        var table = document.createElement('table');
+        table.className = 'jxColorGrid';
+        var tbody = document.createElement('tbody');
+        table.appendChild(tbody);
+        for (var i=0; i<12; i++) {
+            var tr = document.createElement('tr');
+            for (var j=-3; j<18; j++) {
+                var bSkip = false;
+                var r, g, b;
+                /* hacky approach to building first three columns
+                 * because I couldn't find a good way to do it
+                 * programmatically
+                 */
+                
+                if (j < 0) {
+                    if (j == -3 || j == -1) {
+                        r = g = b = 0;
+                        bSkip = true;
+                    } else {
+                        if (i<6) {
+                            r = g = b = i;
+                        } else {
+                            if (i == 6) {
+                                r = 5; g = 0; b = 0;
+                            } else if (i == 7) {
+                                r = 0; g = 5; b = 0;
+                            } else if (i == 8) {
+                                r = 0; g = 0; b = 5;
+                            } else if (i == 9) {
+                                r = 5; g = 5; b = 0;
+                            } else if (i == 10) {
+                                r = 0; g = 5; b = 5;
+                            } else if (i == 11) {
+                                r = 5; g = 0; b = 5;
+                            }
+                        }
+                    }
+                } else {
+                    /* remainder of the columns are built
+                     * based on the current row/column
+                     */
+                    r = parseInt(i/6)*3 + parseInt(j/6);
+                    g = j%6;
+                    b = i%6;
+                }
+                var bgColor = '#'+this.hexColors[r]+this.hexColors[g]+this.hexColors[b];
+                
+                var td = document.createElement('td');
+                if (!bSkip) {
+                    td.style.backgroundColor = bgColor;
+
+                    var a = document.createElement('a');
+                    if ((r > 2 && g > 2) || (r > 2 && b > 2) || (g > 2 && b > 2)) {
+                        a.className = 'colorSwatch borderBlack';
+                    } else {
+                        a.className = 'colorSwatch borderWhite';
+                    }
+                    a.href = '#';
+                    a.title = bgColor;
+                    a.alt = bgColor;
+                    a.swatchColor = bgColor;
+                    
+                    a.onmouseover = swatchOver;
+                    a.onclick = swatchClick;
+
+                    td.appendChild(a);
+                } else {
+                    var span = document.createElement('span');
+                    td.className = 'emptyCell';
+                    td.appendChild(span);
+                }
+                tr.appendChild(td);
+            }
+            tbody.appendChild(tr);
+        }
+
+        this.domObj.appendChild(table);
+        
+        var d = document.createElement('div');
+        d.className = 'jxColorPreview';
+        this.previewSwatch = document.createElement('div');
+        d.appendChild(this.previewSwatch);
+        this.previewSwatch.style.backgroundColor = this.color;
+        this.domObj.appendChild(d);
+        
+        this.previewLabel = document.createElement('label');
+        this.previewLabel.className = 'jxColorLabel';
+        this.previewLabel.innerHTML = this.color;
+        this.domObj.appendChild(this.previewLabel);
+        
+        d = document.createElement('div');
+        d.className = 'jxClearer';
+        this.domObj.appendChild(d);
+        
+        this.updateSelected();
+    },
+    
+    /**
+     * Method: swatchOver
+     * handle the mouse moving over a colour swatch by updating the preview
+     *
+     * Parameters: 
+     * e - {Event} the mousemove event object
+     */
+    swatchOver: function(e) {
+        var a = Event.element(e);
+        
+        this.previewSwatch.style.backgroundColor = a.swatchColor;
+        this.previewLabel.innerHTML = a.swatchColor;
+    },
+    
+    /**
+     * Method: swatchClick
+     * handle mouse click on a swatch by updating the color and hiding the
+     * panel.
+     *
+     * Parameters: 
+     * e - {Event} the mouseclick event object
+     */
+    swatchClick: function(e) {
+        var a = Event.element(e);
+        
+        this.color = a.swatchColor;
+        this.updateSelected();
+        this.hide();
+    },
+    
+    /**
+     * Method: colorChanged
+     * handle the user entering a new colour value manually by updating the
+     * selected colour if the entered value is valid HEX.
+     */
+    colorChanged: function() {
+        var color = this.colorInput.value;
+        if (color.substring(0,1) == '#') {
+            color = color.substring(1);
+        }
+        if (color.toLowerCase().match(/^[0-9a-f]{6}$/)) {
+            this.color = '#' +color.toUpperCase();
+            this.updateSelected();
+        }
+    },
+    
+    /**
+     * Method: alphaChanged
+     * handle the user entering a new alpha value manually by updating the
+     * selected alpha if the entered value is valid alpha (0-100).
+     */
+    alphaChanged: function() {
+        var alpha = this.alphaInput.value;
+        if (alpha.match(/^[0-9]{1,3}$/)) {
+            this.alpha = parseFloat(alpha/100);
+            this.updateSelected();
+        }
+    },
+    
+    /**
+     * Method: setColor
+     * set the colour represented by this colour panel
+     *
+     * Parameters: 
+     * color - {String} the new hex color value
+     */
+    setColor: function( color ) {
+        this.colorInput.value = color;
+        this.colorChanged();
+    },
+    
+    /**
+     * Method: setAlpha
+     * set the alpha represented by this colour panel
+     *
+     * Parameters: 
+     * alpha - {Integer} the new alpha value (between 0 and 100)
+     */
+    setAlpha: function( alpha ) {
+        this.alphaInput.value = alpha;
+        this.alphaChanged();
+    },
+    
+    /**
+     * Method: updateSelected
+     * update the colour panel user interface based on the current
+     * colour and alpha values
+     */
+    updateSelected: function() {
+        this.selectedSwatch.style.backgroundColor = this.color;
+        this.colorInput.value = this.color.substring(1);
+        
+        this.alphaInput.value = parseInt(this.alpha*100);
+        if (this.alpha < 1) {
+            this.selectedSwatch.style.opacity = this.alpha;
+            this.selectedSwatch.style.filter = 'Alpha(opacity='+(this.alpha*100)+')';
+        } else {
+            this.selectedSwatch.style.opacity = '';
+            this.selectedSwatch.style.filter = '';
+        }
+        this.processEvent(this.ccl,'colorChanged',this);
+    },
+    
+    /**
+     * Method: show
+     * show the panel
+     */
+    show: function() {
+        this.domObj.style.display = 'block';
+        Event.observe(window, 'keypress', this.keypressWatcher);
+    },
+    
+    /**
+     * Method: hide
+     * hide the panel
+     */
+    hide: function() {
+        this.domObj.style.display = 'none';
+        Event.stopObserving(window, 'keypress', this.keypressWatcher);
+        
+    },
+    
+    /**
+     * Method: keypressHandler
+     * handle the user pressing a key.  If the key is the ESC key, then
+     * hide the color panel
+     *
+     * Parameters: 
+     * e - {Event} The keypress event
+     */
+    keypressHandler: function(e) {
+        var charCode=(e.charCode)?e.charCode:e.keyCode;
+        if (charCode == Event.KEY_ESC) {
+            this.hide();
+        }
+    },
+    /**
+     * Method: addColorChangeListener
+     * add a colour change listener, an object that has a colorChanged
+     * function.
+     *
+     * Parameters: 
+     * obj - {Object} The colour change listener to call when the colour changes.
+     */
+    addColorChangeListener: function(obj){this.addListener(this.ccl, obj);},
+    /**
+     * Method: removeColorChangeListener
+     * remove a previously added colour change listener
+     *
+     * Parameters: 
+     * obj - {Object} The colour change listener to remove
+     */
+    removeColorChangeListener: function(obj) {
+        this.removeListener(this.ccl, obj);
+    }
+};
+Object.extend(Jx.ColorPanel.prototype, Jx.Listener.prototype);
+
+/**
+ * Class: Jx.Button.Color
+ *
+ * A <Jx.ColorPanel> wrapped up in a Jx.Button.  The button includes a
+ * preview of the currently selected color.  Clicking the button opens
+ * the color panel.
+ *
+ * Inherits From:
+ * <Jx.Button.Flyout>
+ */
+Jx.Button.Color = Class.create();
+Object.extend(Jx.Button.Color.prototype, Jx.Button.Flyout.prototype);
+Object.extend(Jx.Button.Color.prototype, {
+    /**
+     * Property: { Array } colorPanel
+     * By declaring this property as an array in the prototype, the
+     * array is used for all instances making it a Class property.
+     * A <Jx.ColorPanel> instance used by all color buttons is made the
+     * first element so that only one color panel is ever created.
+     */
+    colorPanel: [],
+    /**
+     * Property: {HTMLElement} swatch
+     * a div used to represent the current colour in the button.
+     */
+    swatch: null,
+    /**
+     * Property: {String} color
+     * the current colour of this button in hex.  We have to maintain
+     * it here because we share a colour panel with all other colour
+     * buttons
+     */
+    color: null,
+    /**
+     * Property: {Integer} alpha
+     * the current alpha of this button.  We have to maintain
+     * it here because we share a colour panel with all other colour
+     * buttons
+     */
+    alpha: null,
+    /**
+     * Property: {Array} ccl
+     * color change property listeners
+     */
+    ccl: null,
+    /**
+     * Constructor: Jx.Button.Color
+     * initialize a new colour button.
+     *
+     * Parameters: 
+     * options - {Object} an object containing a variable list of optional initialization
+     * parameters.
+     *
+     * Options:
+     * color - a colour to initialize the panel with, defaults to #000000
+     *      (black) if not specified.
+     * alpha - an alpha value to initialize the panel with, defaults to 1
+     *      (opaque) if not specified.
+     */
+     
+    initialize: function(options) {
+        options = options || {};
+        options.label = options.label || '&nbsp;';
+        this.color = options.color || '#000000';
+        this.alpha = options.alpha || 100;
+        this.ccl = [];
+        
+        if (this.colorPanel.length == 0) {
+            this.colorPanel[0] = new Jx.ColorPanel();
+        }
+        var d = document.createElement('div');
+        d.className = 'jxColorButtonPreview';
+        
+        this.selectedSwatch = document.createElement('div');
+        d.appendChild(this.selectedSwatch);
+        
+        /* create a button with a label so it doesn't get an empty label class
+           and then replace the label text with the swatch */
+        Jx.Button.Flyout.prototype.initialize.apply(this, [options]);
+        Element.addClassName(this.domObj.firstChild, 'jxButtonColor');
+        this.domObj.firstChild.firstChild.insertBefore(d, this.domObj.firstChild.firstChild.firstChild);
+        this.updateSwatch();
+    },
+    
+    /**
+     * Method: show
+     * show the color panel when the user clicks the button
+     */
+    show: function() {
+        if (this.colorPanel[0].currentButton) {
+            this.colorPanel[0].currentButton.hide();
+        }
+        this.colorPanel[0].currentButton = this;
+        this.colorPanel[0].addColorChangeListener(this);
+        this.content.appendChild(this.colorPanel[0].domObj);
+        this.colorPanel[0].domObj.style.display = 'block';
+        Jx.Button.Flyout.prototype.show.apply(this, arguments);
+        /* setting these before causes an update problem when clicking on
+         * a second color button when another one is open - the color
+         * wasn't updating properly
+         */
+        this.colorPanel[0].setColor(this.color);
+        this.colorPanel[0].setAlpha(this.alpha);
+    },
+    
+    /**
+     * Method: hide
+     * hide the colour panel
+     */    
+    hide: function() {
+        this.colorPanel[0].removeColorChangeListener(this);
+        Jx.Button.Flyout.prototype.hide.apply(this, arguments);
+        this.colorPanel[0].currentButton = null;
+    },
+    
+    /**
+     * Method: setColor
+     * set the colour represented by this colour panel
+     *
+     * Parameters: 
+     * color - {String} the new hex color value
+     */
+    setColor: function(color) {
+        this.color = color;
+        this.updateSwatch();
+    },
+    
+    /**
+     * Method: setAlpha
+     * set the alpha represented by this colour panel
+     *
+     * Parameters: 
+     * alpha - {Integer} the new alpha value (between 0 and 100)
+     */
+    setAlpha: function(alpha) {
+        this.alpha = alpha;
+        this.updateSwatch();
+    },
+    
+    /**
+     * Method: colorChanged
+     * colorChangeListener callback function when the user changes
+     * the colour in the panel (just update the preview).
+     */
+    colorChanged: function(panel) {
+        this.color = panel.color;
+        this.alpha = panel.alpha * 100;
+        this.updateSwatch();
+        this.processEvent(this.ccl,'colorChanged',this);
+    },
+    
+    /**
+     * Method: updateSwatch
+     * Update the swatch color for the current color
+     */
+    updateSwatch: function() {
+        this.selectedSwatch.style.backgroundColor = this.color;
+        if (this.alpha < 100) {
+            this.selectedSwatch.style.opacity = this.alpha/100;
+            this.selectedSwatch.style.filter = 'Alpha(opacity='+(this.alpha)+')';    
+        } else {
+            this.selectedSwatch.style.opacity = '';
+            this.selectedSwatch.style.filter = '';    
+        }
+    },
+    /**
+     * Method: addColorChangeListener
+     * add a colour change listener, an object that has a colorChanged
+     * function.
+     *
+     * Parameters: 
+     * obj - {Object} The colour change listener to call when the colour changes.
+     */
+    addColorChangeListener: function(obj){this.addListener(this.ccl, obj);},
+    /**
+     * Method: removeColorChangeListener
+     * remove a previously added colour change listener
+     *
+     * Parameters: 
+     * obj - {Object} The colour change listener to remove
+     */
+    removeColorChangeListener: function(obj) {
+        this.removeListener(this.ccl, obj);
+    }
+});
+/**
+ * $Id: jxdialog.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Dialog
+ *
+ * Purpose: 
+ * Implementation of a javascript Dialog for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+Jx.addStyleSheet('dialog/dialog.css');
+
+/**
+ * Class: Jx.Dialog
+ *
+ * A Jx.Dialog implements a floating dialog.  Dialogs represent a useful way
+ * to present users with certain information or application controls.
+ * Jx.Dialog is designed to provide the same types of features as traditional
+ * operating system dialog boxes, including:
+ *
+ * - dialogs may be modal (user must dismiss the dialog to continue) or 
+ * non-modal
+ *
+ * - dialogs are moveable (user can drag the title bar to move the dialog
+ * around)
+ *
+ * - dialogs may be a fixed size or allow user resizing.
+ *
+ * - dialogs may have associated help content that is available as a slide-out
+ * help panel on the right-hand side of the dialog.
+ *
+ * Jx.Dialog uses <Jx.ContentLoader> to load content into the content area
+ * of the dialog.  Refer to the <Jx.ContentLoader> documentation for details
+ * on content options.  Jx.Dialog also uses <Jx.ContentLoader> to load
+ * help content, using non-standard options prefixed by 'help' instead of
+ * 'content' (see options in initialize below).
+ *
+ * (code)
+ * var dialog = new Jx.Dialog({});
+ * (end)
+ *
+ * Inherits From:
+ * <Jx.ContentLoader>, <Jx.UniqueId>
+ */
+Jx.Dialog = Class.create();
+Jx.Dialog.prototype = {
+    /**
+     * Property: {Function} onClose
+     * if specified by the caller, this is a function to invoke
+     * when the dialog closes.
+     */
+    onClose : null,
+    /**
+     * Property: {Function} onOpen
+     * if specified by the caller, this is a function to invoke
+     * when the dialog opens.
+     */
+    onOpen : null,
+    /**
+     * Property: {Function} onChange
+     * if specified by the caller, this is a function to invoke
+     * when any input element in the dialog is changed.
+     */
+    onChange : null,
+    /**
+     * Property: {String} title
+     * the text to display in the title bar of the dialog.
+     */
+    title : null,
+    /**
+     * Property: {HTMLElement} content
+     * the content area element of the dialog, used to load user-
+     * specified content into.
+     */
+    content : null,
+    /**
+     * Property: {HTMLElement} action
+     * the action area element of the dialog, used for buttons.
+     */
+    action : null,
+    /**
+     * Property: {Object} values
+     * when dialog content is loaded, the content is inspected for input
+     * elements and a record of them is keep in this object for later
+     * reference.
+     */
+    values : null,
+    /**
+     * Property: {Object} actions
+     * when dialog content is loaded, the content is inspected for
+     * input elements of type 'button' and a record of them is
+     * kept in this object for later reference.
+     */
+    actions : null,
+    /**
+     * Property: {Function} handler
+     * if specified by the caller, this is a function to invoke
+     * when an input of type button is clicked by the user.
+     */
+    handler : null,
+    /**
+     * TODO: Jx.Dialog.bContentLoaded
+     * remove this property, it is provided by Jx.ContentLoader.
+     */
+    bContentLoaded : null,
+    /**
+     * Property: {Array} zIndex
+     * class variable containing the last assigned z-index so that
+     * dialogs stack correctly.
+     */
+    zIndex: [101],
+    /**
+     * Property: {Array} stack
+     * class variable containing the list of visible dialogs used to
+     * manage the z-index of non-modal dialogs.  This allows the user
+     * to click a dialog and have it appear in front of other dialogs.
+     */
+    stack: [],
+    /**
+     * Property: {HTMLElement} blanket
+     * modal dialogs prevent interaction with the rest of the application
+     * while they are open, this element is displayed just under the
+     * dialog to prevent the user from clicking anything.
+     */
+    blanket: null,
+    
+    /**
+     * Property: firstShow
+     * {Boolean} true if the dialog has not been made visible yet.  This
+     * facilitates resizing of <Jx.Layout> managed elements in the dialog
+     */
+    firstShow: true,
+    
+    /**
+     * Property: {Boolean} modal
+     * whether or not the dialog is modal.
+     */
+    modal: true,
+    /**
+     * Constructor: Jx.Dialog
+     * Construct a new instance of Jx.Dialog
+     *
+     * Parameters: 
+     * options - {Object} an object containing options for the dialog.
+     *
+     * Options:
+     * onChange - (optional) {Function} a function to call if the user changes
+     *      the value of any input in the dialog
+     * onClose - (optional) {Function} a function to call when the user closes
+     *      the dialog
+     * onOpen - (optional) {Function} a function to call when the user opens
+     *      the dialog
+     * onContentLoaded - (optional) {Function} a function to call when the
+     *      content of the dialog has been loaded, used primarily with
+     *      asynchronous content
+     * handler - (optional) {Function} a function to call when the user clicks
+     *      on any input of type 'button' in the dialog
+     * modal - (optional) {Boolean} controls whether the dialog will be modal
+     *      or not.  The default is to create modal dialogs.
+     * top - (optional) {Integer} the distance in pixels to initially place
+     *      the dialog from the top edge of its container.  Default is 0 unless
+     *      bottom is specified, in which case the top value is not used.
+     * bottom - (optional) {Integer} the distance in pixels to initially place
+     *      the dialog from the bottom edge of its container.  Default is null, which
+     *      means that the dialog is not positioned relative to the bottom of its
+     *      container.  If top and bottom are specified, top is used.
+     * left - (optional) {Integer} the distance in pixels to initially place
+     *      the dialog from the left edge of its container.
+     * right - (optional) {Integer} the distance in pixels to initially place
+     *      the dialog from the right edge of its container.  Default is null, which
+     *      means that the dialog is not positioned relative to the right of its
+     *      container.  If left and right are specified, left is used.
+     * width - (optional) {Integer} the initial width in pixels of the dialog.
+     *      The default value is 250 if not specified.
+     * height - (optional) {Integer} the initial height in pixels of the 
+     *      dialog. The default value is 250 if not specified.
+     * title - (optional) {String} the title of the dialog box.  "New Dialog"
+     *      is the default value.
+     * titleHeight - (optional) {Integer} the height, in pixels, of the
+     *      dialog's title bar.  The default value is 22, and works with the default
+     *      dialog styles.  Only change this value is you are overriding the
+     *      default style of the dialog's title bar
+     * closeImg - (optional) {String} URL to an image to use for the close
+     *      button in the dialog title bar area.  The default value is to use
+     *      the close image provided by Jx.  Only override this value if you are
+     *      changing the default style of the dialog's title bar.
+     * helpID - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      help content.
+     * helpURL - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      help content.
+     * helpHTML - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      help content.
+     * help - (optional) {Object} passed to <Jx.ContentLoader> for loading
+     *      help content.
+     * contentID - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * contentURL - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * contentHTML - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * content - (optional) {Object} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * buttons - (optional) {Array} an array of strings that contain the labels
+     *      for buttons to create in the Action area of the dialog.
+     * id - (optional) {String} an HTML ID to assign to the dialog, primarily
+     *      used for applying CSS styles to specific dialogs
+     * parentObj - (optional) {HTMLElement} a reference to an HTML element that
+     *      the dialog is to be contained by.  The default value is for the dialog
+     *      to be contained by the body element.
+     * resizeable - (optional) {Boolean} determines whether the dialog is
+     *      resizeable by the user or not.  Default is false.
+     * imageBaseUrl - (optional) {String} the path to the various dialog edge
+     *      images.  If not specified, then Jx.baseURL is used.
+     */
+    initialize: function(options) {
+        this.initUniqueId();
+        this.values = {};
+        this.actions = {};
+        this.handler = options.handler?options.handler:null;
+        if (options.onChange) {this.onChange = options.onChange;}
+        if (options.onClose) {this.onClose = options.onClose;}
+        if (options.onOpen) {this.onOpen = options.onOpen;}
+        if (options.onContentLoaded) {this.onContentLoaded = options.onContentLoaded;}
+        
+        this.imageBaseUrl = options.imageBaseUrl || Jx.baseURL + "/images/";
+        if (this.imageBaseUrl.slice(-1) != '/') {
+            this.imageBaseUrl += '/';
+        }
+        this.modal = typeof options.modal == 'undefined' ? true : options.modal;
+        
+        var w = options.width || 250;
+        var h = options.height || 250;
+        var b = (typeof options.bottom != 'undefined') ? options.bottom : null;
+        var r = (typeof options.right != 'undefined') ? options.right : null;
+        var t = (typeof options.top != 'undefined') ? options.top : (b != null ? null : 0);
+        var l = (typeof options.left != 'undefined') ? options.left : (r != null ? null : 0);
+        
+        this.blanket = document.createElement('div');
+        this.blanket.className = 'jxDialogModal';
+        this.blanket.style.display = 'none';
+        
+        if (!window.opera && this.modal) {
+            var iframe = document.createElement('iframe');
+            iframe.className = 'jxDialogShim';
+            iframe.scrolling = 'no';
+            iframe.frameborder = 0;
+            this.blanket.appendChild(iframe);
+            if (options.parentObj) {
+                $(options.parentObj).appendChild(this.blanket);
+            } else {
+                document.body.appendChild(this.blanket);            
+            }        
+        }
+
+        /* dragHandle is the title bar */
+        this.dragHandle = document.createElement('div');
+        this.dragHandle.innerHTML = options.title || '&nbsp;';
+        this.dragHandle.style.width = '100%';
+        
+        var domObj = document.createElement('div');
+        domObj.className = 'jxDialogContainer';
+        this.domObj = domObj;
+        /* set the id if passed in through options */
+        if (options.id) {
+            domObj.id = options.id;
+        }
+
+        var dialogObj = document.createElement('div');
+        dialogObj.className = 'jxDialog';
+        this.innerDialogObj = dialogObj;
+        
+        var titleObj = document.createElement('div');
+        titleObj.className = 'jxDialogTitle';
+        this.title = titleObj;
+        titleObj.appendChild(this.dragHandle);
+        
+        /* element must be in the page to be measured */
+        titleObj.style.visibility = 'hidden';
+        document.getElementsByTagName('BODY')[0].appendChild(titleObj);
+        this.titleHeight = Element.getBorderBoxSize(titleObj).height;
+        document.getElementsByTagName('BODY')[0].removeChild(titleObj);
+        titleObj.style.visibility = '';
+        
+        var contentObj = document.createElement('div');
+        contentObj.className = 'jxDialogContent';
+        this.content = contentObj;
+        
+        domObj.appendChild(dialogObj);
+        dialogObj.appendChild(titleObj);
+        dialogObj.appendChild(contentObj);
+                
+        new Jx.Layout(dialogObj, {width: w, height: h});
+        new Jx.Layout(titleObj, {top: 0, left: 0, right: 0, bottom: null, height: this.titleHeight, width: null});
+
+        /* optional 'action' area for buttons if necessary */
+        this.actionHeight = 0;
+        if (options.buttons) {
+            var actionObj = document.createElement('div');
+            actionObj.className = 'jxDialogAction';
+            actionObj.style.visibility = 'hidden';
+            document.getElementsByTagName('BODY')[0].appendChild(actionObj);
+            this.actionHeight = parseInt(Element.getStyle(actionObj, 'height'));
+            document.getElementsByTagName('BODY')[0].removeChild(actionObj);
+            actionObj.style.visibility = '';
+            dialogObj.appendChild(actionObj);
+            new Jx.Layout(actionObj, {top: null, left: 0, right: 0, bottom: 0, height: this.actionHeight, width: null});
+            this.action = actionObj;
+            this.setButtons(options.buttons);
+        }
+
+        new Jx.Layout(contentObj, {top: this.titleHeight, left: 0, right: 0, bottom: this.actionHeight});
+        
+        
+        /* build the decorations for the title bar */
+        var atag = document.createElement('a');
+        atag.href = 'javascript:void(0)';
+        atag.className = 'jxDialogCloseButton';
+        atag.onclick = this.close.bindAsEventListener(this);
+        
+        var close = document.createElement('img');
+        if(options.closeImg) {
+            close.src = options.closeImg;
+        }
+        else {
+            close.src = this.imageBaseUrl + 'icon_close.png';
+        }
+        close.alt = 'Close Dialog';
+        close.title = 'Close Dialog';
+        atag.appendChild(close);
+        titleObj.appendChild(atag);
+        
+        if (options.helpID || options.helpHTML || options.helpURL || options.help) {
+            /* put a button in the title bar to open help */
+            var atag2 = document.createElement('a');
+            atag2.href = 'javascript:void(0)';
+            atag2.className = 'jxDialogHelpButton';
+            atag2.onclick = this.toggleHelp.bindAsEventListener(this);
+            var help = document.createElement('img');
+            help.src = this.imageBaseUrl + 'icon_quickhelp.png';
+            help.alt = 'Help';
+            help.title = 'Help';
+            atag2.appendChild(help);
+            titleObj.appendChild(atag2);
+
+            /* make the help area */
+            this.help = document.createElement('div');
+            this.help.className = 'jxDialogHelp';
+            this.help.style.display = 'none';
+            this.help.isVisible = false;
+            var helpOpts = {};
+            helpOpts.contentID = options.helpID;
+            helpOpts.content = options.help;
+            helpOpts.contentURL = options.helpURL;
+            helpOpts.contentHTML = options.helpHTML;
+            helpOpts.onContentLoaded = this.onHelpContentLoaded.bind(this);
+            this.loadContent(this.help, helpOpts);
+            dialogObj.appendChild(this.help);
+        }
+        
+        var contentOpts = {};
+        contentOpts.contentID = options.contentID;
+        contentOpts.content = options.content;
+        contentOpts.contentURL = options.contentURL;
+        contentOpts.contentHTML = options.contentHTML;
+        contentOpts.onContentLoaded = this.onDialogContentLoaded.bind(this);
+        this.loadContent(contentObj, contentOpts);
+                
+        /* element must be in the page to be measured */
+        dialogObj.style.visibility = 'hidden';
+        document.body.appendChild(dialogObj);
+        //force an initial size calculation
+        dialogObj.resize();
+        
+        /* the outer box needs to be sized to the border box size plus margins
+         * of the inner box.
+         */
+         
+        this.dialogBoxSize = Element.getBorderBoxSize(dialogObj);
+        this.dialogBoxMargins = Element.getMarginSize(dialogObj);
+        
+        var containerSize = {width: this.dialogBoxSize.width, height: this.dialogBoxSize.height};
+        containerSize.width += this.dialogBoxMargins.left + this.dialogBoxMargins.right; 
+        containerSize.height += this.dialogBoxMargins.top + this.dialogBoxMargins.bottom;
+        
+        document.body.removeChild(dialogObj);
+        dialogObj.style.visibility = '';
+        domObj.appendChild(dialogObj);
+        
+        /* now create overall container with the correct size */
+        domObj.style.display = "none";
+        
+        Element.setBorderBoxSize(domObj, {width:(containerSize.width), height:(containerSize.height)});
+        
+        domObj.style.position = 'absolute';
+        if (t != null) {
+            domObj.style.top = (t) + 'px';
+        } else {
+            domObj.style.bottom = (b) + 'px';
+        }
+        if (l != null) {
+            domObj.style.left = (l) + 'px';
+        } else {
+            domObj.style.right = (r) + 'px';
+        }
+
+        if (options.parentObj) {
+            $(options.parentObj).appendChild(domObj);
+        } else {
+            document.body.appendChild(domObj);            
+        }
+
+        /* Background */
+        this.DTOffset = 0;
+        this.DBOffset = 0;
+        this.DROffset = 0;
+        this.DLOffset = 0;
+        this.decorationOffsets = {top:0, right: 0, bottom: 0, left: 0};
+        
+        /* top left */
+        
+        var imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgTL';
+        var img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_tl.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.decorationOffsets.top += parseInt(Element.getStyle(img,'width'));
+        this.decorationOffsets.left += parseInt(Element.getStyle(img,'height'));
+
+        /* top right */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgTR';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_tr.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.decorationOffsets.top += parseInt(Element.getStyle(img,'width'));
+        this.decorationOffsets.right += parseInt(Element.getStyle(img,'height'));
+
+        /* bottom right */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgBR';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_br.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.decorationOffsets.bottom += parseInt(Element.getStyle(img,'width'));
+        this.decorationOffsets.right += parseInt(Element.getStyle(img,'height'));
+
+        /* bottom left */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgBL';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_bl.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.decorationOffsets.bottom += parseInt(Element.getStyle(img,'width'));
+        this.decorationOffsets.left += parseInt(Element.getStyle(img,'height'));
+
+        /* top */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgT';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_t.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        img.style.width = containerSize.width-this.decorationOffsets.top + 'px';
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.topImg = img;
+
+        /* bottom */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgB';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_b.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        img.style.width = containerSize.width-this.decorationOffsets.bottom + 'px';
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.bottomImg = img;
+
+        /* left */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgL';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_l.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        img.style.height = containerSize.height-this.decorationOffsets.left + 'px';
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.leftImg = img;
+
+        /* right */
+        imgContainer = document.createElement('div');
+        imgContainer.className = 'jxDialogBgR';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + 'dialog_glow_r.png';
+        img.className = 'png24'; /* apply png hack for IE */
+        img.style.height = containerSize.height-this.decorationOffsets.right + 'px';
+        imgContainer.appendChild(img);
+        domObj.appendChild(imgContainer);
+        this.rightImg = img;
+
+        
+        Event.observe(domObj, 'mousedown', this.mouseDown.bind(this));
+        Event.observe(this.title, 'mousedown', this.mouseDown.bind(this));
+                
+        if (options.resizeable) {
+            this.resizeHandle = document.createElement('div');
+            this.resizeHandle.className = 'jxDialogResize';
+            this.resizeHandle.style.position = 'absolute'; //required for Draggable
+            this.domObj.appendChild(this.resizeHandle);
+
+            this.resizeHandleSize = {width:parseInt(Element.getStyle(this.resizeHandle,'width')),
+                                     height:parseInt(Element.getStyle(this.resizeHandle,'height'))};
+
+            this.resizeHandle.style.top = (containerSize.height-this.resizeHandleSize.height) + 'px';
+            this.resizeHandle.style.left = (containerSize.width-this.resizeHandleSize.width) + 'px';
+            new Draggable(this.resizeHandle, {starteffect: false, endeffect: false,change:this.ondrag.bind(this), zindex: 0});
+        }
+        
+        this.bOpen = false;
+    },
+    /**
+     * Method: mouseDown
+     * handle the user clicking the title area, promote the dialog to the
+     * top of the stack so it is fully visible to the user.
+     */
+    mouseDown: function() {
+        for (var i=0; i<this.stack.length; i++) {
+            if (this.stack[i] == this) {
+                this.stack.splice(i, 1);
+                this.stack.push(this);
+            }
+        }
+        for (var i=0; i<this.stack.length; i++) {
+            this.stack[i].domObj.style.zIndex = (101 + i);
+        }
+    },
+    /** 
+     * Method: ondrag
+     * callback function for user-resizing of the dialog
+     *
+     * Parameters: 
+     * obj - {Object} a drag object that indicates what happened.
+     */
+    ondrag: function(obj) {
+        this.mouseDown();
+        
+        var delta = obj.currentDelta();
+        //delta is top/left of resize image.  Bottom/right of the dialog needs to be
+        //adjusted for size of image (20x20).
+        var deltaX = delta[0] + this.resizeHandleSize.width;
+        var deltaY = delta[1] + this.resizeHandleSize.height;
+        this.resize({width: deltaX, height: deltaY});
+    },
+    /**
+     * Method: resize
+     * programmatically resize the dialog in either or both dimensions
+     *
+     * Parameters: 
+     * newSize - {Object} an object containing either or both 'width' and 'height' properties
+     * that hold the new width or height in pixels
+     */
+    resize: function(newSize) {
+
+        /* let jxLayout manage the internal stuff */
+        this.innerDialogObj.resize(newSize);
+                
+        /* sizing logic for container
+         *
+         * we need to set the size of this.innerDialogObj to the requested size
+         * then size the title, content and action area within it and expand
+         * this.domObj to contain it properly.  Then we need to position the
+         * images appropriately too.
+         */
+        if (newSize.width) {
+            var outerWidth = newSize.width;
+            Element.setBorderBoxSize(this.domObj, {width: outerWidth});
+            Element.setBorderBoxSize(this.topImg, {width:outerWidth-this.decorationOffsets.top});
+            Element.setBorderBoxSize(this.bottomImg, {width:outerWidth-this.decorationOffsets.bottom});
+        }
+        if (newSize.height) {
+            var outerHeight = newSize.height;
+            Element.setBorderBoxSize(this.domObj, {height: outerHeight});
+            Element.setBorderBoxSize(this.leftImg, {height:outerHeight-this.decorationOffsets.left});
+            Element.setBorderBoxSize(this.rightImg, {height:outerHeight-this.decorationOffsets.right});
+            if (this.help) {
+                Element.setBorderBoxSize(this.help, {height:newSize.height - this.titleHeight});
+            }
+        }
+    },
+    /**
+     * Method: setTitle
+     * set the text of the dialog title.
+     *
+     * Parameters: 
+     * title - {String} the new title
+     */
+    setTitle: function( title ) {
+        this.title.childNodes[0].innerHTML = title;
+    },
+    /**
+     * Method: setButtons
+     * create buttons in the action area of the dialog
+     *
+     * Parameters: 
+     * buttons - {Array} an array of strings containing the labels to place on the
+     * buttons.  One button is created for each label.
+     */
+    setButtons: function(buttons) {
+        this.action.innerHTML = '';
+        for (var i=0; i<buttons.length;i++) {
+            var button = document.createElement('input');
+            button.id = buttons[i];
+            button.type = 'button';
+            button.className = 'normalButton';
+            button.name = buttons[i];
+            button.value = buttons[i];
+            button.onclick = this.buttonHandler.bind(this, button);
+            this.action.appendChild(button);
+            this.uniqueIdRefs[button.id] = button;
+        }
+    },
+    /**
+     * Method: processInputs
+     * look through the DOM obj for nodes of type INPUT and register
+     * for events on them.
+     *
+     * Parameters: 
+     * obj - {HTMLElement} the DOM obj to process
+     */
+    processInputs : function(obj) {
+        for (var i=0;i<obj.childNodes.length; i++) {
+            var node = obj.childNodes[i];
+            if (node.tagName == 'INPUT' || node.tagName == 'SELECT' || node.tagName == 'TEXTAREA') {
+                if (node.type == 'button') {
+                    this.actions[node.id] = node;
+                    node.onclick = this.buttonHandler.bind(this, node);
+                } else {
+                    this.values[node.id] = node;
+                    if (this.onChange) {
+                        node.onchange = this.onChangeHandler.bind(this, node);
+                    }
+                }
+            } else {
+                if (node.childNodes) {
+                    this.processInputs(node);
+                }
+            }
+        }
+    },
+    /**
+     * Method: buttonHandler
+     * handle button events, dispatching to user handler if required.
+     *
+     * Parameters: 
+     * input - {HTMLElement} the input element that triggered a click event
+     * event - {Event} the event object
+     */
+    buttonHandler : function(input, event) {
+        if (this.handler) {
+            this.handler(input.value, this);
+        }
+    },
+    /**
+     * Method: onChangeHandler
+     * handle onchange events, dispatching to user handler if required.
+     *
+     * Parameters: 
+     * input - {HTMLElement} the input element that triggered an onchange event
+     * event - {Event} the event object
+     */
+    onChangeHandler: function(input, event) {
+        if (this.onChange) {
+            this.onChange(input, this);
+        }
+    },
+    /**
+     * Method: getValue
+     * retrieve the value of an input element in the dialog.  This is done
+     * safely so depending on the type of the input.
+     *
+     * Parameters: 
+     * name - {String} the id of the element to get the value of
+     *
+     * Returns: {String} the value or an empty string.
+     */
+    getValue : function( name ) {
+        var result = '';
+        var input = this.values[name];
+        if (input) {
+            switch (input.tagName) {
+                case 'INPUT': 
+                    result = input.value;
+                    break;
+                case 'SELECT':
+                    result = input.options[input.selectedIndex].value;
+            }
+        }
+        return result;
+    },
+    /**
+     * Method: setValue
+     * set the value of an input element in the dialog.  This is done
+     * safely  depending on the type of the input.
+     *
+     * Parameters: 
+     * name - {String} the id of the element to set the value of
+     * value - {String} the value to set
+     */
+    setValue : function( name, value ) {
+        if (typeof this.values[name] != 'undefined') {
+            if (this.values[name].type == 'text' || this.values[name].type == 'hidden') {
+                this.values[name].value = value;
+            }
+        }
+    },
+    /**
+     * Method: show
+     * show the dialog
+     */
+    show : function( ) {
+        this.stack.push(this);
+        if (this.modal) {
+            this.blanket.style.zIndex = this.zIndex[0]++;
+            this.blanket.style.visibility = 'visible';
+            this.blanket.style.display = 'block';
+        }
+        this.domObj.style.zIndex = this.zIndex[0]++;
+        Effect.Appear(this.domObj, {duration: 0.1});
+        this.domObj.style.display = 'block';
+        new Draggable(this.domObj, {handle:this.dragHandle, starteffect: false, endeffect: false});
+        this.content.resize({forceResize: this.firstShow});
+        this.firstShow = false;
+    },
+    /**
+     * Method: hide
+     * hide the dialog
+     */
+    hide : function() {
+        for (var i=0; i<this.stack.length; i++) {
+            if (this.stack[i] == this) {
+                this.stack.splice(i,1);
+            }
+        }
+        this.zIndex[0]--;
+        Effect.Fade(this.domObj, {duration: 0.3});
+        //this.domObj.style.display = 'none';
+        if (this.modal) {
+            this.blanket.style.visibility = 'hidden';
+            this.zIndex[0]--;
+        }
+        
+    },
+    /**
+     * Method: open
+     * open the dialog.  This may be delayed depending on the 
+     * asynchronous loading of dialog content.  The onOpen
+     * callback function is called when the dialog actually
+     * opens
+     */
+    open: function() {
+        if (!this.bOpen) {
+            this.bOpen = true;
+        }
+        if (this.bContentLoaded) {
+            this.show();
+            if (this.onOpen) this.onOpen();
+        }
+    },
+    /**
+     * Method: close
+     * close the dialog and trigger the onClose callback function
+     * if necessary
+     */
+    close: function() {
+        this.bOpen = false;
+        this.hide();
+        if (this.onClose) this.onClose();
+    },
+    /**
+     * Method: onDialogContentLoaded
+     * handle the dialog content being loaded.  This triggers
+     * processing of inputs and the onContentLoaded callback
+     * function (if necessary).  Also, if the dialog was previously
+     * requested to be opened, this will actually open it.
+     */
+    onDialogContentLoaded : function() {
+        this.processInputs(this.content);
+        if (this.onContentLoaded) {
+            this.onContentLoaded(this);
+        }
+        if (this.bOpen) {
+            //may need to do this?
+            //window.setTimeout(this.open.bind(this),1);
+            this.open();
+            this.bOpen = false;
+        }
+    },
+    /**
+     * Method: onHelpContentLoaded
+     * handle the help content being loaded.  
+     */
+    onHelpContentLoaded : function() {
+        var img = document.createElement('img');
+        img.className = 'jxDialogHelpCloseButton png24';
+        img.src = this.imageBaseUrl + 'help_close.png';
+        img.onclick = this.toggleHelp.bind(this);
+        img.alt = 'Close Help';
+        img.title = 'Close Help';
+        this.help.appendChild(img);
+    },
+    /**
+     * Method: toggleHelp
+     * show or hide the help panel.
+     */
+    toggleHelp: function() { 
+        if (this.help.isVisible) {
+            Effect.Fade(this.help, {duration: 0.3});
+        } else {
+            var actionSize = this.action ? Element.getBorderBoxSize(this.action) : {width: 0, height: 0};
+            var contentSize = Element.getBorderBoxSize(this.content);
+            Element.setBorderBoxSize(this.help, {height:contentSize.height+actionSize.height});
+            Effect.Appear(this.help, {duration: 0.3});
+        }
+        this.help.isVisible = !this.help.isVisible;
+    }
+};
+Object.extend(Jx.Dialog.prototype, Jx.UniqueId.prototype);
+Object.extend(Jx.Dialog.prototype, Jx.ContentLoader.prototype);/**
+ * $Id: jxgrid.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Grid
+ *
+ * Purpose: 
+ * Implementation of a javascript Grid control for Jx.
+ *
+ * Jx.Grid is a tabular control with convenient controls for resizing columns,
+ * sorting, and inline editing.  It is created inside another element, typically a
+ * div.  If the div is resizable (for instance it fills the page or there is a
+ * user control allowing it to be resized), you must call the resize() method
+ * of the grid to let it know that its container has been resized.
+ *
+ * When creating a new Jx.Grid, you can specify a number of options for the grid
+ * that control its appearance and functionality.
+ *
+ * Jx.Grid renders data that comes from an external source.  This external 
+ * source, called the model, must implement the following interface.
+ *
+ * *Mandatory Functions*
+ *
+ * addGridListener(l) - mandatory
+ * mandatory.  This function accepts one argument, l, which is the listener
+ * to add.  The model can then call the gridChanged() method on the grid
+ * listener object when something in the model changes.
+ * 
+ * removeGridListener(l) - mandatory
+ * mandatory.  This function accepts one argument, l, which is the listener
+ * to remove.  The listener should have been previously added using
+ * addGridListener.
+ * 
+ * getColumnCount() - mandatory
+ * mandatory.  This function returns the number of columns of data in the 
+ * model as an integer value.
+ * 
+ * getColumnHeaderHTML(column) - mandatory
+ * mandatory. This function returns an HTML string to be placed in the
+ * column header for the given column index.
+ * 
+ * getColumnHeaderHeight() - mandatory
+ * mandatory.  This function returns an integer which is the height of the
+ * column header row in pixels.
+ * 
+ * getColumnWidth(column) - mandatory
+ * mandatory.  This function returns an integer which is the width of the
+ * given column in pixels.
+ * 
+ * getRowHeaderHTML(row) - mandatory
+ * mandatory.  This function returns an HTML string to be placed in the row
+ * header for the given row index
+ * 
+ * getRowHeaderWidth() - mandatory
+ * mandatory.  This function returns an integer which is the width of the row
+ * header column in pixels.
+ * 
+ * getRowHeight(row) - mandatory
+ * mandatory.  This function returns an integer which is the height of the
+ * given row in pixels.
+ * 
+ * getRowCount() - mandatory
+ * mandatory.  This function returns the number of rows of data in the model
+ * as an integer value.
+ * 
+ * getValueAt(row, column) - mandatory
+ * mandatory.  This function returns an HTML string which is the text to place
+ * in the cell at the given row and column.
+ * 
+ * isCellEditable(row, column) - mandatory
+ * mandatory.  This function returns a boolean value to indicate if a given
+ * cell is editable by the user.
+ *
+ * *Optional Functions*
+ *  
+ * setColumnWidth(column, width) - optional
+ * optional.  This function is called with a column index and width in pixels
+ * when a column is resized.  This function is only required if the grid
+ * allows resizeable columns.
+ * 
+ * setValueAt(row, column, value) - optional
+ * optional.  This function is called with the row and column of a cell and a
+ * new value for the cell.  It is mandatory to provide this function if any of
+ * the cells in the model are editable.
+ * 
+ * rowSelected(row) - optional
+ * optional.  This function is called by the grid to indicate that the user
+ * has selected a row by clicking on the row header.
+ * 
+ * columnSelected(column) - optional
+ * optional.  This function is called by the grid to indicate that the user
+ * has selected a column by clicking on the column header.
+ * 
+ * cellSelected(row, column) - optional
+ * optional.  This function is called by the grid to indicate that the user
+ * has selected a cell by clicking on the cell in the grid.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/* our default css styles */
+Jx.addStyleSheet('grid/grid.css');
+
+/**
+ * Class: Jx.Grid
+ * A tabular control that has fixed scrolling headers on the rows and columns
+ * like a spreadsheet.
+ */
+Jx.Grid = Class.create();
+Jx.Grid.prototype = {
+    domObj : null,
+    model : null,
+    /**
+     * Constructor: Jx.Grid
+     * construct a new instance of Jx.Grid within the domObj
+     *
+     * Parameters:
+     * domObj - {HTMLElement} the HTML element to create the grid inside.
+     *          The grid will resize to fill the domObj.
+     * options - you can specify some options as attributes of a
+     * generic object.
+     *
+     * Options:
+     * alternateRowColors - defaults to false.  If set to true, then
+     *      alternating CSS classes are used for rows
+     * rowHeaders - defaults to false.  If set to true, then a column
+     *      of row header cells are displayed.
+     * columnHeaders - defaults to false.  If set to true, then a column
+     *      of row header cells are displayed.
+     * rowSelection - defaults to false.  If set to true, allow the
+     *      user to select rows.
+     * cellSelection - defaults to false.  If set to true, allow the
+     *      user to select cells.
+     */
+    initialize : function( domObj, options ) {
+        this.domObj = $(domObj);
+        
+        /* if this grid is the content of a Jx Panel, this will
+           allow the grid to resize when the panel resizes
+         */
+        if (!this.domObj.jxLayout) {
+            new Jx.Layout(this.domObj);
+        }
+        this.domObj.jxLayout.addSizeChangeListener(this);
+        
+        options = options || {};
+        
+        this.rowColObj = document.createElement('div');
+        this.rowColObj.className = 'jxGridContainer';
+        
+        this.colObj = document.createElement('div');
+        this.colObj.className = 'jxGridContainer';
+        this.colTable = document.createElement('table');
+        this.colTable.className = 'jxGridTable';
+        this.colTableHead = document.createElement('thead');
+        this.colTable.appendChild(this.colTableHead);
+        this.colTableBody = document.createElement('tbody');
+        this.colTable.appendChild(this.colTableBody);
+        this.colObj.appendChild(this.colTable);
+        
+        this.rowObj = document.createElement('div');
+        this.rowObj.className = 'jxGridContainer';
+        this.rowTable = document.createElement('table');
+        this.rowTable.className = 'jxGridTable';
+        this.rowTableHead = document.createElement('thead');
+        this.rowTable.appendChild(this.rowTableHead);
+        this.rowObj.appendChild(this.rowTable);
+        
+        this.gridObj = document.createElement('div');
+        this.gridObj.className = 'jxGridContainer';
+        this.gridObj.style.overflow = 'scroll';
+        this.gridTable = document.createElement('table');
+        this.gridTable.className = 'jxGridTable';
+        this.gridTableBody = document.createElement('tbody');
+        this.gridTable.appendChild(this.gridTableBody);
+        this.gridObj.appendChild(this.gridTable);
+        
+        this.domObj.appendChild(this.rowColObj);
+        this.domObj.appendChild(this.rowObj);
+        this.domObj.appendChild(this.colObj);
+        this.domObj.appendChild(this.gridObj);
+        
+        this.bAlternateRowColors = options.alternateRowColors || false;
+        this.showRowHeader = options.rowHeaders || false;
+        this.showColumnHeader = options.columnHeaders || false;
+        this.rowSelection = options.rowSelection || false;
+        this.cellSelection = options.cellSelection || false;
+                
+        Event.observe(this.gridObj, 'scroll', this.onScroll.bind(this));
+        Event.observe(this.gridObj, 'click', this.onClickGrid.bindAsEventListener(this));
+        Event.observe(this.rowObj, 'click', this.onClickRowHeader.bindAsEventListener(this));
+        Event.observe(this.colObj, 'click', this.onClickColumnHeader.bindAsEventListener(this));
+        Event.observe(this.gridObj, 'mousemove', this.onMouseMoveGrid.bindAsEventListener(this));
+        Event.observe(this.rowObj, 'mousemove', this.onMouseMoveRowHeader.bindAsEventListener(this));
+        Event.observe(this.colObj, 'mousemove', this.onMouseMoveColumnHeader.bindAsEventListener(this));
+    },
+    
+    /**
+     * Method: onScroll
+     * handle the grid scrolling by updating the position of the headers
+     */
+    onScroll: function() {
+        this.colObj.scrollLeft = this.gridObj.scrollLeft;
+        this.rowObj.scrollTop = this.gridObj.scrollTop;        
+    },
+    
+    /**
+     * Method: sizeChanged
+     * Handle the container of the grid resizing
+     */
+    sizeChanged: function() {
+        this.resize();
+    },
+    
+    /**
+     * Method: resize
+     * resize the grid to fit inside its container.  This involves knowing something
+     * about the model it is displaying (the height of the column header and the
+     * width of the row header) so nothing happens if no model is set
+     */
+    resize: function() {
+        if (!this.model) {
+            return;
+        }
+        
+        /* TODO: Jx.Grid.resize
+         * if not showing column or row, should we handle the resize differently
+         */
+        var colHeight = this.showColumnHeader ? this.model.getColumnHeaderHeight() : 1;
+        var rowWidth = this.showRowHeader ? this.model.getRowHeaderWidth() : 1;
+        
+        var size = Element.getContentBoxSize(this.domObj);
+        
+        /* -1 because of the right/bottom borders */
+        this.rowColObj.style.width = (rowWidth - 1) + 'px';
+        this.rowColObj.style.height = (colHeight - 1) + 'px';
+        
+        this.rowObj.style.top = (colHeight) + 'px';
+        this.rowObj.style.left = '0px';
+        this.rowObj.style.width = (rowWidth - 1) + 'px';
+        this.rowObj.style.height = (size.height - colHeight - 1) + 'px';
+
+        this.colObj.style.top = '0px';
+        this.colObj.style.left = (rowWidth) + 'px';
+        this.colObj.style.width = (size.width - rowWidth - 1) + 'px';
+        this.colObj.style.height = (colHeight - 1) + 'px';
+
+        this.gridObj.style.top = (colHeight) + 'px';
+        this.gridObj.style.left = (rowWidth) + 'px';
+        this.gridObj.style.width = (size.width - rowWidth - 1) + 'px';
+        this.gridObj.style.height = (size.height - colHeight - 1) + 'px';
+    },
+    
+    /**
+     * Method: setModel
+     * set the model for the grid to display.  If a model is attached to the grid
+     * it is removed and the new model is displayed.
+     * 
+     * Parameters:
+     * model - {Object} the model to use for this grid
+     */
+    setModel: function(model) {
+        if (this.model) {
+            this.model.removeGridListener(this);
+        }
+        this.model = model;
+        if (this.model) {
+            this.domObj.jxLayout.resize();
+            this.model.addGridListener(this);
+            this.createGrid();
+            this.resize();
+        } else {
+            this.destroyGrid();
+        }
+    },
+    
+    /**
+     * Method: destroyGrid
+     * destroy the contents of the grid safely
+     */
+    destroyGrid: function() {
+        var n = this.colTableHead.cloneNode(false);
+        this.colTable.replaceChild(n, this.colTableHead);
+        this.colTableHead = n;
+        
+        n = this.colTableBody.cloneNode(false);
+        this.colTable.replaceChild(n, this.colTableBody);
+        this.colTableBody = n;
+        
+        n = this.rowTableHead.cloneNode(false);
+        this.rowTable.replaceChild(n, this.rowTableHead);
+        this.rowTableHead = n;
+        
+        n = this.gridTableBody.cloneNode(false);
+        this.gridTable.replaceChild(n, this.gridTableBody);
+        this.gridTableBody = n;
+        
+    },
+    
+    /**
+     * Method: createGrid
+     * create the grid for the current model
+     */
+    createGrid: function() {
+        this.destroyGrid();
+        if (this.model) {
+            var model = this.model;
+            var nColumns = model.getColumnCount();
+            var nRows = model.getRowCount();
+            
+            /* create header if necessary */
+            if (this.showColumnHeader) {
+                var colHeight = model.getColumnHeaderHeight();
+                var trHead = document.createElement('tr');
+                this.colTableHead.appendChild(trHead);
+                var trBody = document.createElement('tr');
+                this.colTableBody.appendChild(trBody);
+                
+                var th = document.createElement('th');
+                th.style.width = '0px';
+                th.style.height = '0px';
+                trHead.appendChild(th);
+                th = th.cloneNode(true);
+                th.style.height = (colHeight) + 'px';
+                trBody.appendChild(th);
+                for (var i=0; i<nColumns; i++) {
+                    var colWidth = model.getColumnWidth(i);
+                    th = document.createElement('th');
+                    th.className = 'jxGridColHeadHide';
+                    th.style.width = (colWidth) + 'px';
+                    var p = document.createElement('p');
+                    p.style.height = '0px';
+                    p.style.width = (colWidth) + 'px';
+                    th.appendChild(p);
+                    trHead.appendChild(th);
+                    
+                    th = document.createElement('th');
+                    th.className = 'jxGridColHead';
+                    th.innerHTML = model.getColumnHeaderHTML(i);
+                    trBody.appendChild(th);
+                }
+                /* one extra column at the end for filler */
+                var th = document.createElement('th');
+                th.style.width = '1000px';
+                th.style.height = '0px';
+                trHead.appendChild(th);
+                th = th.cloneNode(true);
+                th.style.height = (colHeight - 1) + 'px';
+                th.className = 'jxGridColHead';
+                trBody.appendChild(th);
+                
+            }
+            
+            if (this.showRowHeader) {
+                var rowWidth = model.getRowHeaderWidth();
+                var tr = document.createElement('tr');
+                var td = document.createElement('td');
+                td.style.width = '0px';
+                td.style.height = '0px';
+                tr.appendChild(td);
+                var th = document.createElement('th');
+                th.style.width = (rowWidth) + 'px';
+                th.style.height = '0px';
+                tr.appendChild(th);
+                this.rowTableHead.appendChild(tr);
+                for (var i=0; i<nRows; i++) {
+                    var rowHeight = model.getRowHeight(i);
+                    var tr = document.createElement('tr');
+                    var td = document.createElement('td');
+                    td.className = 'jxGridRowHeadHide';
+                    td.style.width = '0px';
+                    td.style.height = (rowHeight)+'px';
+                    var p = document.createElement('p');
+                    p.style.width = '0px';
+                    p.style.height = (rowHeight)+'px';
+                    td.appendChild(p);
+                    tr.appendChild(td);
+                    var th = document.createElement('th');
+                    th.className = 'jxGridRowHead';
+                    th.innerHTML = model.getRowHeaderHTML(i);
+                    tr.appendChild(th);
+                    this.rowTableHead.appendChild(tr);
+                }
+                /* one extra row at the end for filler */
+                var tr = document.createElement('tr');
+                var td = document.createElement('td');
+                td.style.width = '0px';
+                td.style.height = '1000px';
+                tr.appendChild(td);
+                var th = document.createElement('th');
+                th.style.width = (rowWidth) + 'px';
+                th.style.height = '1000px';
+                th.className = 'jxGridRowHead';
+                tr.appendChild(th);
+                this.rowTableHead.appendChild(tr);
+            }
+            
+            var colHeight = model.getColumnHeaderHeight();
+            var trBody = document.createElement('tr');
+            this.gridTableBody.appendChild(trBody);
+            
+            var td = document.createElement('td');
+            td.style.width = '0px';
+            td.style.height = '0px';
+            trBody.appendChild(td);
+            for (var i=0; i<nColumns; i++) {
+                var colWidth = model.getColumnWidth(i);
+                td = document.createElement('td');
+                td.className = 'jxGridColHeadHide';
+                td.style.width = (colWidth) + 'px';
+                var p = document.createElement('p');
+                p.style.height = '0px';
+                p.style.width = (colWidth) + 'px';
+                td.appendChild(p);
+                trBody.appendChild(td);
+            }
+            
+            for (var j=0; j<nRows; j++) {
+                var rowHeight = model.getRowHeight(j);
+                var actualRowHeight = rowHeight;
+                var tr = document.createElement('tr');
+                this.gridTableBody.appendChild(tr);
+                
+                var td = document.createElement('td');
+                td.className = 'jxGridRowHeadHide';
+                td.style.width = '0px';
+                td.style.height = (rowHeight) + 'px';
+                var p = document.createElement('p');
+                p.style.height = (rowHeight) + 'px';
+                td.appendChild(p);
+                tr.appendChild(td);
+                for (var i=0; i<nColumns; i++) {
+                    var colWidth = model.getColumnWidth(i);
+                    td = document.createElement('td');
+                    td.className = 'jxGridCell';
+                    td.innerHTML = model.getValueAt(j,i);
+                    tr.appendChild(td);
+                    var tdSize = Element.getDimensions(td);
+                    if (tdSize.height > actualRowHeight) {
+                        actualRowHeight = tdSize.height;
+                    }
+                }
+                /* some notes about row sizing
+                 * In Safari, the height of a TR is always returned as 0
+                 * In Safari, the height of any given TD is the height it would
+                 * render at, not the actual height of the row
+                 * In IE, the height is returned 1px bigger than any other browser
+                 * Firefox just works
+                 *
+                 * So, for Safari, we have to measure every TD and take the highest one
+                 * and if its IE, we subtract 1 from the overall height, making all
+                 * browsers identical
+                 *
+                 * Using document.all is not a good hack for this
+                 */
+                if (document.all) {
+                    actualRowHeight -= 1;
+                }
+                if (this.showRowHeader) {
+                    this.setRowHeaderHeight(j, actualRowHeight);                    
+                }
+                /* if we apply the class before adding content, it
+                 * causes a rendering error in IE (off by 1) that is 'fixed'
+                 * when another class is applied to the row, causing dynamic
+                 * shifting of the row heights
+                 */
+                if (this.bAlternateRowColors) {
+                    tr.className = (j%2) ? 'jxGridRowOdd' : 'jxGridRowEven';
+                } else {
+                    tr.className = 'jxGridRowAll';
+                }
+            }
+            
+        }
+    },
+    
+    /**
+     * Method: setRowHeaderHeight
+     * set the height of a row.  This is used internally to adjust the height of
+     * the row header when cell contents wrap.  A limitation of the table structure
+     * is that overflow: hidden on a td will work horizontally but not vertically
+     *
+     * Parameters:
+     * row - {Integer} the row to set the height for
+     * height - {Integer} the height to set the row (in pixels)
+     */
+    setRowHeaderHeight: function(row, height) {
+        //this.rowTableHead.childNodes[row+1].childNodes[0].style.height = (height) + 'px';
+        this.rowTableHead.childNodes[row+1].childNodes[0].childNodes[0].style.height = (height) + 'px';
+    },
+    
+    /**
+     * Method: gridChanged
+     * called through the grid listener interface when data has changed in the
+     * underlying model
+     *
+     * Parameters:
+     * model - {Object} the model that changed
+     * row - {Integer} the row that changed
+     * col - {Integer} the column that changed
+     * value - {Mixed} the new value
+     */
+    gridChanged: function(model, row, col, value) {
+        if (this.model == model) {
+            this.gridObj.childNodes[row].childNodes[col].innerHTML = value;
+        }
+    },
+    
+    /** 
+     * Method: prelightRowHeader
+     * apply the jxGridRowHeaderPrelight style to the header cell of a row.
+     * This removes the style from the previously pre-lit row header.
+     * 
+     * Parameters:
+     * row - {Integer} the row to pre-light the header cell of
+     */
+    prelightRowHeader: function(row) {
+        var cell = (row >= 0 && row < this.rowTableHead.rows.length-1) ? this.rowTableHead.rows[row+1].cells[1] : null;
+        if (this.prelitRowHeader != cell) {
+            if (this.prelitRowHeader) {
+                Element.removeClassName(this.prelitRowHeader, 'jxGridRowHeaderPrelight');
+            }
+            this.prelitRowHeader = cell;
+            if (this.prelitRowHeader) {
+                Element.addClassName(this.prelitRowHeader, 'jxGridRowHeaderPrelight');
+            }
+        }
+    },
+    
+    /** 
+     * Method: prelightColumnHeader
+     * apply the jxGridColumnHeaderPrelight style to the header cell of a column.
+     * This removes the style from the previously pre-lit column header.
+     * 
+     * Parameters:
+     * col - {Integer} the column to pre-light the header cell of
+     */
+    prelightColumnHeader: function(col) {
+        if (this.colTableBody.rows.length == 0) {
+            return;
+        }
+        var cell = (col >= 0 && col < this.colTableBody.rows[0].cells.length-1) ? this.colTableBody.rows[0].cells[col+1] : null;
+        if (this.prelitColumnHeader != cell) {
+            if (this.prelitColumnHeader) {
+                Element.removeClassName(this.prelitColumnHeader, 'jxGridColumnHeaderPrelight');
+            }
+            this.prelitColumnHeader = cell;
+            if (this.prelitColumnHeader) {
+                Element.addClassName(this.prelitColumnHeader, 'jxGridColumnHeaderPrelight');
+            }
+        }
+    },
+    
+    /** 
+     * Method: prelightRow
+     * apply the jxGridRowPrelight style to row.
+     * This removes the style from the previously pre-lit row.
+     * 
+     * Parameters:
+     * row - {Integer} the row to pre-light
+     */
+    prelightRow: function(row) {
+        var tr = (row >= 0 && row < this.gridTableBody.rows.length-1) ? this.gridTableBody.rows[row+1] : null;
+        
+        if (this.prelitRow != row) {
+            if (this.prelitRow) {
+                Element.removeClassName(this.prelitRow, 'jxGridRowPrelight');
+            }
+            this.prelitRow = tr;
+            if (this.prelitRow && !Element.hasClassName(this.prelitRow, 'jxGridRowSelected')) {
+                this.prelightRowHeader(row);
+                Element.addClassName(this.prelitRow, 'jxGridRowPrelight');
+            }
+        }
+    },
+    
+    /** 
+     * Method: prelightColumn
+     * apply the jxGridColumnPrelight style to a column.
+     * This removes the style from the previously pre-lit column.
+     * 
+     * Parameters:
+     * col - {Integer} the column to pre-light
+     *
+     * TODO: Jx.Grid.prelightColumn
+     * Not Yet Implemented.
+     */
+    prelightColumn: function(col) {
+        /* TODO: Jx.Grid.prelightColumn
+         * implement column prelighting (possibly) 
+         */
+        this.prelightColumnHeader(col);
+    },
+    
+    /** 
+     * Method: prelightCell
+     * apply the jxGridCellPrelight style to a cell.
+     * This removes the style from the previously pre-lit cell.
+     *
+     * Parameters:
+     * row - {Integer} the row of the cell to pre-light
+     * col - {Integer} the column of the cell to pre-light
+     */
+    prelightCell: function(row, col) {
+         var td = (row >=0 && col >=0 && row < this.gridTableBody.rows.length - 1 && col < this.gridTableBody.rows[row+1].cells.length - 1) ? this.gridTableBody.rows[row+1].cells[col+1] : null;
+        if (this.prelitCell != td) {
+            if (this.prelitCell) {
+                Element.removeClassName(this.prelitCell, 'jxGridCellPrelight');
+            }
+            this.prelitCell = td;
+            if (this.prelitCell) {
+                Element.addClassName(this.prelitCell, 'jxGridCellPrelight');
+                this.prelightRow(row);
+                this.prelightColumn(col);
+            }
+        }    
+    },
+    
+    /** 
+     * Method: selectCell
+     * Select a cell and apply the jxGridCellSelected style to it.
+     * This deselects a previously selected cell.
+     *
+     * If the model supports cell selection, it should implement
+     * a cellSelected function to receive notification of the selection.
+     *
+     * Parameters:
+     * row - {Integer} the row of the cell to select
+     * col - {Integer} the column of the cell to select
+     */
+    selectCell: function(row, col) {
+         var td = (row >=0 && col >=0 && row < this.gridTableBody.rows.length - 1 && col < this.gridTableBody.rows[row+1].cells.length - 1) ? this.gridTableBody.rows[row+1].cells[col+1] : null;
+         if (!td) {
+             return;
+         }
+         
+         if (this.selectedCell) {
+             Element.addClassName(this.selectedCell, 'jxGridCellSelected');
+         } else {
+             Element.removeClassName(this.selectedCell, 'jxGridCellSelected');
+         }
+    },
+    
+    /** 
+     * Method: selectRowHeader
+     * Apply the jxGridRowHeaderSelected style to the row header cell of a
+     * selected row.
+     *
+     * Parameters:
+     * row - {Integer} the row header to select
+     * selected - {Boolean} the new state of the row header
+     */
+    selectRowHeader: function(row, selected) {
+        var cell = (row >= 0 && row < this.rowTableHead.rows.length-1) ? this.rowTableHead.rows[row+1].cells[1] : null;
+        if (!cell) {
+            return;
+        }
+        if (selected) {
+            Element.addClassName(cell, 'jxGridRowHeaderSelected');
+        } else {
+            Element.removeClassName(cell, 'jxGridRowHeaderSelected');
+        }
+    },
+    
+    /** 
+     * Method: selectRow
+     * Select a row and apply the jxGridRowSelected style to it.
+     *
+     * If the model supports row selection, it should implement
+     * a rowSelected function to receive notification of the selection.
+     *
+     * Parameters:
+     * row - {Integer} the row to select
+     * selected - {Boolean} the new state of the row
+     */
+    selectRow: function(row, selected) {
+        var tr = (row >= 0 && row < this.gridTableBody.rows.length - 1) ? this.gridTableBody.rows[row+1] : null;
+        if (tr) {
+            if (selected) {
+                Element.addClassName(tr, 'jxGridRowSelected');
+            } else {
+                Element.removeClassName(tr, 'jxGridRowSelected');
+            }
+        }
+        this.selectRowHeader(row, selected);
+    },
+    
+    /** 
+     * method: selectColumnHeader
+     * Apply the jxGridColumnHeaderSelected style to the column header cell of a
+     * selected column.
+     *
+     * Parameters:
+     * col - {Integer} the column header to select
+     * selected - {Boolean} the new state of the column header
+     */
+    selectColumnHeader: function(col, selected) {
+        if (this.colTableBody.rows.length == 0) {
+            return;
+        }
+        var cell = (col >= 0 && col < this.colTableBody.rows[0].cells.length-1) ? this.colTableBody.rows[0].cells[col+1] : null;
+        if (cell == null) { 
+            return; 
+        }
+        
+        if (selected) {
+            Element.addClassName(cell, 'jxGridColumnHeaderSelected');
+        } else {
+            Element.removeClassName(cell, 'jxGridColumnHeaderSelected');
+        }
+    },
+    
+    /** 
+     * Method: selectColumn
+     * Select a column.
+     * This deselects a previously selected column.
+     *
+     * Parameters:
+     * col - {Integer} the column to select
+     * selected - {Boolean} the new state of the column
+     */
+    selectColumn: function(col, selected) {
+        /* todo: implement column selection */
+        if (col >= 0 && col < this.gridTable.rows[0].cells.length) {
+            if (selected) {
+                for (var i=0; i<this.gridTable.rows.length; i++) {
+                    Element.removeClassName(this.gridTable.rows[i].cells[this.selectedColumn + 1], 'jxGridColumnSelected');
+                }
+            } else {
+                for (var i=0; i<this.gridTable.rows.length; i++) {
+                    Element.addClassName(this.gridTable.rows[i].cells[col+1], 'jxGridColumnSelected');
+                }
+                
+            }
+        }
+        this.selectColumnHeader(col, selected);
+    },
+    
+    /**
+     * Method: onMouseMoveGrid
+     * handle the mouse moving over the main grid.  This pre-lights the cell,
+     * and subsquently the row and column (and headers).
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onMouseMoveGrid: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        this.prelightCell(rc.row, rc.column);
+    },
+    
+    /**
+     * Method: onMouseMoveRowHeader
+     * handle the mouse moving over the row header cells.  This pre-lights
+     * the row and subsequently the row header.
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onMouseMoveRowHeader: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        this.prelightRow(rc.row);
+    },
+
+    /**
+     * Method: onMouseMoveColumnHeader
+     * handle the mouse moving over the column header cells.  This pre-lights
+     * the column and subsequently the column header.
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onMouseMoveColumnHeader: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        this.prelightColumn(rc.column);
+    },
+    
+    /**
+     * Method: onClickGrid
+     * handle the user clicking on the grid.  This triggers an
+     * event to the model (if a cellSelected function is provided).
+     *
+     * The following is an example of a function in the model that selects
+     * a row when the cellSelected function is called and deselects any rows
+     * that are currently selected.
+     *
+     * (code)
+     * cellSelected: function(grid, row,col) { 
+     *    if (this.selectedRow != null) {
+     *        grid.selectRow(this.selectedRow, false);
+     *    }
+     *    this.selectedRow = row;
+     *    grid.selectRow(row, true);
+     * }
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onClickGrid: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        //this.selectCell(rc.row, rc.column);
+        
+        if (this.model.cellSelected) {
+            this.model.cellSelected(this, rc.row, rc.column);
+        }
+    },
+    
+    /**
+     * Method: onClickRowHeader
+     * handle the user clicking on the row header.  This triggers an
+     * event to the model (if a rowSelected function is provided) which
+     * can then select the row if desired.  
+     *
+     * The following is an example of a function in the model that selects
+     * a row when the rowSelected function is called and deselects any rows
+     * that are currently selected.  More complex code could be written to 
+     * allow the user to select multiple rows.
+     *
+     * (code)
+     * rowSelected: function(grid, row) {
+     *    if (this.selectedRow != null) {
+     *        grid.selectRow(this.selectedRow, false);
+     *    }
+     *    this.selectedRow = row;
+     *    grid.selectRow(row, true);
+     * }
+     * (end)
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onClickRowHeader: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        
+        if (this.model.rowSelected) {
+            this.model.rowSelected(this, rc.row);
+        }
+    },
+    
+    /**
+     * Method: onClickColumnHeader
+     * handle the user clicking on the column header.  This triggers column
+     * selection and column (and header) styling changes and an
+     * event to the model (if a columnSelected function is provided)
+     *
+     * The following is an example of a function in the model that selects
+     * a column when the columnSelected function is called and deselects any 
+     * columns that are currently selected.  More complex code could be written
+     * to allow the user to select multiple columns.
+     *
+     * (code)
+     * colSelected: function(grid, col) {
+     *    if (this.selectedColumn != null) {
+     *        grid.selectColumn(this.selectedColumn, false);
+     *    }
+     *    this.selectedColumn = col;
+     *    grid.selectColumn(col, true);
+     * }
+     * (end)
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     */
+    onClickColumnHeader: function(e) {
+        var rc = this.getRowColumnFromEvent(e);
+        
+        if (this.model.columnSelected) {
+            this.model.columnSelected(this, rc.column);
+        }
+    },
+    
+    /**
+     * method: getRowColumnFromEvent
+     * retrieve the row and column indexes from an event click.
+     * This function is used by the grid, row header and column
+     * header to safely get these numbers.
+     *
+     * If the event isn't valid (i.e. it wasn't on a TD or TH) then
+     * the returned values will be -1, -1
+     *
+     * Parameters:
+     * e - {Event} the browser event object
+     *
+     * @return Object an object with two properties, row and column,
+     *         that contain the row and column that was clicked
+     */
+    getRowColumnFromEvent: function(e) {
+        var td = Event.element(e);
+        if (td.tagName != 'TD' && td.tagName != 'TH') {
+            return {row:-1,column:-1};
+        }
+        var tr = td.parentNode;
+        var col = td.cellIndex - 1; /* because of hidden spacer column */
+        var row = tr.rowIndex - 1; /* because of hidden spacer row */
+        
+        if (col == -1) { 
+            /* bug in safari returns 0 for cellIndex - only choice seems
+             * to be to loop through the row
+             */
+            for (var i=0; i<tr.childNodes.length; i++) {
+                if (tr.childNodes[i] == td) {
+                    col = i - 1;
+                    break;
+                }
+            }
+        }
+        return {row:row,column:col};
+    }
+};/**
+ * $Id: jxlayout.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Layout
+ *
+ * Purpose: 
+ * Implementation of a javascript layout engine for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * Class: Jx.Layout
+ *
+ * Jx.Layout is used to provide more flexible layout options for applications
+ *
+ * Jx.Layout wraps an existing DOM element (typically a div) and provides
+ * extra functionality for sizing that element within its parent and sizing
+ * elements contained within it that have a 'resize' function attached to them.
+ *
+ * To create a Jx.Layout, pass the element or id plus an options object to
+ * the constructor:
+ *
+ * (code)
+ * var myContainer = new Jx.Layout('myDiv', options);
+ * (end)
+ *
+ * Inherits From:
+ * <Jx.Listener>
+ */
+ 
+Jx.Layout = Class.create();
+Jx.Layout.prototype = {
+    scl: null,
+    /**
+     * Constructor: Jx.Layout
+     * Create a new instance of Jx.Layout.
+     *
+     * Parameters:
+     * domObj - {HTMLElement} element or id to apply the layout to
+     * options - {Object} options can be passed to the Jx.Layout as an object
+     * with some, all, or none of the options below.
+     *
+     * Options:
+     * position - how to position the element, either 'absolute' or 'relative'.
+     *    The default (if not passed) is 'absolute'.  When using
+     *    'absolute' positioning, both the width and height are
+     *    controlled by Jx.Layout.  If 'relative' positioning is used
+     *    then only the width is controlled, allowing the height to
+     *    be controlled by its content.
+     * left - the distance (in pixels) to maintain the left edge of the element
+     *    from its parent element.  The default value is 0.  If this is set
+     *    to 'null', then the left edge can be any distance from its parent
+     *    based on other parameters.
+     * right - the distance (in pixels) to maintain the right edge of the element
+     *    from its parent element.  The default value is 0.  If this is set
+     *    to 'null', then the right edge can be any distance from its parent
+     *    based on other parameters.
+     * top - the distance (in pixels) to maintain the top edge of the element
+     *    from its parent element.  The default value is 0.  If this is set
+     *    to 'null', then the top edge can be any distance from its parent
+     *    based on other parameters.
+     * bottom - the distance (in pixels) to maintain the bottom edge of the element
+     *    from its parent element.  The default value is 0.  If this is set
+     *    to 'null', then the bottom edge can be any distance from its parent
+     *    based on other parameters.
+     * width - the width (in pixels) of the element.  The default value is null.
+     *    If this is set to 'null', then the width can be any value based on
+     *    other parameters.
+     * height - the height (in pixels) of the element.  The default value is null.
+     *    If this is set to 'null', then the height can be any value based on
+     *    other parameters.
+     * minWidth - the minimum width that the element can be sized to.  The default
+     *    value is 0.
+     * minHeight - the minimum height that the element can be sized to.  The
+     *    default value is 0.
+     * maxWidth - the maximum width that the element can be sized to.  The default
+     *    value is -1, which means no maximum.
+     * maxHeight - the maximum height that the element can be sized to.  The
+     *    default value is -1, which means no maximum.
+     */
+    initialize: function(domObj, options) {
+        options = options || {};
+        this.options = new Jx.Constraint(options);
+        this.domObj = $(domObj);
+        this.domObj.resize = this.resize.bind(this);
+        this.domObj.style.position = this.options.position;
+        this.domObj.jxLayout = this;
+
+        if (this.domObj.parentNode && this.domObj.parentNode.tagName == 'BODY') {
+            Event.observe(window, 'resize', this.windowResize.bind(this));
+        }
+        
+        this.scl = [];
+    },
+    
+    /**
+     * Method: windowResize
+     * when the window is resized, any Jx.Layout controlled elements that are
+     * direct children of the BODY element are resized
+     */
+     windowResize: function() {
+        if (this.resizeTimer) {
+            window.clearTimeout(this.resizeTimer);
+            this.resizeTimer = null;
+        }
+        this.resizeTimer = window.setTimeout(this.resize.bind(this), 250);
+    },
+    
+    /**
+     * Method: resize
+     * resize the element controled by this Jx.Layout object.
+     *
+     * Parameters:
+     * options - new options to apply, see <Jx.Layout::Jx.Layout>
+     */
+     resize: function(options) {
+        this.resizeTimer = null;
+        var needsResize = false;
+        if (options) {
+            for (var i in options) {
+                if (this.options[i] != options[i]) {
+                    needsResize = true;
+                    this.options[i] = options[i];
+                }
+            }
+            if (options.forceResize) {
+                needsResize = true;
+            }
+        }
+        
+        
+        var parentSize;
+        if (this.domObj.parentNode.tagName == 'BODY') {
+            parentSize = Element.getPageDimensions();
+        } else {
+            parentSize = Element.getContentBoxSize(this.domObj.parentNode);
+        }
+        
+        if (this.lastParentSize && !needsResize) {
+            needsResize = (this.lastParentSize.width != parentSize.width || 
+                          this.lastParentSize.height != parentSize.height);
+        } else {
+            needsResize = true;
+        }
+        this.lastParentSize = parentSize;
+        
+        if (!needsResize) {
+            return;
+        }
+        
+        var l, t, w, h;
+        
+        /* calculate left and width */
+        if (this.options.left != null) {
+            /* fixed left */
+            l = this.options.left;
+            if (this.options.right == null) {
+                /* variable right */
+                if (this.options.width == null) {
+                    //console.log( 'fixed left, variable right, variable width' );
+                    /* variable right and width
+                     * set right to min, stretch width */
+                    w = parentSize.width - l;
+                    if (w < this.options.minWidth ) {
+                        w = this.options.minWidth;
+                    }
+                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
+                        w = this.options.maxWidth;
+                    }
+                } else {
+                    //console.log( 'fixed left, variable right, fixed width' );
+                    /* variable right, fixed width
+                     * use width
+                     */
+                    w = this.options.width;
+                }
+            } else {
+                /* fixed right */
+                if (this.options.width == null) {
+                    //console.log( 'fixed left, fixed right, variable width' );
+                    
+                    /* fixed right, variable width
+                     * stretch width
+                     */
+                    w = parentSize.width - l - this.options.right;
+                    if (w < this.options.minWidth) {
+                        w = this.options.minWidth;
+                    }
+                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
+                        w = this.options.maxWidth;
+                    }
+                } else {
+                    //console.log( 'fixed left, fixed right, fixed width' );
+                    
+                    /* fixed right, fixed width
+                     * respect left and width, allow right to stretch
+                     */
+                    w = this.options.width;
+                }
+            }
+            
+        } else {
+            if (this.options.right == null) {
+                if (this.options.width == null) {
+                    //console.log( 'variable left, variable right, variable width' );
+                    
+                    /* variable left, width and right
+                     * set left, right to min, stretch width
+                     */
+                     l = 0;
+                     w = parentSize.width;
+                     if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
+                         l = l + parseInt(w - this.options.maxWidth)/2;
+                         w = this.options.maxWidth;
+                     }
+                } else {
+                    //console.log( 'variable left, variable right, fixed width' );
+                    
+                    /* variable left, fixed width, variable right
+                     * distribute space between left and right
+                     */
+                    w = this.options.width;
+                    l = parseInt((parentSize.width - w)/2);
+                    if (l < 0) {
+                        l = 0;
+                    }
+                }
+            } else {
+                if (this.options.width != null) {
+                    //console.log( 'variable left, fixed right, fixed width' );
+                    
+                    /* variable left, fixed width, fixed right
+                     * left is calculated directly
+                     */
+                    w = this.options.width;
+                    l = parentSize.width - w - this.options.right;
+                    if (l < 0) {
+                        l = 0;
+                    }
+                } else {
+                    //console.log( 'variable left, fixed right, variable width' );
+                    
+                    /* variable left and width, fixed right
+                     * set left to min value and stretch width
+                     */
+                    l = 0;
+                    w = parentSize.width - this.options.right;
+                    if (w < this.options.minWidth) {
+                        w = this.options.minWidth;
+                    }
+                    if (this.options.maxWidth >= 0 && w > this.options.maxWidth) {
+                        l = w - this.options.maxWidth - this.options.right;
+                        w = this.options.maxWidth;                        
+                    }
+                }
+            }
+        }
+        
+        /* calculate the top and height */
+        if (this.options.top != null) {
+            /* fixed top */
+            t = this.options.top;
+            if (this.options.bottom == null) {
+                /* variable bottom */
+                if (this.options.height == null) {
+                    //console.log( 'fixed top, variable bottom, variable height' );
+                    
+                    /* variable bottom and height
+                     * set bottom to min, stretch height */
+                    h = parentSize.height - t;
+                    if (h < this.options.minHeight) {
+                        h = this.options.minHeight;
+                    }
+                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
+                        h = this.options.maxHeight;
+                    }
+                } else {
+                    //console.log( 'fixed top, variable bottom, fixed height' );
+                    
+                    /* variable bottom, fixed height
+                     * stretch height
+                     */
+                    h = this.options.height;
+                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
+                        t = h - this.options.maxHeight;
+                        h = this.options.maxHeight;
+                    }
+                }
+            } else {
+                /* fixed bottom */
+                if (this.options.height == null) {
+                    //console.log( 'fixed top, fixed bottom, variable height' );
+                    
+                    /* fixed bottom, variable height
+                     * stretch height
+                     */
+                    h = parentSize.height - t - this.options.bottom;
+                    if (h < this.options.minHeight) {
+                        h = this.options.minHeight;
+                    }
+                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
+                        h = this.options.maxHeight;
+                    }                
+                } else {
+                    //console.log( 'fixed top, fixed bottom, fixed height' );
+                    
+                    /* fixed bottom, fixed height
+                     * respect top and height, allow bottom to stretch
+                     */
+                    h = this.options.height;
+                }
+            }
+            
+        } else {
+            if (this.options.bottom == null) {
+                if (this.options.height == null) {
+                    //console.log( 'variable top, variable bottom, variable height' );
+                    
+                    /* variable top, height and bottom
+                     * set top, bottom to min, stretch height
+                     */
+                     t = 0;
+                     h = parentSize.height;
+                     if (h < this.options.minHeight) {
+                         h = this.options.minHeight;
+                     }
+                     if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
+                         t = parseInt((parentSize.height - this.options.maxHeight)/2);
+                         h = this.options.maxHeight;
+                     }
+                } else {
+                    //console.log( 'variable top, variable bottom, fixed height' );
+                    
+                    /* variable top, fixed height, variable bottom
+                     * distribute space between top and bottom
+                     */
+                    h = this.options.height;
+                    t = parseInt((parentSize.height - h)/2);
+                    if (t < 0) {
+                        t = 0;
+                    }
+                }
+            } else {
+                if (this.options.height != null) {
+                    //console.log( 'variable top, fixed bottom, fixed height' );
+                    
+                    /* variable top, fixed height, fixed bottom
+                     * top is calculated directly
+                     */
+                    h = this.options.height;
+                    t = parentSize.height - h - this.options.bottom;
+                    if (t < 0) {
+                        t = 0;
+                    }
+                } else {
+                    //console.log( 'variable top, fixed bottom, variable height' );
+                    
+                    /* variable top and height, fixed bottom
+                     * set top to min value and stretch height
+                     */
+                    t = 0;
+                    h = parentSize.height - this.options.bottom;
+                    if (h < this.options.minHeight) {
+                        h = this.options.minHeight;
+                    }
+                    if (this.options.maxHeight >= 0 && h > this.options.maxHeight) {
+                        t = parentSize.height - this.options.maxHeight - this.options.bottom;
+                        h = this.options.maxHeight;
+                    }
+                }
+            }
+        }
+                
+        this.domObj.style.position = this.options.position;
+        if (this.options.position == 'absolute') {
+            var padding = Element.getPaddingSize(this.domObj.parentNode);
+        
+            this.domObj.style.left = (l+padding.left) + 'px';
+            this.domObj.style.top = (t+padding.top) + 'px';
+            Element.setBorderBoxSize(this.domObj, {width: w, height: h} );
+        } else {
+            var sizeOpts = {width: w};
+            if (this.options.height) {
+                sizeOpts.height = this.options.height;
+            }
+            Element.setBorderBoxSize(this.domObj, sizeOpts);
+        }
+        
+        var o = {forceResize: options ? options.forceResize : false};
+        for (var i=0; i<this.domObj.childNodes.length; i++) {
+            var c = this.domObj.childNodes[i];
+            if (c.resize) {
+                c.resize(o);
+            }
+        }
+        this.processEvent(this.scl,'sizeChanged',this);
+    },
+    /**
+     * Method: addSizeChangeListener
+     * add a size change listener to be notified when the size of the
+     * element changes.
+     *
+     * Parameters:
+     * obj - {Object} a size change listener
+     */
+     addSizeChangeListener: function(obj){this.addListener(this.scl, obj);},
+    /**
+     * Method: removeSizeChangeListener
+     * remove a size change listener 
+     *
+     * Parameters:
+     * obj - {Object} a size change listener
+     */
+     removeSizeChangeListener: function(o) {
+        this.removeListener(this.scl, o);
+    }
+};
+Object.extend(Jx.Layout.prototype, Jx.Listener.prototype);
+
+/**
+ * Class: Jx.Constraint
+ * A utility class used with <Jx.Layout> to represent the current
+ * set of constraints on an element.  This object is not intended
+ * to be instantiated directly by a user
+ */
+Jx.Constraint = Class.create();
+Jx.Constraint.prototype = {
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    top: 0,
+    bottom: 0,
+    width: null,
+    height: null,
+    minWidth: 0,
+    minHeight: 0,
+    maxWidth: -1,
+    maxHeight: -1,
+    initialize: function(o) {
+        for( var i in o ) {
+            this[i] = o[i];
+        }
+    }
+};/**
+ * $Id: jxmenu.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Menu
+ *
+ * Purpose: 
+ * Implementation of a javascript menuing system for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+
+ Jx.addStyleSheet('menu/menu.css');
+ Jx.addStyleSheet('button/button.css');
+
+/**
+ * Class: Jx.MenuItem
+ * A menu item is a single entry in a menu.  It is typically composed of
+ * a label and an optional icon.  Selecting the menu item triggers an
+ * action.
+ */
+Jx.MenuItem = Class.create();
+Object.extend(Jx.MenuItem.prototype, Jx.Listener.prototype);
+Object.extend(Jx.MenuItem.prototype, {
+    /**
+     * Property: al
+     * {Array} action listeners
+     */
+    al: null,
+    /**
+     * Property: domObj
+     * {HTMLElement} the HTML element for this menu item.
+     */
+    domObj: null,
+    /**
+     * Property: parent
+     * {<Jx.SubMenu> or <Jx.Menu>} the menu that contains the menu item.
+     */
+    parent: null,
+    /**
+     * Property: enabled
+     * {Boolean} whether the menu item is enabled or not
+     */
+    enabled: false,
+    /**
+     * Property: button
+     * {<Jx.Button>} the clickable part of the menu item is managed as a
+     * <Jx.Button>
+     */
+    button: null,
+    /**
+     * Constructor: Jx.MenuItem
+     * Create a new instance of Jx.MenuItem
+     *
+     * Parameters:
+     * action - {<Jx.Action>} the action to invoke when the menu item is
+     *          invoked
+     * options - {Object} an object containing options as below.
+     * 
+     * Options:
+     * image - {String} URL to an image to use as an icon on this menu item
+     * label - {String} the label for the menu item.
+     */
+    initialize: function(action, options) {
+        this.initializeItem(options);
+        action.bindTo(this);
+        this.propertyChanged(action);
+    },
+    /**
+     * Method: initializeItem
+     * Internal method to initalize the button for this menu item.
+     *
+     * Parameters:
+     * options - {Object} an object containing options as below.
+     *
+     * Options:
+     * image - {String} URL to an image to use as an icon on this menu item
+     * label - {String} the label for the menu item.     */
+    initializeItem: function(options) { 
+        if (!options.image) {
+            options.image = Jx.baseURL + 'images/a_pixel.png';
+        }
+        if (!options.label) {
+            options.label = '&nbsp;';
+        }
+        this.label = options.label || '&nbsp;';
+        this.image = options.image || null;
+        
+        this.al = [];
+        this.domObj = document.createElement('li');
+        this.domObj.className = 'jxMenuItem';
+        
+        /* menu items are buttons without the jxButton class */
+        var action = new Jx.Action(this.processActionEvent.bindAsEventListener(this))
+        this.button = new Jx.Button(action, options);
+        //Element.removeClassName(this.button.domA, 'jxButton');
+        
+        Event.observe(this.button.domObj, 'mouseover', this.onmouseover.bindAsEventListener(this), true);
+        
+        this.domObj.appendChild(this.button.domObj);
+    },
+    /**
+     * Method: setParent
+     * Set the parent of this menu item
+     *
+     * Parameters:
+     * obj - {Object} the new parent
+     */
+    setParent: function(obj) {
+        this.parent = obj;
+    },
+    /**
+     * Method: hide
+     * Hide the menu item.
+     */
+    hide: function() {},
+    /**
+     * Method: show
+     * Show the menu item
+     */
+    show: function() {},
+    /**
+     * Method: addActionListener
+     * Add an action listener to this menu item
+     *
+     * Parameters:
+     * obj - {Object} the action listener
+     */
+    addActionListener: function(obj) { this.addListener(this.al,obj); },
+    /**
+     * Method: removeActionListener
+     * Remove an action listener from this menu item
+     *
+     * Parameters:
+     * obj - {Object} the action listener
+     */
+    removeActionListener : function(obj) { this.removeListener(this.al, obj); },
+    /**
+     * Method: processActionEvent
+     * Process an action event by informing any action listeners that the action
+     * associated with this menu item and hiding the menu.
+     *
+     * Parameters:
+     * e - {Event} the event associated with the user clicking on the menu item
+     */
+    processActionEvent: function(e) { 
+        if (this.enabled) {
+            this.processEvent(this.al, 'actionPerformed', this);
+            if (this.parent && this.parent.deactivate) {
+                this.parent.deactivate(e);
+            }
+        }
+    },
+    /**
+     * Method: propertyChanged
+     * Track when a property of the action changes and update the state of the
+     * menu item accordingly.
+     *
+     * Parameters:
+     * obj - {<Jx.Action>} the action object
+     */
+    propertyChanged: function(obj) {
+        this.enabled = obj.isEnabled();
+        if (this.enabled) {
+            Element.removeClassName( this.domObj.childNodes[0].childNodes[0], 'jxDisabled' );
+        } else {
+            Element.addClassName( this.domObj.childNodes[0].childNodes[0], 'jxDisabled' );
+        }
+    },
+    /**
+     * Method: onmouseover
+     * handle the mouse moving over the menu item
+     *
+     * Parameters:
+     * e - {Event} the mousemove event
+     */
+    onmouseover: function(e) {
+        var target = Event.element(e);
+        if (this.parent && this.parent.setVisibleItem) {
+            this.parent.setVisibleItem(this);
+        }
+        this.show();
+    }
+});
+
+/**
+ * Class: Jx.MenuSeparator
+ * A convenience class to create a visual separator in a menu.
+ */
+Jx.MenuSeparator = Class.create();
+Object.extend(Jx.MenuSeparator.prototype, {
+    /**
+     * Property: domObj
+     * {HTMLElement} the HTML element that the separator is contained
+     * within
+     */
+    domObj: null,
+    /**
+     * Property: parent
+     * {<Jx.Menu>, <Jx.SubMenu>} the menu that the separator is in.
+     */
+    parent: null,
+    /**
+     * Constructor: Jx.MenuSeparator
+     * Create a new instance of a menu separator
+     */
+    initialize: function() {
+        this.domObj = document.createElement('li');
+        this.domObj.className = 'jxMenuItem';
+        var span = document.createElement('span');
+        span.className = 'jxMenuSeparator';
+        span.innerHTML = '&nbsp;';
+        this.domObj.appendChild(span);
+    },
+    /**
+     * Method: setParent
+     * Set the parent of this menu item
+     *
+     * Parameters:
+     * obj - {Object} the new parent
+     */
+    setParent: function(obj) {
+        this.parent = obj;
+    },
+    /**
+     * Method: hide
+     * Hide the menu item.
+     */
+    hide: function() {},
+    /**
+     * Method: show
+     * Show the menu item
+     */
+    show: function() {}
+});
+
+/**
+ * Class: Jx.SubMenu
+ * A sub menu contains menu items within a main menu or another
+ * sub menu.
+ *
+ * Inherits From:
+ * <Jx.MenuItem>
+ */
+Jx.SubMenu = Class.create();
+Object.extend(Jx.SubMenu.prototype, Jx.MenuItem.prototype);
+Object.extend(Jx.SubMenu.prototype, {
+    /**
+     * Property: subDomObj
+     * {HTMLElement} the HTML container for the sub menu.
+     */
+    subDomObj: null,
+    /**
+     * Property: parent
+     * {<Jx.Menu> or <Jx.SubMenu>} the menu or sub menu that this sub menu
+     * belongs
+     */
+    parent: null,
+    /**
+     * Property: visibleItem
+     * {<Jx.MenuItem>} the visible item within the menu
+     */
+    visibleItem: null,
+    /**
+     * Property: items
+     * {Array} the menu items that are in this sub menu.
+     */
+    items: null,
+    /**
+     * Constructor: Jx.SubMenu
+     * Create a new instance of Jx.SubMenu
+     *
+     * Parameters:
+     * options - see <Jx.MenuItem::Jx.MenuItem>
+     */
+    initialize: function(options) { 
+        this.open = false;
+        this.items = [];
+        this.initializeItem(options);
+        Element.addClassName(this.domObj.childNodes[0].childNodes[0], 'jxButtonSubMenu');
+        
+        this.iframe = document.createElement('iframe');
+        this.iframe.className = 'jxMenuShim';
+        this.iframe.scrolling = 'no';
+        this.iframe.frameborder = 0;
+        
+        this.subDomObj = document.createElement('ul');
+        this.subDomObj.className = 'jxSubMenu';
+        this.subDomObj.style.display = 'none';
+        
+        // this.button.domObj.appendChild(this.subDomObj);
+        this.domObj.appendChild(this.subDomObj);
+    },
+    /**
+     * Method: setParent
+     * Set the parent of this sub menu
+     *
+     * Parameters:
+     * obj - {Object} the parent
+     */
+    setParent: function(obj) {
+        this.parent = obj;
+    },
+    /**
+     * Method: show
+     * Show the sub menu
+     */
+    show: function() {
+        if (this.open || this.items.length == 0) {
+            return;
+        }
+
+        this.open = true;
+        this.subDomObj.style.display = 'block';
+        if (!window.opera) {
+            this.subDomObj.childNodes[0].appendChild(this.iframe);
+            var size = Element.getBorderBoxSize(this.subDomObj);
+            this.iframe.style.width = size.width + "px";
+            this.iframe.style.height = size.height + "px";
+            
+        }
+        this.setActive(true);
+    },
+    /**
+     * Method: hide
+     * Hide the sub menu
+     */
+    hide: function() {
+        if (!this.open) {
+            return;
+        }
+        this.open = false;
+        for (var i=0; i<this.items.length; i++) {
+            this.items[i].hide();
+        }
+        this.subDomObj.style.display = 'none';
+        if (!window.opera && this.iframe.parentNode) {
+            this.subDomObj.childNodes[0].removeChild(this.iframe);
+        }
+        this.visibleItem = null;
+    },
+    /**
+     * Method: add
+     * Add menu items to the sub menu.
+     *
+     * Parameters:
+     * item - {<Jx.MenuItem>} the menu item to add.  Multiple menu items
+     * can be added by passing multiple arguments to this function.
+     */
+    add : function() { /* menu */
+        for (var i=0; i<arguments.length; i++) {
+            var item = arguments[i];
+            this.items.push(item);
+            item.setParent(this);
+            this.subDomObj.appendChild(item.domObj);
+        }
+    },
+    /**
+     * Method: insertBefore
+     * Insert a menu item before another menu item.
+     *
+     * Parameters:
+     * newItem - {<Jx.MenuItem>} the menu item to insert
+     * targetItem - {<Jx.MenuItem>} the menu item to insert before
+     */
+    insertBefore: function(newItem, targetItem) {
+        var bInserted = false;
+        for (var i=0; i<this.items.length; i++) {
+            if (this.items[i] == targetItem) {
+                this.items.splice(i, 0, newItem);
+                this.subDomObj.insertBefore(newItem.domObj, targetItem.domObj);
+                bInserted = true;
+                break;
+            }
+        }
+        if (!bInserted) {
+            this.add(newItem);
+        }
+    },
+    /**
+     * Method: remove
+     * Remove a single menu item from the menu.
+     *
+     * Parameters:
+     * item - {<Jx.MenuItem} the menu item to remove.
+     */
+    remove: function(item) {
+        for (var i=0; i<this.items.length; i++) {
+            if (this.items[i] == item) {
+                this.items.splice(i,1);
+                this.subDomObj.removeChild(item.domObj);
+                break;
+            }
+        }
+    },
+    /**
+     * Method: processActionEvent
+     * Process an action event coming from the menu item that
+     * represents the sub menu in its parent by showing or hiding
+     * the sub menu.
+     */
+    processActionEvent: function(e) { 
+        if (this.open) { 
+            this.hide(); 
+        } else { 
+            this.show();
+        }
+        return Event.stop(e);
+    },
+    /**
+     * Method: deactivate
+     * Deactivate the sub menu
+     *
+     * Parameters:
+     * e - {Event} the event that triggered the menu being
+     * deactivated.
+     */
+    deactivate: function(e) {
+        if (this.parent) {
+            this.parent.deactivate(e);            
+        }
+    },
+    /**
+     * Method: isActive
+     * Indicate if this sub menu is active
+     *
+     * Returns:
+     * {Boolean} true if the <Jx.Menu> that ultimately contains
+     * this sub menu is active, false otherwise.
+     */
+    isActive: function() { 
+        if (this.parent) {
+            return this.parent.isActive();
+        } else {
+            return false;
+        }
+    },
+    /**
+     * Method: setActive
+     * Set the active state of the <Jx.Menu> that contains this sub menu
+     *
+     * Parameters:
+     * isActive - {Boolean} the new active state
+     */
+    setActive: function(isActive) { 
+        if (this.parent && this.parent.setActive) {
+            this.parent.setActive(isActive);
+        }
+    },
+    /**
+     * Method: setVisibleItem
+     * Set a sub menu of this menu to be visible and hide the previously
+     * visible one.
+     *
+     * Parameters: 
+     * obj - {<Jx.SubMenu>} the sub menu that should be visible
+     */
+    setVisibleItem: function(obj) {
+        if (this.visibleItem != obj) {
+            if (this.visibleItem && this.visibleItem.hide) {
+                this.visibleItem.hide();
+            }
+            this.visibleItem = obj;
+            this.visibleItem.show();
+        }
+    }
+});
+
+/**
+ * Class: Jx.Menu
+ * A main menu as opposed to a sub menu that lives inside the menu.
+ *
+ * TODO: Jx.Menu
+ * revisit this to see if Jx.Menu and Jx.SubMenu can be merged into
+ * a single implementation.
+ */
+Jx.Menu = Class.create();
+Jx.Menu.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} The HTML element containing the menu.
+     */
+    domObj : null,
+    /**
+     * Property: buttonObj
+     * {<Jx.Button>} The button that represents this menu in a toolbar and
+     * opens the menu.
+     */
+    buttonObj : null,
+    /**
+     * Property: subDomObj
+     * {HTMLElement} the HTML element that contains the menu items
+     * within the menu.
+     */
+    subDomObj : null,
+    /**
+     * Property: items
+     * {Array} the items in this menu
+     */
+    items : null,
+    /**
+     * Property: menus
+     * {Array} Class variable that contains a reference to all
+     * menus shared by all menu instances.
+     */
+    menus : [],
+    /**
+     * Constructor: Jx.Menu
+     * Create a new instance of Jx.Menu.
+     *
+     * Parameters:
+     * options - {Object} an options object passed directly to the
+     * <Jx.Button> when creating the button that triggers this menu.
+     * If options is not passed, then no button is created.
+     */
+    initialize : function(options) {
+        /* stores menu items and sub menus */
+        this.items = [];
+        
+        /* iframe shim to prevent scrollbars and 
+           inputs from showing through the menu */
+        this.iframe = document.createElement('iframe');
+        this.iframe.className = 'jxMenuShim';
+        this.iframe.scrolling = 'no';
+        this.iframe.frameborder = 0;
+        
+        /* the DOM element that holds the actual menu */
+        this.subDomObj = document.createElement('ul');
+        this.subDomObj.className = 'jxMenu';
+        this.subDomObj.style.display = 'none';
+        
+        /* if options are passed, make a button inside an LI so the
+           menu can be embedded inside a toolbar */
+        if (options) {
+            this.domObj = document.createElement('li');
+            
+            var action = new Jx.Action(this.show.bind(this));
+            this.button = new Jx.Button(action, options);
+            Element.addClassName(this.button.domObj.firstChild, 'jxButtonMenu');
+            this.domObj.appendChild(this.button.domObj);
+        
+            Event.observe(this.domObj, 'mouseover', this.onMouseOver.bindAsEventListener(this));
+            //this.button.domObj.appendChild(this.subDomObj);
+            this.domObj.appendChild(this.subDomObj);
+        }
+        
+        /* pre-bind the hide function for efficiency */
+        this.hideWatcher = this.hide.bindAsEventListener(this);
+    },
+    /**
+     * Method: add
+     * Add menu items to the sub menu.
+     *
+     * Parameters:
+     * item - {<Jx.MenuItem>} the menu item to add.  Multiple menu items
+     * can be added by passing multiple arguments to this function.
+     */
+    add : function() {
+        for (var i=0; i<arguments.length; i++) {
+            var item = arguments[i];
+            this.items.push(item);
+            item.setParent(this);
+            this.subDomObj.appendChild(item.domObj);
+        }
+    },
+    /**
+     * Method: deactivate
+     * Deactivate the menu by hiding it.
+     */
+    deactivate: function() { this.hide(); },
+    /**
+     * Method: actionPerformed
+     * Any action performed in the menu ultimately calls this
+     * method to hide the menu.
+     */
+    actionPerformed : function() {this.hide();},
+    /**
+     * Method: onMouseOver
+     * Handle the user moving the mouse over the button for this menu
+     * by showing this menu and hiding the other menu.
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    onMouseOver: function(e) {
+        if (this.menus[0] && this.menus[0] != this) {
+            this.show(e);
+        }
+    },
+    /**
+     * Method: hide
+     * Hide the menu.
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    hide: function(e) {
+        if (e) {
+            var root = Event.findElement(e, 'LI');
+            if (root == this.domObj) {
+                return;
+            }
+        }
+        if (this.menus[0] && this.menus[0] == this) {
+            this.menus[0] = null;
+        }
+        for (var i=0; i<this.items.length; i++) {
+            this.items[i].hide(e);
+        }
+        Event.stopObserving(document, 'click', this.hideWatcher, true);
+        this.subDomObj.style.display = 'none';  
+    },
+    /**
+     * Method: show
+     * Show the menu
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    show : function(e) {
+        if (this.menus[0] && this.menus[0] != this) {
+            this.menus[0].hide(e);
+        }
+        if (this.items.length ==0) {
+            return;
+        }
+        this.menus[0] = this;
+        this.subDomObj.style.display = 'block';
+        this.subDomObj.style.visibility = 'visible';
+        
+        if (!window.opera) {
+            this.subDomObj.childNodes[0].appendChild(this.iframe);
+            var size = Element.getContentBoxSize(this.subDomObj);
+            this.iframe.style.width = size.width + "px";
+            this.iframe.style.height = size.height + "px";
+        }
+        Event.stop(e);
+        /* fix bug in IE that closes the menu as it opens because of bubbling */
+        Event.observe(document, 'click', this.hideWatcher, true);
+    },
+    /**
+     * Method: setVisibleItem
+     * Set the sub menu that is currently open
+     *
+     * Parameters:
+     * obj- {<Jx.SubMenu>} the sub menu that just became visible
+     */
+    setVisibleItem: function(obj) {
+        if (this.visibleItem != obj) {
+            if (this.visibleItem && this.visibleItem.hide) {
+                this.visibleItem.hide();
+            }
+            this.visibleItem = obj;
+            this.visibleItem.show();
+        }
+    }
+};
+
+/**
+ * Class: Jx.ContextMenu
+ * A <Jx.Menu> that has no button but can be opened at a specific 
+ * browser location to implement context menus (for instance).
+ *
+ * Inherits From:
+ * <Jx.Menu>
+ */
+Jx.ContextMenu = Class.create();
+Object.extend(Jx.ContextMenu.prototype, Jx.Menu.prototype);
+Object.extend(Jx.ContextMenu.prototype, {
+    /**
+     * Constructor: Jx.ContextMenu
+     * create a new context menu
+     *
+     * Parameters:
+     * id - {HTMLElement} element or id to make this the context menu
+     * for.  The menu hooks the oncontextmenu event of the element
+     * and shows itself at the mouse position where the right-click
+     * happened.
+     */
+    initialize : function(id) {
+        Jx.Menu.prototype.initialize.apply(this, []);
+        document.getElementsByTagName('BODY')[0].appendChild(this.subDomObj);
+        if ($(id)) {
+            $(id).oncontextmenu = this.show.bindAsEventListener(this);;
+        }
+    },
+    /**
+     * Method: show
+     * Show the context menu at the location of the mouse click
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    show : function(e) {
+        this.subDomObj.style.left = Event.pointerX(e) + "px";
+        this.subDomObj.style.top = Event.pointerY(e) + "px";
+        Jx.Menu.prototype.show.apply(this, [e]);
+    }
+});/**
+ * $Id: jxpanel.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Panel
+ *
+ * Purpose: 
+ * Implementation of a javascript panels for Jx.  Panels are vertically 
+ * oriented areas that can be resized by the user dragging the panel title
+ * bar.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+Jx.addStyleSheet('panel/panel.css');
+
+/**
+ * Class: Jx.PanelManager
+ * A panel manager manages a set of panels within a DOM element.
+ */
+Jx.PanelManager = Class.create();
+Jx.PanelManager.prototype = {
+    /**
+     * Property: panels
+     * {Array} the panels being managed by the manager
+     */
+    panels: null,
+    /**
+     * Property: height
+     * {Integer} the height of the container, cached for speed
+     */
+    height: null,
+    /**
+     * Property: firstLayout
+     * {Boolean} true until the panel manager has first been resized
+     */
+    firstLayout: true,
+    /**
+     * Constructor: Jx.PanelManager
+     * Create a new instance of Jx.PanelManager.
+     *
+     * Parameters:
+     * domObj - {HTMLElement} the HTML element that will contain the panels
+     * panels - {Array} the panels to go into the PanelManager
+     *
+     * TODO: Jx.PanelManager.initialize
+     * Remove the panels parameter in favour of an add method.
+     */
+    initialize: function(domObj, panels) {
+        this.domObj = $(domObj);
+        this.panels = panels;
+        var d = document.createElement('div');
+        d.style.position = 'absolute';
+        new Jx.Layout(d, {minHeight:0,maxHeight:0,height:0});
+        var elements = [d];
+        for (var i=0; i<this.panels.length; i++) {
+            elements.push(this.panels[i].domObj);
+        }
+        this.splitter = new Jx.Splitter(this.domObj, {splitInto: panels.length+1,
+                                                     layout: 'vertical',
+                                                     elements: elements });
+        /* redirect splitter sizeChanged so we can capture the first time the
+         * splitter is layed out in the client in a way that we can measure
+         * the title bar heights
+         */
+        this.splitter.sizeChanged = this.sizeChanged.bind(this);
+        /* create the bars for the panel manager */
+        for (var i=0; i<this.panels.length; i++) {
+            var panel = this.panels[i];
+            this.splitter.bars[i].appendChild(panel.title);
+            this.splitter.bars[i].style.height = Element.getBorderBoxSize(panel.title).height + 'px';
+            Element.removeClassName(this.splitter.bars[i], 'jxSplitterBar');
+            Element.addClassName(this.splitter.bars[i], 'jxPanelBar');
+            panel.manager = this;
+        }
+    },
+    /**
+     * Method: sizeChanged
+     * called when the size of the container of the splitter changes.  This tracks the
+     * first time the panel titles have a non-zero height (i.e. they are put in the
+     * DOM and are visible) and recalculates the panel title height then.
+     */ 
+    sizeChanged: function() {
+        if (this.firstLayout) {
+            if (Element.getBorderBoxSize(this.panels[0].title).height != 0) {
+                for (var i=0; i<this.splitter.bars.length; i++) {
+                    var panel = this.panels[i];
+                    this.splitter.bars[i].style.height = Element.getBorderBoxSize(panel.title).height + 'px';
+                    this.splitter.bars[i].size = null;
+                }
+                this.firstLayout = false;
+                Jx.Splitter.prototype.sizeChanged.apply(this.splitter, []);            
+            }
+        } else {
+            Jx.Splitter.prototype.sizeChanged.apply(this.splitter, []);            
+        }
+    },
+    
+    /**
+     * Method: maximizePanel
+     * Maximize the panel, taking up all available space (taking into
+     * consideration any minimum or maximum values)
+     */
+    maximizePanel: function(panel) {
+        var h = Element.getContentBoxSize(this.domObj).height;
+        
+        var t = 0;
+        for (var i=1; i<this.splitter.elements.length; i++) {
+            var p = this.splitter.elements[i];
+            t += Element.getBorderBoxSize(p.leftBar).height;
+            if (p !== panel.domObj) {
+                p.jxLayout.resize({top: t, height: p.jxLayout.options.minHeight, bottom: null});                    
+                t += p.jxLayout.options.minHeight;
+                p.rightBar.style.top = t + 'px';
+            } else {
+                break;
+            }
+        }
+        
+        b = h;
+        for (var i=this.splitter.elements.length - 1; i > 0; i--) {
+            p = this.splitter.elements[i];
+            if (p !== panel.domObj) {
+                b -= p.jxLayout.options.minHeight;
+                p.jxLayout.resize({top: b, height: p.jxLayout.options.minHeight, bottom: null});
+                b -= Element.getBorderBoxSize(p.leftBar).height;
+                p.leftBar.style.top = b + 'px';
+                
+            } else {
+                break;
+            }
+        }
+        panel.domObj.jxLayout.resize({top: t, height:b - t, bottom: null});
+    }
+};
+
+/**
+ * Class: Jx.Panel
+ * A panel that can be displayed inside a panel manager.
+ */
+Jx.Panel = Class.create();
+Jx.Panel.prototype = {
+    /** 
+     * Property: labelObj
+     * the DOM object that holds the label in the title bar. 
+     */
+    labelObj : null,
+    /**
+     * Property: state
+     * the state of this panel 
+     */
+    state : 'open',
+    /**
+     * Property: busyCount
+     * track the busy state of this panel - used to control a 'loading' image 
+     */
+    busyCount : null,
+    /**
+     * Property: bContentReady
+     * {Boolean} is the content ready to be displayed?
+     */
+    bContentReady : null,
+    /**
+     * Property: onContentReady
+     * {Function} a function to call when the content is ready
+     */
+    onContentReady : null,
+    
+    /** 
+     * Constructor: Jx.Panel
+     * Initialize a new Jx.Panel instance
+     *
+     * Options:
+     *
+     * label - String, the title of the Jx Panel
+     * toolbar - element to use as the toolbar
+     * menubar - element to use as the menu
+     * content - element to use as the content. A content area is created
+     *           if none is provided.  Otherwise, the content element is moved
+     *           in the DOM
+     * statusbar - element to use as the statusbar
+     * helpCallback - function to call when the user clicks the contextual help button
+     * state - initial state of the panel (open or closed)
+     *
+     * Inherits From:
+     * <Jx.UniqueId>, <Jx.ContentLoader>
+     */
+    initialize : function(options){
+        //console.log("Jx.Panel::initialize('"+options.label+"')");
+        this.initUniqueId();
+        
+        /* set up the title object */
+        this.title = document.createElement('div');
+        this.title.className = "jxPanelTitle";
+        //TODO: Jx.Panel.initialize
+        //Opera is broken because it doesn't report the height of the
+        //title bars at all unless set through javascript
+        //this is a hack until we can figure out from css what the height is
+        this.title.style.height = '22px';
+        
+        this.labelObj = document.createElement('span');
+        this.labelObj.className = 'jxPanelLabel';
+        this.labelObj.innerHTML = options.label?options.label:'empty';
+    
+        this.imageBaseUrl = options.imageBaseUrl || Jx.baseURL + 'images/';
+        
+        var a, img;
+        if (options.helpCallback) {
+            a = document.createElement('a');
+            a.className = 'jxPanelHelp';
+            a.href = 'javascript:void(0)';
+            Event.observe(a, 'click', options.helpCallback);
+            img = document.createElement('img');
+            img.src = this.imageBaseUrl + "help.png";
+            img.alt = 'Help on this panel';
+            img.title = 'Help on this panel';
+            a.appendChild(img);
+            this.title.appendChild(a);
+        }
+    
+        a = document.createElement('a');
+        a.className = 'jxPanelMaximize';
+        a.href = 'javascript:void(0)';
+        Event.observe(a, 'click', this.maximize.bindAsEventListener(this));
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + "maximize.png";
+        img.alt = 'Maximize Panel';
+        img.title = 'Maximize Panel';
+        a.appendChild(img);
+        this.title.appendChild(a);
+    
+        a = document.createElement('a');
+        a.className = 'jxPanelLoading';
+        a.href = 'javascript:void(0)';
+        img = document.createElement('img');
+        img.src = this.imageBaseUrl + "loading.gif";
+        img.alt = 'Loading Panel';
+        img.title = 'Loading Panel';
+        a.appendChild(img);
+        this.loadingObj = {};
+        this.loadingObj.link = a;
+        this.loadingObj.img = img;
+        this.title.appendChild(this.loadingObj.link);
+        this.title.appendChild(this.labelObj);
+        
+        Event.observe(this.title, 'dblclick', this.maximize.bindAsEventListener(this));
+        
+        this.domObj = document.createElement('div');
+        this.domObj.className = 'jxPanel';
+        
+        this.jxLayout = new Jx.Layout(this.domObj, options.constraint || {});
+        this.jxLayout.addSizeChangeListener(this);
+        
+        var top = 0;
+        var bottom = 0;
+        if (options.menubar) {
+            this.menubar = options.menubar;
+            this.domObj.appendChild(options.menubar);
+            var h = Element.getBorderBoxSize(options.menubar).height;
+            new Jx.Layout(this.menubar, {top: top, height:h});
+            top += h;
+        }
+        if (options.toolbar) {
+            this.toolbar = options.toolbar;
+            this.domObj.appendChild(options.toolbar);
+            var h = Element.getBorderBoxSize(options.toolbar).height;
+            new Jx.Layout(this.toolbar, {top:top, height: h});
+        }
+        
+        if (options.statusbar) {
+            this.statusbar = options.statusbar;
+            this.domObj.appendChild(options.statusbar);
+            var h = Element.getBorderBoxSize(options.statusbar).height;
+            new Jx.Layout(this.statusbar, {bottom: bottom, height: h, top: null});
+            bottom += h;
+        }
+        this.content = document.createElement('div');
+        Element.addClassName(this.content, 'jxPanelContent');
+        new Jx.Layout(this.content, {top: top, bottom: bottom});
+        this.domObj.appendChild(this.content);
+        this.loadContent(this.content, options);
+        
+        this.busyCount = 0;
+        this.bContentReady = false;
+    },
+    /**
+     * Method: setLabel
+     * Set the label in the title bar of this panel
+     *
+     * Parameters:
+     * s - {String} the new label
+     */
+    setLabel: function(s) {
+        this.labelObj.innerHTML = s;
+    },
+    /**
+     * Method: getLabel
+     * Get the label of the title bar of this panel
+     *
+     * Returns: 
+     * {String} the label
+     */
+    getLabel: function() {
+        return this.labelObj.innerHTML;
+    },
+    /**
+     * Method: finalize
+     * Clean up the panel
+     */
+    finalize: function() {
+        this.domObj = null;
+        this.deregisterIds();
+    },
+    /**
+     * Method: maximize
+     * Maximize this panel
+     */
+    maximize: function() {
+        if (this.manager) {
+            this.manager.maximizePanel(this);
+        }
+    },
+    /**
+     * Method: setContent
+     * set the content of this panel to some HTML
+     *
+     * Parameters:
+     * html - {String} the new HTML to go in the panel
+     */
+    setContent : function (html) {
+        //console.log('Jx.Panel::setContent()');
+        this.content.innerHTML = html;
+        this.bContentReady = true;
+    },
+    /**
+     * Method: setContentURL
+     * Set the content of this panel to come from some URL.
+     *
+     * Parameters:
+     * url - {String} URL to some HTML content for this panel
+     */
+    setContentURL : function (url) {
+        this.bContentReady = false;
+        this.setBusy(true);
+        if (arguments[1]) {
+            this.onContentReady = arguments[1];
+        }
+        if (url.indexOf('?') == -1) {
+            url = url + '?';
+        }
+        //var ts = (new Date()).getTime();
+        //url = url + 'ts='+ts;
+        var opts = { method: 'get',
+                     onComplete:this.panelContentLoaded.bind(this),
+                     requestHeaders: ['If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT']};
+        var a = new Ajax.Request( url, opts);
+    },
+    /**
+     * Method: panelContentLoaded
+     * When the content of the panel is loaded from a remote URL, this 
+     * method is called when the ajax request returns.
+     *
+     * Parameters:
+     * r - {XmlHttpRequest} the XmlHttpRequest object
+     */
+    panelContentLoaded: function(r) {
+        this.content.innerHTML = r.responseText;
+        this.bContentReady = true;
+        this.setBusy(false);
+        if (this.onContentReady) {
+            window.setTimeout(this.onContentReady.bind(this),1);
+        }
+    },
+    /**
+     * Method: setBusy
+     * Set the panel as busy or not busy, which displays a loading image
+     * in the title bar.
+     *
+     * Parameters:
+     * isBusy - {Boolean} the busy state
+     */
+    setBusy : function(isBusy) {
+        this.busyCount += isBusy?1:-1;
+        this.loadingObj.img.style.visibility = (this.busyCount>0)?'visible':'hidden';
+    },
+    /**
+     * Method: sizeChanged
+     * handle the size of the container changing by resizing the various
+     * elements of the panel.
+     */
+    sizeChanged: function() {
+        var top = 0;
+        var bottom = 0;
+        if (this.menubar) {
+            this.menubar.style.height = '';
+            var size = Element.getBorderBoxSize(this.menubar);
+            this.menubar.resize({height:size.height});
+            top += size.height;
+        }
+        if (this.toolbar) {
+            this.toolbar.style.height = '';
+            var size = Element.getBorderBoxSize(this.toolbar);
+            this.toolbar.resize({height:size.height});
+            top += size.height;
+        }
+        if (this.statusbar) {
+            this.statusbar.style.height = '';
+            var size = Element.getBorderBoxSize(this.statusbar);
+            this.statusbar.resize({height:size.height});
+            bottom += size.height;
+        }
+        if (top || bottom) {
+            this.content.resize({bottom: bottom, top: top});
+        }               
+    }
+};
+Object.extend(Jx.Panel.prototype, Jx.UniqueId.prototype);
+Object.extend(Jx.Panel.prototype, Jx.ContentLoader.prototype);/**
+ * $Id: jxpicker.js 516 2008-03-10 23:21:04Z pspencer $
+ *
+ * Title: Jx.Picker
+ *
+ * Purpose: 
+ * Implementation of a javascript Pick List for Jx.  This is analagous to an 
+ * HTML select except that it allows other things to be put in the list.  The
+ * selected item from the list can also be editable.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+Jx.addStyleSheet('picker/picker.css');
+
+/**
+ * Class: Jx.Picker
+ * A drop down list of selectable items that can be any HTML.
+ *
+ * Inherits From:
+ * <Jx.Listener>
+ */
+Jx.Picker = Class.create();
+Jx.Picker.prototype = {
+    /** 
+     * Property: sl
+     * {Array} selection listeners 
+     */
+    sl : null,
+    
+    /** 
+     * Property: domObj
+     * {HTMLElement} the div that contains the control, 
+     * used to show/hide the control 
+     */
+    domObj : null,
+    /** 
+     * Property: ul
+     * {HTMLElement} the ul that contains the selectable items 
+     */
+    ul : null,
+    /**
+     * Property: currentSelection
+     * {Object} current selection in the list 
+     */
+    currentSelection : null,
+    
+    /**
+     * Property: isEditable
+     * {Boolean} is the selected item editable? 
+     **/
+    isEditable: false,
+    /** 
+     * Constructor: Jx.Picker
+     * create a new instance of Jx.Picker
+     *
+     * Options:
+     * editable - {Boolean} defaults to false.  If true, then the selected item
+     * is editable.
+     */
+    initialize: function(options) {
+        options = options || {};
+        
+        this.domObj = document.createElement('div');
+        this.domObj.className = 'jxPicker';
+        this.isEditable = options.editable || false;
+        
+        if (this.isEditable) {
+            this.domInput = document.createElement('input');
+            this.domInput.type = 'text';
+            Event.observe(this.domInput, 'change', this.valueChanged.bind(this));
+            Event.observe(this.domInput, 'keydown', this.onKeyPress.bind(this));
+        } else {
+            this.domInput = document.createElement('span');
+        }
+        this.domInput.className = 'jxPickerInput';
+        
+        this.domObj.appendChild(this.domInput);
+        
+        this.domA = document.createElement('a');
+        this.domA.href = 'javascript:void(0)';
+        this.domA.className = 'jxPickerDiscloser';
+        Event.observe(this.domA, 'click', this.toggle.bind(this));
+        
+        this.domButton = document.createElement('img');
+        this.domButton.src = Jx.baseURL + 'images/disclose2.png';
+        Element.addClassName(this.domButton, 'png24');
+        this.domA.appendChild(this.domButton);
+        this.domObj.appendChild(this.domA);
+        
+        if (!window.opera) {
+            //insert iframeShim for IE to cover other controls in the page.
+            var iframe = document.createElement('iframe');
+            iframe.className = 'jxDialogShim';
+            iframe.scrolling = 'no';
+            iframe.frameborder = 0;
+            this.domObj.appendChild(iframe);
+        }
+        
+        this.domListDiv = document.createElement('div');
+        this.domListDiv.className = 'jxPickerOptions';
+        this.domListDiv.style.display = 'none';
+        this.domObj.appendChild(this.domListDiv);
+        this.domList = document.createElement('ul');
+        this.domListDiv.appendChild(this.domList);
+        this.sl = [];
+    },
+    
+    /**
+     * Method: onKeyPress
+     * Handle the user pressing a key by looking for an ENTER key to set the
+     * value.
+     *
+     * Parameters:
+     * e - {Event} the keypress event
+     */
+    onKeyPress: function(e) {
+        var charCode = (e.charCode) ? e.charCode : ((e.keyCode) ? e.keyCode : e.which);
+        if (charCode == Event.KEY_RETURN) {
+            this.valueChanged();
+        }
+    },
+    
+    /**
+     * Method: valueChanged
+     * When the value is changed, propogate the change to the selection 
+     * listeners
+     */
+    valueChanged: function() {
+        this.processEvent(this.sl, 'selectionChanged', this);
+    },
+    
+    /**
+     * Method: add
+     * add a new item to the pick list
+     *
+     * Parameters:
+     * domObj - {HTMLElement} the element to add
+     * idx - {Integer} the index to add the element add
+     */
+    add: function(domObj, idx) {
+        var li = document.createElement('li');
+        var a = document.createElement('a');
+        a.href="javascript:void(0)";
+        
+        if (typeof(domObj) == 'string') {
+            a.innerHTML = domObj;
+        } else {
+            a.appendChild(domObj);
+        }
+        Event.observe(a, 'click', this.pick.bindAsEventListener(this));
+        li.appendChild(a);
+
+        if (arguments.length > 1 && this.domList.childNodes.length > idx) {
+            this.domList.insertBefore(li, this.domList.childNodes[idx]);
+        } else {
+            this.domList.appendChild(li);
+        }
+        if (this.getValue() == '') {
+            this.setValue(a.childNodes[0]);
+        }
+    },
+    
+    /**
+     * Method: remove
+     * Remove the item at the given index
+     *
+     * Parameters:
+     * idx - {Integer} the item to remove.
+     */
+    remove: function(idx) {
+        if (idx > 0 && idx < this.domList.childNodes.length) {
+            this.domList.removeChild(this.domList.childNodes[idx]);
+        }
+    },
+    
+    /**
+     * Method: pick
+     * user has clicked something in the list, select it
+     *
+     * Parameters:
+     * e - {Event} the mouse event from the user's click
+     */
+    pick: function(e) {
+        var target = Event.element(e);
+        if (target.tagName == 'A') {
+            this.currentSelection = target;
+            this.setValue(this.currentSelection.childNodes[0]);
+            this.valueChanged();
+        }
+        this.close();
+    },
+    /**
+     * Method: setValue
+     * set the value of the picker
+     *
+     * Parameters:
+     * value - {Object} the new value.  May be a string, a text node, or
+     * another DOM element.
+     */
+    setValue: function(value) {
+        if (this.isEditable) {
+            if (typeof(value) == 'string') {
+                this.domInput.value = value;
+            } else if (value.nodeType && value.nodeType == 3) {
+                this.domInput.value = value.nodeValue;
+            } else {
+                this.domInput.value = value.innerHTML;
+            }
+        } else if (!this.isEditable) {
+            if (typeof(value) == 'string') {
+                this.domInput.innerHTML = value;
+            } else if (value.nodeType && value.nodeType == 3) {
+                this.domInput.innerHTML = value.nodeValue;
+            } else {
+                this.domInput.appendChild(value);
+            }
+        }
+    },
+    
+    /**
+     * Method: getValue
+     * Return the current value
+     *
+     * Returns:
+     * {Object} returns the currently selected item
+     */
+    getValue: function() {
+        value = '';
+        if (this.isEditable) {
+            value = this.domInput.value;
+        } else if (this.domInput.childNodes.length > 0) {
+            if (this.domInput.childNodes[0].nodeType == 3) {
+                value = this.domInput.innerHTML;
+            } else {
+                value = this.domInput.childNodes[0];
+            }
+        }
+        return value;
+    },
+    
+    /**
+     * Method: toggle
+     * Toggle the display of the list associated with the picker
+     */
+    toggle: function() {
+        if (this.domListDiv.style.display == 'block') {
+            this.close();
+        } else {
+            this.open();
+        }
+    },
+    
+    /**
+     * Method: open
+     * Open the pick list
+     */
+    open: function() {
+        if (!this.keypressListener) {
+            this.keypressListener = this.keypress.bindAsEventListener(this);
+        }
+        this.domListDiv.style.display = 'block';
+        Event.observe(document, 'keypress', this.keypressListener);
+        //Effect.SlideDown(this.domObj, 0.2);
+    },
+    /**
+     * Method: keypress
+     * Handle a key press event when the list is open so we can close it if the
+     * user hits the ESC key.
+     *
+     * Parameters:
+     * e - {Event} the keypress event
+     */
+    keypress: function(e) {
+        var charCode=(e.charCode)?e.charCode:e.keyCode;
+        if (charCode == Event.KEY_ESC) {
+            this.close();
+        }
+    },
+    /**
+     * Method: close
+     * Close the picker.
+     */
+    close: function() {
+        this.domListDiv.style.display = 'none';
+        Event.stopObserving(document, 'keypress', this.keypressListener);
+        //Effect.SlideUp(this.domObj, 0.2);
+    },
+    /**
+     * Method: addSelectionListener
+     * Add a selection listener to the picker
+     *
+     * Parameters:
+     * obj - {Object} the selection listener
+     */
+    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
+    /**
+     * Method: removeSelectionListener
+     * Remove a selection listener to the picker
+     *
+     * Parameters:
+     * obj - {Object} the selection listener
+     */
+    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); },
+    /**
+     * Method: getSelection
+     * return the current selection
+     *
+     * Returns:
+     * {Object} the current selection or an empty string.
+     */
+    getSelection: function() {
+        return this.currentSelection ? this.currentSelection.name : '';
+    }
+};
+Object.extend(Jx.Picker.prototype, Jx.Listener.prototype);/**
+ * $Id: jxsplitter.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Splitter
+ *
+ * Purpose: 
+ * Implementation of a javascript Splitter for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+  
+/**
+ * Class: Jx.Splitter
+ * a Jx.Splitter creates two or more containers within a parent container
+ * and provides user control over the size of the containers.  The split
+ * can be made horizontally or vertically.
+ * 
+ * A horizontal split creates containers that divide the space horizontally
+ * with vertical bars between the containers.  A vertical split divides
+ * the space vertically and creates horizontal bars between the containers.
+ */
+ 
+Jx.Splitter = Class.create();
+Jx.Splitter.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} the element being split
+     */
+    domObj: null,
+    /**
+     * Property: elements
+     * {Array} an array of elements that are displayed in each of the split 
+     * areas
+     */
+    elements: null,
+    /**
+     * Property: bars
+     * {Array} an array of the bars between each of the elements used to
+     * resize the split areas.
+     */
+    bars: null,
+    /**
+     * Property: firstUpdate
+     * {Boolean} track the first resize event so that unexposed Jx things
+     * can be forced to calculate their size the first time they are exposed.
+     */
+    firstUpdate: true,
+    /**
+     * Constructor: Jx.Splitter
+     * Create a new instance of Jx.Splitter
+     *
+     * Parameters:
+     * domObj - {HTMLElement} the element or id of the element to split
+     * options - {Object} optional arguments specified as properties of
+     * this object are as below.
+     *
+     * Options:
+     * elements - {Array} an array of elements to put into the split areas.
+     *      If splitInto is not set, then it is calculated from the length of
+     *      this array.
+     * splitInto - {Integer} the number of elements to split the domObj into.
+     *      If not set, then the length of the elements option is used, or 2 if
+     *      elements is not specified.  If splitInto is specified and elements
+     *      is specified, then splitInto is used.  If there are more elements than
+     *      splitInto specifies, then the extras are ignored.  If there are less
+     *      elements than splitInto specifies, then extras are created.
+     * containerOptions - {Array} an array of objects that provide options
+     *      for the <Jx.Layout> constraints on each element.
+     * layout - {String} either 'horizontal' or 'vertical', indicating the
+     *      direction in which the domObj is to be split.
+     * snappers - {Array} an array of objects which can be used to snap
+     *      elements open or closed.
+     */
+    initialize: function(domObj, options) {
+        options = options || {};  
+        
+        this.domObj = $(domObj);
+        this.domObj.style.overflow = 'hidden';
+        if (this.domObj.jxLayout) {
+            this.domObj.jxLayout.addSizeChangeListener(this);
+        }
+       
+        this.elements = [];
+        this.bars = [];
+        
+        var nSplits = options.splitInto || (options.elements ? options.elements.length : 2);
+        
+        var aContainerOpts = options.containerOptions || [];
+
+        for (var i=0; i<nSplits; i++) {
+            this.elements[i] = options.elements ? options.elements[i] : this.prepareElement();
+            this.domObj.appendChild(this.elements[i]);
+            if (!this.elements[i].jxLayout) {
+                new Jx.Layout(this.elements[i], aContainerOpts[i]);
+            }
+        }
+        
+        for (var i=1; i<nSplits; i++) {
+            this.bars[i-1] = this.prepareBar();
+            this.bars[i-1].leftSide = this.elements[i-1];
+            this.bars[i-1].rightSide = this.elements[i];
+            this.elements[i-1].rightBar = this.bars[i-1];
+            this.elements[i].leftBar = this.bars[i-1];
+            this.domObj.appendChild(this.bars[i-1]);
+        }
+
+        this.layout = options.layout || 'horizontal';
+        this.establishConstraints();
+        
+        if (options.snappers) {
+            for (var i=0; i<options.snappers.length; i++) {
+                if (options.snappers[i]) {
+                    new Jx.Splitter.Snapper(options.snappers[i], this.elements[i], this);
+                }
+            }
+        }
+    },
+    /**
+     * Method: prepareElement
+     * Prepare a new, empty element to go into a split area.
+     *
+     * Returns:
+     * {HTMLElement} an HTMLElement that goes into a split area.
+     */
+    prepareElement: function(){
+        var o = document.createElement('div');
+        o.style.position = 'absolute';
+        o.leftBar = null;
+        o.rightBar = null;
+        return o;
+    },
+    
+    /**
+     * Method: prepareBar
+     * Prepare a new, empty bar to go into between split areas.
+     *
+     * Returns:
+     * {HTMLElement} an HTMLElement that becomes a bar.
+     */
+    prepareBar: function() {
+        var o = document.createElement('div');
+        o.className = 'jxSplitterBar';
+        o.style.position = 'absolute';
+        o.title = 'drag this bar to resize';
+        o.style.lineHeight = '1px'; // for IE, horizontal bars
+        o.splitterObj = this;
+        return o;
+    },
+    
+    /**
+     * Method: establishConstraints
+     * Setup the initial set of constraints that set the behaviour of the
+     * bars between the elements in the split area.
+     */
+    establishConstraints: function() {
+        if (this.layout == 'horizontal') {
+            for (var i=0; i< this.bars.length; i++) {
+                this.bars[i].style.top = '0px';
+                this.bars[i].style.height = '100%';
+                new Draggable(this.bars[i], { constraint: 'horizontal' , 
+                                     starteffect : function(element) { 
+                                            element.style.backgroundColor = '#eee';
+                                            },
+                                     endeffect : function(element) {
+                                         element.style.backgroundColor = '';
+                                     }
+                });
+            }
+        } else {
+            for (var i=0; i< this.bars.length; i++) {
+                this.bars[i].style.left = '0px';
+                this.bars[i].style.width = '100%';
+                new Draggable(this.bars[i], { constraint: 'vertical' , 
+                                     starteffect : function(element) { 
+                                            element.style.backgroundColor = '#eee';
+                                            },
+                                     endeffect : function(element) {
+                                         element.style.backgroundColor = '';
+                                     }
+                });
+            }
+        }
+        Draggables.addObserver(this);
+    },
+    
+    /**
+     * Method: onEnd
+     * Handle the end of a drag event on a bar.
+     *
+     * Parameters:
+     * eventName - {String} the name associated with the drag event
+     * obj - {HTMLElement} the bar that was dragged
+     * event - {Event} the event object associated with the drag
+     */
+    onEnd: function(eventName, obj, event) {
+        if (obj.element.splitterObj != this) {
+            return;
+        }
+        if (this.layout == 'horizontal') {
+            this.dragHorizontal(eventName, obj, event);
+        } else {
+            this.dragVertical(eventName, obj, event);
+        }
+    },
+    
+    /**
+     * Method: dragHorizontal
+     * In a horizontally split container, handle a bar being dragged left or
+     * right by resizing the elements on either side of the bar.
+     *
+     * Parameters:
+     * eventName - {String} the name associated with the drag event
+     * obj - {HTMLElement} the bar that was dragged
+     * event - {Event} the event object associated with the drag
+     */
+    dragHorizontal: function(eventName, obj, event) {
+        var leftEdge = parseInt(obj.element.style.left);
+        var leftSide = obj.element.leftSide;
+        var rightSide = obj.element.rightSide;
+        
+        /* process right side first */
+        var rsLeft, rsWidth, rsRight;
+        
+        if (!obj.element.size) {
+            obj.element.size = Element.getBorderBoxSize(obj.element);
+        }
+        var barSize = obj.element.size;
+        rsLeft = leftEdge + barSize.width;
+        
+        var parentSize = Element.getContentBoxSize(this.domObj);
+        
+        if (rightSide.jxLayout.options.width != null) {
+            rsWidth = rightSide.jxLayout.options.width + rightSide.jxLayout.options.left - rsLeft;
+            rsRight = parentSize.width - rsLeft - rsWidth;
+        } else {
+            rsWidth = parentSize.width - rightSide.jxLayout.options.right - rsLeft;
+            rsRight = rightSide.jxLayout.options.right;
+        }
+        
+        /* enforce constraints on right side */
+        if (rsWidth < 0) {
+            rsWidth = 0;
+        }
+        
+        if (rsWidth < rightSide.jxLayout.options.minWidth) {
+            rsWidth = rightSide.jxLayout.options.minWidth;
+        }
+        if (rightSide.jxLayout.options.maxWidth >= 0 && rsWidth > rightSide.jxLayout.options.maxWidth) {
+            rsWidth = rightSide.jxLayout.options.maxWidth;
+        }
+        
+        rsLeft = parentSize.width - rsRight - rsWidth;
+        leftEdge = rsLeft - barSize.width;
+        
+        /* process left side */
+        var lsLeft, lsWidth;
+        lsLeft = leftSide.jxLayout.options.left;
+        lsWidth = leftEdge - lsLeft;
+        
+        /* enforce constraints on left */
+        if (lsWidth < 0) {
+            lsWidth = 0;
+        }
+        if (lsWidth < leftSide.jxLayout.options.minWidth) {
+            lsWidth = leftSide.jxLayout.options.minWidth;
+        }
+        if (leftSide.jxLayout.options.maxWidth >= 0 && 
+            lsWidth > leftSide.jxLayout.options.maxWidth) {
+            lsWidth = leftSide.jxLayout.options.maxWidth;
+        }
+        
+        /* update the leftEdge to accomodate constraints */
+        if (lsLeft + lsWidth != leftEdge) {
+            /* need to update right side, ignoring constraints because left side
+               constraints take precedence (arbitrary decision)
+             */
+            leftEdge = lsLeft + lsWidth;
+            var delta = leftEdge + barSize.width - rsLeft;
+            rsLeft += delta;
+            rsWidth -= delta; 
+        }
+        
+        /* put bar in its final location based on constraints */
+        obj.element.style.left = leftEdge + 'px';
+        
+        /* update leftSide positions */
+        if (leftSide.jxLayout.options.width == null) {
+            var parentSize = Element.getContentBoxSize(this.domObj);
+            leftSide.jxLayout.resize({right: parentSize.width - lsLeft-lsWidth});
+        } else {
+            leftSide.jxLayout.resize({width: lsWidth});
+        }
+        
+        /* update rightSide position */
+        if (rightSide.jxLayout.options.width == null) {
+            rightSide.jxLayout.resize({left:rsLeft});
+        } else {
+            rightSide.jxLayout.resize({left: rsLeft, width: rsWidth});
+        }
+    },
+    
+    /**
+     * Method: dragVertical
+     * In a vertically split container, handle a bar being dragged up or
+     * down by resizing the elements on either side of the bar.
+     *
+     * Parameters:
+     * eventName - {String} the name associated with the drag event
+     * obj - {HTMLElement} the bar that was dragged
+     * event - {Event} the event object associated with the drag
+     */
+    dragVertical: function(eventName, obj, event) {
+        /* top edge of the bar */
+        var topEdge = parseInt(obj.element.style.top);
+        
+        /* the containers on either side of the bar */
+        var topSide = obj.element.leftSide;
+        var bottomSide = obj.element.rightSide;
+        
+        /* measure the bar and parent container for later use */
+        if (!obj.element.size) {
+            obj.element.size = Element.getBorderBoxSize(obj.element);
+        }
+        var barSize = obj.element.size;
+        var parentSize = Element.getContentBoxSize(this.domObj);
+
+        /* process top side first */
+        var bsTop, bsHeight, bsBottom;
+        
+        /* top edge of bottom side is the top edge of bar plus the height of the bar */
+        bsTop = topEdge + barSize.height;
+        
+        if (bottomSide.jxLayout.options.height != null) {
+            /* bottom side height is fixed */
+            bsHeight = bottomSide.jxLayout.options.height + bottomSide.jxLayout.options.top - bsTop;
+            bsBottom = parentSize.height - bsTop - bsHeight;
+        } else {
+            /* bottom side height is not fixed. */
+            bsHeight = parentSize.height - bottomSide.jxLayout.options.bottom - bsTop;
+            bsBottom = bottomSide.jxLayout.options.bottom;
+        }
+        
+        /* enforce constraints on bottom side */
+        if (bsHeight < 0) {
+            bsHeight = 0;
+        }
+        
+        if (bsHeight < bottomSide.jxLayout.options.minHeight) {
+            bsHeight = bottomSide.jxLayout.options.minHeight;
+        }
+        
+        if (bottomSide.jxLayout.options.maxHeight >= 0 && bsHeight > bottomSide.jxLayout.options.maxHeight) {
+            bsHeight = bottomSide.jxLayout.options.maxHeight;
+        }
+        
+        /* recalculate the top of the bottom side in case it changed
+           due to a constraint.  The bar may have moved also.
+         */
+        bsTop = parentSize.height - bsBottom - bsHeight;
+        topEdge = bsTop - barSize.height;
+                
+        /* process left side */
+        var tsTop, tsHeight;
+        tsTop = topSide.jxLayout.options.top;
+        tsHeight = topEdge - tsTop;
+                        
+        /* enforce constraints on left */
+        if (tsHeight < 0) {
+            tsHeight = 0;
+        }
+        if (tsHeight < topSide.jxLayout.options.minHeight) {
+            tsHeight = topSide.jxLayout.options.minHeight;
+        }
+        if (topSide.jxLayout.options.maxHeight >= 0 && 
+            tsHeight > topSide.jxLayout.options.maxHeight) {
+            tsHeight = topSide.jxLayout.options.maxHeight;
+        }
+        
+        /* update the topEdge to accomodate constraints */
+        if (tsTop + tsHeight != topEdge) {
+            /* need to update right side, ignoring constraints because left side
+               constraints take precedence (arbitrary decision)
+             */
+            topEdge = tsTop + tsHeight;
+            var delta = topEdge + barSize.height - bsTop;
+            bsTop += delta;
+            bsHeight -= delta; 
+        }
+        
+        /* put bar in its final location based on constraints */
+        obj.element.style.top = topEdge + 'px';
+        
+        /* update topSide positions */
+        if (topSide.jxLayout.options.height == null) {
+            topSide.jxLayout.resize({bottom: parentSize.height - tsTop-tsHeight});
+        } else {
+            topSide.jxLayout.resize({height: tsHeight});
+        }
+        
+        /* update bottomSide position */
+        if (bottomSide.jxLayout.options.height == null) {
+            bottomSide.jxLayout.resize({top:bsTop});
+        } else {
+            bottomSide.jxLayout.resize({top: bsTop, height: bsHeight});
+        }
+    },
+    
+    /**
+     * Method: sizeChanged
+     * handle the size of the container being changed.
+     */
+    sizeChanged: function() {
+        if (this.layout == 'horizontal') {
+            this.horizontalResize();
+        } else {
+            this.verticalResize();
+        }
+    },
+    
+    /**
+     * Method: horizontalResize
+     * Resize a horizontally layed-out container
+     */
+    horizontalResize: function() {
+        var availableSpace = Element.getContentBoxSize(this.domObj).width;
+        var overallWidth = availableSpace;
+
+        for (var i=0; i<this.bars.length; i++) {
+            var bar = this.bars[i];
+            if (!bar.size) {
+                bar.size = Element.getBorderBoxSize(bar);
+            }
+            availableSpace -= bar.size.width;
+        }
+
+        var nVariable = 0;
+        var jxo;
+        for (var i=0; i<this.elements.length; i++) {
+            var e = this.elements[i];
+            jxo = e.jxLayout.options;
+            if (jxo.width != null) {
+                availableSpace -= parseInt(jxo.width);
+            } else {
+                var w = 0;
+                if (jxo.right != 0 || 
+                    jxo.left != 0) {
+                    w = Element.getBorderBoxSize(e).width;
+                }
+                
+                availableSpace -= w;
+                nVariable++;
+            }
+        }
+
+        if (nVariable == 0) { /* all fixed */
+            /* stick all available space in the last one */
+            availableSpace += jxo.width;
+            jxo.width = null;
+            nVariable = 1;
+        }
+
+        var amount = parseInt(availableSpace / nVariable);
+        /* account for rounding errors */
+        var remainder = availableSpace % nVariable;
+
+        var currentPosition = 0;
+
+        for (var i=0; i<this.elements.length; i++) {
+             var e = this.elements[i];
+             var jxl = e.jxLayout;
+             var jxo = jxl.options;
+             if (jxo.width != null) {
+                 jxl.resize({left: currentPosition});
+                 currentPosition += jxo.width;
+             } else {
+                 var a = amount;
+                 if (nVariable == 1) {
+                     a += remainder;
+                 }
+                 nVariable--;
+                 
+                 var w = 0;
+                 if (jxo.right != 0 || jxo.left != 0) {
+                     w = Element.getBorderBoxSize(e).width + a;
+                 } else {
+                     w = a;
+                 }
+                 
+                 if (w < 0) {
+                     if (nVariable > 0) {
+                         amount = amount + w/nVariable;
+                     }
+                     w = 0;
+                 }
+                 if (w < jxo.minWidth) {
+                     if (nVariable > 0) {
+                         amount = amount + (w - jxo.minWidth)/nVariable;
+                     }
+                     w = jxo.minWidth;
+                 }
+                 if (jxo.maxWidth >= 0 && w > jxo.maxWidth) {
+                     if (nVariable > 0) {
+                         amount = amount + (w - jxo.maxWidth)/nVariable;
+                     }
+                     w = e.options.maxWidth;
+                 }
+                 
+                 var r = overallWidth - currentPosition - w;
+                 jxl.resize({left: currentPosition, right: r});
+                 currentPosition += w;
+             }
+             if (e.rightBar) {
+                 e.rightBar.style.left = currentPosition + 'px';
+                 currentPosition += e.rightBar.size.width;
+             }
+         }
+    },
+    
+    /**
+     * Method: verticalResize
+     * Resize a vertically layed out container.
+     */
+    verticalResize: function() { 
+        var availableSpace = Element.getContentBoxSize(this.domObj).height;
+        var overallHeight = availableSpace;
+
+        for (var i=0; i<this.bars.length; i++) {
+            var bar = this.bars[i];
+            if (!bar.size) {
+                bar.size = Element.getBorderBoxSize(bar);
+            }
+            availableSpace -= bar.size.height;
+        }
+
+        var nVariable = 0;
+        
+        var jxo;
+        for (var i=0; i<this.elements.length; i++) {
+            var e = this.elements[i];
+            jxo = e.jxLayout.options;
+            if (jxo.height != null) {
+                availableSpace -= parseInt(jxo.height);
+            } else {
+                var h = 0;
+                if (jxo.bottom != 0 || jxo.top != 0) {
+                    h = Element.getBorderBoxSize(e).height;
+                }
+                
+                availableSpace -= h;
+                nVariable++;
+            }
+        }
+
+        if (nVariable == 0) { /* all fixed */
+            /* stick all available space in the last one */
+            availableSpace += jxo.height;
+            jxo.height = null;
+            nVariable = 1;
+        }
+
+        var amount = parseInt(availableSpace / nVariable);
+        /* account for rounding errors */
+        var remainder = availableSpace % nVariable;
+
+        var currentPosition = 0;
+
+        for (var i=0; i<this.elements.length; i++) {
+             var e = this.elements[i];
+             var jxl = e.jxLayout;
+             var jxo = jxl.options;
+             if (jxo.height != null) {
+                 jxl.resize({top: currentPosition});
+                 currentPosition += jxo.height;
+             } else {
+                 var a = amount;
+                 if (nVariable == 1) {
+                     a += remainder;
+                 }
+                 nVariable--;
+                 
+                 var h = 0;
+                 if (jxo.bottom != 0 || 
+                     jxo.top != 0) {
+                     h = Element.getBorderBoxSize(e).height + a;
+                 } else {
+                     h = a;
+                 }
+                 
+                 if (h < 0) {
+                     if (nVariable > 0) {
+                         amount = amount + h/nVariable;
+                     }
+                     h = 0;
+                 }
+                 if (h < jxo.minHeight) {
+                     if (nVariable > 0) {
+                         amount = amount + (h - jxo.minHeight)/nVariable;
+                     }
+                     h = jxo.minHeight;
+                 }
+                 if (jxo.maxHeight >= 0 && h > jxo.maxHeight) {
+                     if (nVariable > 0) {
+                         amount = amount + (h - jxo.maxHeight)/nVariable;
+                     }
+                     h = jxo.maxHeight;
+                 }
+                 
+                 var r = overallHeight - currentPosition - h;
+                 jxl.resize({top: currentPosition, bottom: r});
+                 currentPosition += h;
+             }
+             if (e.rightBar) {
+                 e.rightBar.style.top = currentPosition + 'px';
+                 currentPosition += e.rightBar.size.height;
+             }
+         }
+    }
+};
+
+/**
+ * Class: Jx.Splitter.Snapper
+ * A helper class to create an element that can snap a split panel open or
+ * closed.
+ */
+Jx.Splitter.Snapper = Class.create();
+Jx.Splitter.Snapper.prototype = {
+    /**
+     * Property: snapper
+     * {HTMLElement} the DOM element of the snapper (the thing that gets
+     * clicked).
+     */
+    snapper: null,
+    /**
+     * Property: element
+     * {HTMLElement} An element of the <Jx.Splitter> that gets controlled
+     * by this snapper
+     */
+    element: null,
+    /**
+     * Property: splitter
+     * {<Jx.Splitter>} the splitter that this snapper is associated with.
+     */
+    splitter: null,
+    /**
+     * Property: layout
+     * {String} track the layout of the splitter for convenience.
+     */
+    layout: 'vertical',
+    /**
+     * Constructor: Jx.Splitter.Snapper
+     * Create a new Jx.Splitter.Snapper
+     *
+     * Parameters:
+     * snapper - {HTMLElement} the clickable thing that snaps the element
+     *           open and closed
+     * element - {HTMLElement} the element that gets controlled by the snapper
+     * splitter - {<Jx.Splitter>} the splitter that this all happens inside of.
+     */
+    initialize: function(snapper, element, splitter) {
+        this.snapper = snapper;
+        this.element = element;
+        element.jxLayout.addSizeChangeListener(this);
+        this.splitter = splitter;
+        this.layout = splitter.layout; 
+        var jxo = this.element.jxLayout.options;
+        var size = Element.getBorderBoxSize(this.element);
+        if (this.layout == 'vertical') {
+            this.originalSize = size.height;
+            this.minimumSize = jxo.minHeight ? jxo.minHeight : 0;
+        } else {
+            this.originalSize = size.width;
+            this.minimumSize = jxo.minWidth ? jxo.minWidth : 0;
+        }
+        
+        Event.observe(snapper, 'click', this.toggleElement.bind(this));
+    },
+    
+    /**
+     * Method: toggleElement
+     * Snap the element open or closed.
+     */
+    toggleElement: function() {
+        var size = Element.getBorderBoxSize(this.element);
+        var newSize = {};
+        if (this.layout == 'vertical') {
+            if (size.height == this.minimumSize) {
+                newSize.height = this.originalSize;
+            } else {
+                this.originalSize = size.height;
+                newSize.height = this.minimumSize;
+            }
+        } else {
+            if (size.width == this.minimumSize) {
+                newSize.width = this.originalSize;
+            } else {
+                this.originalSize = size.width;
+                newSize.width = this.minimumSize;
+            }
+        }
+        this.element.jxLayout.resize(newSize);
+        this.splitter.sizeChanged();
+    },
+    
+    /**
+     * Method: sizeChanged
+     * Handle the size of the element changing to see if the
+     * toggle state has changed.
+     */
+    sizeChanged: function() {
+        var size = Element.getBorderBoxSize(this.element);
+        if (this.layout == 'vertical') {
+            if (size.height == this.minimumSize) {
+                Element.addClassName(this.snapper, 'jxSnapClosed');
+                Element.removeClassName(this.snapper, 'jxSnapOpened');
+            } else {
+                Element.addClassName(this.snapper, 'jxSnapOpened');
+                Element.removeClassName(this.snapper, 'jxSnapClosed');
+            }
+        } else {
+            if (size.width == this.minimumSize) {
+                Element.addClassName(this.snapper, 'jxSnapClosed');
+                Element.removeClassName(this.snapper, 'jxSnapOpened');
+            } else {
+                Element.addClassName(this.snapper, 'jxSnapOpened');
+                Element.removeClassName(this.snapper, 'jxSnapClosed');
+            }
+        }
+    }
+};/**
+ * $Id: jxtab.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Tab
+ *
+ * Purpose: 
+ * Implementation of a javascript tabbed panel capability for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+Jx.addStyleSheet('tab/tabs.css');
+Jx.addStyleSheet('tabs/tabs_ie.css', true);
+
+/**
+ * Class: Jx.TabSet
+ * A TabSet manages a set of <Jx.Tab> content areas by ensuring that only one
+ * of the content areas is visible (i.e. the active tab).  TabSet does not
+ * manage the actual tabs.  The instances of <Jx.Tab> that are to be managed
+ * as a set have to be added to both a TabSet and a <Jx.Toolbar>.  The content
+ * areas of the <Jx.Tab>s are sized to fit the content area that the TabSet
+ * is managing.
+ *
+ * (code)
+ * var tabBar = new Jx.Toolbar('tabBar');
+ * var tabSet = new Jx.TabSet('tabArea');
+ * 
+ * var tab1 = new Jx.Tab('tab 1', {contentID: 'content1'});
+ * var tab2 = new Jx.Tab('tab 2', {contentID: 'content2'});
+ * var tab3 = new Jx.Tab('tab 3', {contentID: 'content3'});
+ * var tab4 = new Jx.Tab('tab 4', {contentURL: 'test_content.html'});
+ * 
+ * tabSet.add(t1, t2, t3, t4);
+ * tabBar.add(t1, t2, t3, t4);
+ * (end)
+ *
+ * Inherits From:
+ * <Jx.Listener>
+ */
+Jx.TabSet = Class.create();
+Jx.TabSet.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} The HTML element that represents this tab set in the DOM.
+     * The content areas of each tab are sized to fill the domObj.
+     */
+    domObj : null,
+    /**
+     * Property: sl
+     * {Array} array of selection listeners.
+     */
+    sl: null,
+    /**
+     * Constructor: Jx.TabSet
+     * Create a new instance of <Jx.TabSet> within a specific element of
+     * the DOM.
+     *
+     * Parameters:
+     * domObj - {HTMLElement} an element or id of an element to put the
+     * content of the tabs into.
+     */
+    initialize : function(domObj) {
+        this.domObj = $(domObj);
+        if (!Element.hasClassName(this.domObj, 'jxTabSetContainer')) {
+            Element.addClassName(this.domObj, 'jxTabSetContainer');
+        }
+        this.sl = [];
+    },
+    /**
+     * Method: sizeChanged
+     * Respond to the size of the container changing.
+     *
+     * TODO: is this needed?
+     */
+    sizeChanged: function() { 
+      this.resizeTabBox(); 
+    },
+    /**
+     * Method: resizeTabBox
+     * Resize the tab set content area and propogate the changes to
+     * each of the tabs managed by the tab set.
+     */
+    resizeTabBox: function() {
+    
+        var parentSize = Element.getContentBoxSize(this.domObj.parentNode);
+        Element.setBorderBoxSize(this.domObj, {width: parentSize.width, height: parentSize.height});
+        // this is a bullshit hack for IE.  We need to set the tab content height
+        // for IE when the tabs are in a snap panel, otherwise the tab content
+        // doesn't collapse with the panel and no scrollbars appear.  This only
+        // affects the height.  In fact, setting the width breaks tab placement
+        
+        for (var i=0; i<this.domObj.childNodes.length; i++) {
+            // don't try to set the height on a text node 
+            if (this.domObj.childNodes[i].nodeType == 3) {
+                 continue;
+             }
+            Element.setBorderBoxSize(this.domObj.childNodes[i], {height: parentSize.height});
+            if (this.domObj.childNodes[i].resize) {
+                this.domObj.childNodes[i].resize({forceResize: true});
+            }
+        }
+    },
+    
+    /**
+     * Method: add
+     * Add one or more <Jx.Tab>s to the TabSet.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} an instance of <Jx.Tab> to add to the tab set.  More
+     * than one tab can be added by passing extra parameters to this method.
+     */
+    add : function() {
+        for (var i=0; i<arguments.length; i++) {
+            var tab = arguments[i];
+            tab.addSelectionListener(this);
+            this.domObj.appendChild(tab.content);
+            if (!this.activeTab) {
+                this.setActiveTab(tab);
+            }
+        }
+    },
+    /**
+     * Method: remove
+     * Remove a tab from the TabSet.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to remove.
+     *
+     * TODO: Implement remove for Jx.TabSet
+     */
+    remove : function(tab) {},
+    /**
+     * Method: setActiveTab
+     * Set the active tab to the one passed to this method
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to make active.
+     */
+    setActiveTab: function(tab) {
+        if (this.activeTab) {
+            Element.removeClassName(this.activeTab.domObj, 'tabActive');
+            Element.removeClassName(this.activeTab.content, 'tabContentActive');
+        }
+        this.activeTab = tab;
+        Element.addClassName(this.activeTab.domObj, 'tabActive');
+        Element.addClassName(this.activeTab.content, 'tabContentActive');
+        if (this.activeTab.content.resize) {
+          this.activeTab.content.resize({forceResize: true});
+        }
+    },
+    /**
+     * Method: selectionChanged
+     * Handle selection changing on the tabs themselves and activate the
+     * appropriate tab in response.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to make active.
+     */
+    selectionChanged: function(tab) {
+        this.setActiveTab(tab);
+        this.processEvent(this.sl, 'selectionChanged', tab);
+    },
+    /**
+     * Method: addSelectionListener
+     * Add a selection listener
+     *
+     * Parameters:
+     * obj - {Object} the selection listener to add
+     */
+    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
+    /**
+     * Method: removeSelectionListener
+     * Remove a selection listener
+     *
+     * Parameters:
+     * obj - {Object} the selection listener to remove
+     */
+    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); }
+};
+Object.extend(Jx.TabSet.prototype, Jx.Listener.prototype);
+
+/**
+ * Class: Jx.Tab
+ * A single tab in a tab set.  A tab has a label (displayed in the tab) and a
+ * content area that is displayed when the tab is active.  A tab has to be
+ * added to both a <Jx.TabSet> (for the content) and <Jx.Toolbar> (for the
+ * actual tab itself) in order to be useful.  Alternately, you can use
+ * a <Jx.TabBox> which combines both into a single control at the cost of
+ * some flexibility in layout options.
+ *
+ * A tab is a <Jx.ContentLoader> and you can specify the initial content of
+ * the tab using any of the methods supported by 
+ * <Jx.ContentLoader::loadContent>.  You can acccess the actual DOM element
+ * that contains the content (if you want to dynamically insert content
+ * for instance) via the <Jx.Tab::content> property.
+ *
+ * (code)
+ * var tab1 = new Jx.Tab('tab 1', {contentID: 'content1'});
+ * (end)
+ *
+ * Inherits From:
+ * <Jx.Listener>, <Jx.ContentLoader>
+ */
+Jx.Tab = Class.create();
+Jx.Tab.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} The button that is used to activate the tab.
+     */
+    domObj: null,
+    /**
+     * Property: content
+     * {HTMLElement} The content area that is displayed when the tab is active.
+     */
+    content: null,
+    /**
+     * Property: name
+     * {String} the name of the tab is also the label.
+     */
+    name: null,
+    /**
+     * Property: sl
+     * {Array} an array of selection listeners.
+     */
+    sl: null,
+    /**
+     * Constructor: Jx.Tab
+     * Create a new instance of Jx.Tab.
+     *
+     * Parameters:
+     * name - {String} the name (and label) of the tab.
+     * options - {Object} an object containing options that are used
+     * to control the appearance of the tab.  See 
+     * <Jx.ContentLoader::loadContent> and <Jx.Layout::Jx.Layout> for
+     * valid options.
+     */
+    initialize : function(name, options) {
+        this.sl = [];
+        options = options || {};
+        this.name = name;
+        this.content = document.createElement('div');
+        this.content.className = 'tabContent';
+        this.loadContent(this.content, options);
+        var a = new Jx.Action(this.clicked.bind(this));
+        var b = new Jx.Button(a, {label: name});
+        this.domObj = b.domA;
+        // rename the element from jxButton to jxTab
+        // Element.removeClassName(this.domObj, 'jxButton');
+        Element.addClassName(this.domObj, 'jxTab');
+        new Jx.Layout(this.content, options);
+        //this.content.resize = this.resize.bind(this);
+    },
+    /**
+     * Method: clicked
+     * Handle the tab being clicked by generating a selectionChanged
+     * event.
+     */
+    clicked: function() {
+        this.processEvent(this.sl, 'selectionChanged', this);
+        this.domObj.childNodes[0].blur();
+    },
+    /**
+     * Method: addSelectionListener
+     * Add a selection listener
+     *
+     * Parameters:
+     * obj - {Object} the selection listener to add
+     */
+    addSelectionListener: function(obj) { this.addListener(this.sl, obj); },
+    /**
+     * Method: removeSelectionListener
+     * Remove a selection listener
+     *
+     * Parameters:
+     * obj - {Object} the selection listener to remove
+     */
+    removeSelectionListener: function(obj) { this.removeListener(this.sl, obj); }
+};
+Object.extend(Jx.Tab.prototype, Jx.Listener.prototype);
+Object.extend(Jx.Tab.prototype, Jx.ContentLoader.prototype);
+
+/**
+ * Class: Jx.TabBox
+ * A convenience class to handle the common case of a single toolbar
+ * directly attached to the content area of the tabs.  It manages both a
+ * <Jx.Toolbar> and a <Jx.TabSet> so that you don't have to.  If you are using
+ * a TabBox, then tabs only have to be added to the TabBox rather than to
+ * both a <Jx.TabSet> and a <Jx.Toolbar>.
+ *
+ * (code)
+ * var tabBox = new Jx.TabBox('subTabArea', 'top');
+ * 
+ * var tab1 = new Jx.Tab('Tab 1', {contentID: 'content4'});
+ * var tab2 = new Jx.Tab('Tab 2', {contentID: 'content5'});
+ * 
+ * tabBox.add(tab1, tab2);
+ * (end)
+ *
+ * Inherits From:
+ * <Jx.Listener>
+ */
+Jx.TabBox = Class.create();
+Jx.TabBox.prototype = {
+    /**
+     * Property: tabBar
+     * {<Jx.Toolbar>} the toolbar for this tab box.
+     */
+    tabBar: null,
+    /**
+     * Property: tabSet
+     * {<Jx.TabSet>} the tab set for this tab box.
+     */
+    tabSet: null,
+    /**
+     * Constructor: Jx.TabBox
+     */
+    initialize : function(domObj, position) {
+        var parent = $(domObj);
+        position = position || 'top';
+        var tabBarDiv = document.createElement('div');
+        parent.appendChild(tabBarDiv);
+        this.tabBar = new Jx.Toolbar(tabBarDiv, position);
+        this.tabSet = new Jx.TabSet(parent);
+        switch (position) {
+            case 'top':
+                Element.addClassName(parent, 'jxTabBoxTop');
+                break;
+            case 'bottom':
+                Element.addClassName(parent, 'jxTabBoxBottom');
+                break;
+            case 'left':
+                Element.addClassName(parent, 'jxTabBoxLeft');
+                Element.addClassName(tabBarDiv, 'verticalToolbar');
+                break;
+            case 'right':
+                Element.addClassName(parent, 'jxTabBoxRight');
+                Element.addClassName(tabBarDiv, 'verticalToolbar');
+                break;
+        }
+        this.sl = [];
+    },
+    /**
+     * Method: sizeChanged
+     * Handle the size of the content area of the tab box changing.
+     *
+     * TODO: is this needed?
+     */
+    sizeChanged: function() { this.tabSet.sizeChanged(); },
+    
+    /**
+     * Method: add
+     * Add one or more <Jx.Tab>s to the TabBox.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} an instance of <Jx.Tab> to add to the tab box.  More
+     * than one tab can be added by passing extra parameters to this method.
+     * Unlike <Jx.TabSet>, tabs do not have to be added to a separate 
+     * <Jx.Toolbar>.
+     */
+    add : function() { 
+        this.tabBar.add.apply(this.tabBar, arguments); 
+        this.tabSet.add.apply(this.tabSet, arguments); 
+    },
+    /**
+     * Method: remove
+     * Remove a tab from the TabSet.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to remove.
+     *
+     * TODO: implement remove for Jx.TabBox.
+     */
+    remove : function(tab) { /* TODO */ }
+};
+Object.extend(Jx.TabBox.prototype, Jx.Listener.prototype);
+/**
+ * $Id: jxtoolbar.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Toolbar
+ *
+ * Purpose: 
+ * Implementation of a javascript Toolbar for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+/**
+ * import stylesheets
+ */
+Jx.addStyleSheet('toolbar/toolbar.css');
+Jx.addStyleSheet('button/button.css');
+
+/**
+ * Class: Jx.Toolbar
+ *
+ * A toolbar is a container object that contains other objects such as
+ * buttons.  The toolbar organizes the objects it contains automatically,
+ * wrapping them as necessary.  Multiple toolbars may be placed within
+ * the same containing object.
+ *
+ * Jx.Toolbar includes CSS classes for styling the appearance of a
+ * toolbar to be similar to traditional desktop application toolbars.
+ *
+ * There is one special object, Jx.ToolbarSeparator, that provides
+ * a visual separation between objects in a toolbar.
+ *
+ * The following example shows how to create a Jx.Toolbar instance and place two objects in it.
+ * (code)
+ * //myToolbarContainer is the id of a <div> in the HTML page.
+ * function myFunction() {}
+ * var myToolbar = new Jx.Toolbar('myToolbarContainer');
+ * 
+ * var myAction = new Jx.Action(myFunction):
+ * var myButton = new Jx.Button(myAction);
+ *
+ * var myElement = document.createElement('select');
+ *
+ * myToolbar.add(myButton, new Jx.ToolbarSeparator(), myElement);
+ * (end)
+ *
+ * While a toolbar is generally a *dumb* container, it serves a special purpose
+ * for menus by providing some infrastructure so that menus can behave
+ * properly.
+ *
+ * In general, almost anything can be placed in a Toolbar, and mixed with 
+ * anything else.
+ */
+Jx.Toolbar = Class.create();
+Jx.Toolbar.prototype = {
+    /**
+     * Property: items
+     * {Array} an array of the things in the toolbar.
+     */
+    items : null,
+    /**
+     * Property: domObj
+     * {HTMLElement} the HTML element that the toolbar lives in
+     */
+    domObj : null,
+    /**
+     * Property: isActive
+     * When a toolbar contains <Jx.Menu> instances, they want to know
+     * if any menu in the toolbar is active and this is how they
+     * find out.
+     */
+    isActive : false,
+    /**
+     * Constructor: Jx.Toolbar
+     * Create a new instance of Jx.Toolbar.
+     *
+     * Parameters:
+     * domObj - {HTMLElement} object reference or id to place the toolbar in.
+     * position - one of 'top', 'right', 'bottom', or 'left', indicates how
+     * the toolbar is being placed in the page and may influence the behaviour
+     * of items in the toolbar that open sub panels, they will tend to open
+     * them towards the center of the page.  Default is top.
+     */
+    initialize : function(domObj, position) {
+        var parent = $(domObj);
+        this.domObj = document.createElement('ul');
+        Element.addClassName(this.domObj,'jxToolbar');
+        
+        if (!Element.hasClassName(parent, 'jxToolbarContainer')) {
+            Element.addClassName(parent, 'jxToolbarContainer');
+            parent.appendChild(this.domObj);
+            var clearer = document.createElement('div');
+            clearer.className = 'jxClearer';
+            parent.appendChild(clearer);                    
+        } else {
+            parent.insertBefore(this.domObj, parent.lastChild);
+        }
+        switch (position) {
+            case 'top':
+                Element.addClassName(parent, 'jxBarTop');
+                break;
+            case 'right':
+                Element.addClassName(parent, 'jxBarRight');
+                break;
+            case 'bottom':
+                Element.addClassName(parent, 'jxBarBottom');
+                break;
+            case 'left':
+                Element.addClassName(parent, 'jxBarLeft');
+                break;
+            default:
+                Element.addClassName(parent, 'jxBarTop');
+        }
+        this.deactivateWatcher = this.deactivate.bindAsEventListener(this);
+        
+    },
+    /**
+     * Method: add
+     * Add an item to the toolbar.  If the item being added is a Jx component
+     * with a domObj property, the domObj is added.  If the item being added
+     * is an LI element, then it is given a CSS class of *jxToolItem*.
+     * Otherwise, the thing is wrapped in a <Jx.ToolbarItem>.
+     *
+     * Parameters:
+     * thing - {Object} the thing to add.  More than one thing can be added
+     * by passing multiple arguments.
+     */
+    add : function( ) {
+        for (var i=0; i<arguments.length; i++) {
+            var thing = arguments[i];
+            thing.toolbar = this;
+            if (thing.domObj) {
+                thing = thing.domObj;
+            }
+            if (thing.tagName == 'LI') {
+                if (!Element.hasClassName(thing, 'jxToolItem')) {
+                    Element.addClassName(thing, 'jxToolItem');
+                }
+                this.domObj.appendChild(thing);
+            } else {
+                var item = new Jx.ToolbarItem(thing);
+                this.domObj.appendChild(item.domObj);
+            }
+        }
+    },
+    /**
+     * Method: deactivate
+     * Deactivate the Toolbar (when it is acting as a menu bar).
+     */
+    deactivate: function() {
+        for (var i=0; i<this.items.length; i++) {
+            this.items[i].hide();
+        }
+        this.setActive(false);
+    },
+    /**
+     * Method: isActive
+     * Indicate if the toolbar is currently active (as a menu bar)
+     *
+     * Returns:
+     * {Boolean}
+     */
+    isActive: function() { 
+        return this.isActive; 
+    },
+    /**
+     * Method: setActive
+     * Set the active state of the toolbar (for menus)
+     *
+     * Parameters: 
+     * b - {Boolean} the new state
+     */
+    setActive: function(b) { 
+        this.isActive = b;
+        if (this.isActive) {
+            Event.observe(document, 'click', this.deactivateWatcher);
+        } else {
+            Event.stopObserving(document, 'click', this.deactivateWatcher);
+        }
+    },
+    /**
+     * Method: setVisibleItem
+     * For menus, they want to know which menu is currently open.
+     *
+     * Parameters:
+     * obj - {<Jx.Menu>} the menu that just opened.
+     */
+    setVisibleItem: function(obj) {
+        if (this.visibleItem && this.visibleItem.hide && this.visibleItem != obj) {
+            this.visibleItem.hide();
+        }
+        this.visibleItem = obj;
+        if (this.isActive()) {
+            this.visibleItem.show();
+        }
+    }
+};
+
+/**
+ * Class: Jx.ToolbarItem
+ * A helper class to provide a container for something to go into 
+ * a <Jx.Toolbar>.
+ */
+Jx.ToolbarItem = Class.create();
+Jx.ToolbarItem.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} an element to contain the thing to be placed in the
+     * toolbar.
+     */
+    domObj: null,
+    /**
+     * Constructor: Jx.ToolbarItem
+     * Create a new instance of Jx.ToolbarItem.
+     *
+     * Parameters:
+     * jxThing - {Object} the thing to be contained.
+     */
+    initialize : function( jxThing ) {
+        this.al = [];
+        this.domObj = document.createElement('li');
+        this.domObj.className = 'jxToolItem';
+        if (jxThing) {
+            if (jxThing.domObj) {
+                this.domObj.appendChild(jxThing.domObj);
+                if (jxThing instanceof Jx.Tab) {
+                    // this.domObj.className = 'jxTabItem';
+                    Element.addClassName(this.domObj, 'jxTabItem');
+                }
+            } else {
+                this.domObj.appendChild(jxThing);
+                if (Element.hasClassName(jxThing, 'jxTab')) {
+                    // this.domObj.className = 'jxTabItem';
+                    Element.addClassName(this.domObj, 'jxTabItem');
+                }
+            }
+        }
+    }
+};
+
+/**
+ * Class: Jx.ToolbarSeparator
+ * A helper class that represents a visual separator in a <Jx.Toolbar>
+ */
+Jx.ToolbarSeparator = Class.create();
+Jx.ToolbarSeparator.prototype = {
+    /**
+     * Property: domObj
+     * {HTMLElement} The DOM element that goes in the <Jx.Toolbar>
+     */
+    domObj: null,
+    /**
+     * Constructor: Jx.ToolbarSeparator
+     * Create a new Jx.ToolbarSeparator
+     */
+    initialize: function() {
+        this.domObj = document.createElement('li');
+        this.domObj.className = 'jxToolItem';
+        this.domSpan = document.createElement('span');
+        this.domSpan.className = 'separator';
+        this.domObj.appendChild(this.domSpan);
+    }
+};
+
+/**
+ * $Id: jxtree.js 512 2008-03-07 21:15:45Z pspencer $
+ *
+ * Title: Jx.Tree
+ *
+ * Purpose: 
+ * Implementation of a javascript Tree for Jx.
+ *
+ * Author: 
+ * Paul Spencer (pspencer at dmsolutions.ca)
+ *
+ * Copyright:
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+Jx.addStyleSheet('tree/tree.css');
+Jx.addStyleSheet('tree/tree_ie.css', true);
+
+/**
+ * Class: Jx.TreeItem 
+ * An item in a tree.  An item is a leaf node that has no children.
+ *
+ * Jx.TreeItem supports selection listeners.  When an item in the tree
+ * is selected by the user, listeners are called by invoking the
+ * selectionChanged method on the listener and passing the tree item
+ * object that was selected.  The application is responsible for
+ * changing the style of the selected item in the tree and for
+ * tracking selection if that is important.
+ * 
+ * When the selection changes, the mouse event that triggered the
+ * selection change is passed to the listener as a lastEvent
+ * member of the tree item object.  You can use this to determine
+ * if the item was clicked, double-clicked, right clicked etc.
+ *
+ * Inherits From:
+ * <Jx.Listener>
+ */
+Jx.TreeItem = Class.create();
+Jx.TreeItem.prototype = {
+    /**
+     * Property: data
+     * {Object} arbitrary data associated with the TreeItem
+     */
+    data : null,
+    /**
+     * Property: domObj
+     * {HTMLElement} a reference to the HTML element that is the TreeItem
+     * in the DOM
+     */
+    domObj : null,
+    /**
+     * Property: parent
+     * {Object} the folder or tree that this item belongs to
+     */
+    parent : null,
+    /**
+     * Property: currentClassName
+     * {String} the current CSS class name for this TreeItem.
+     *
+     * TODO: Property currentClassName
+     * This property does not appear to be used?
+     */
+    currentClassName : null,
+    /**
+     * Property: onClick
+     * {Function} callback function to invoke with the TreeItem is clicked
+     */
+    onClick : null,
+    /**
+     * Property: sl
+     * {Array} an array of selection listeners
+     */
+    sl : null,
+    /**
+     * Property: enabled
+     * {Boolean} is the TreeItem enabled or not?
+     */
+    enabled : null,
+    /**
+     * Property: contextMenu
+     *
+     * {<Jx.ContextMenu>} an optional context menu for the TreeItem
+     */
+    contextMenu : null,
+    /**
+     * Constructor: Jx.TreeItem
+     * Create a new instance of Jx.TreeItem with the associated options
+     *
+     * Parameters:
+     * options - {Object} an object containing the below optional
+     * attributes that control how the TreeItem functions.
+     *
+     * Options:
+     * label - {String} the label to display for the TreeItem
+     * data - {Object} any arbitrary data to be associated with the TreeItem
+     * contextMenu - {<Jx.ContextMenu>} the context menu to trigger if there
+     *      is a right click on the node
+     * imgNode - {String} URL to an image to use for the node of this 
+     *      TreeItem.  Not sure if this should ever be set.
+     * imgIcon - {String} URL to an image to use as the icon next to the
+     *      label of this TreeItem
+     * enabled - {Boolean} the initial state of the TreeItem.  If the 
+     *      TreeItem is not enabled, it cannot be clicked.
+     */
+    initialize : function( options ) {
+        this.initializeItem(options);
+    },
+    /**
+     * Method: initializeItem
+     * internal method to initialize the TreeItem.
+     *
+     * Parameters: 
+     * options - See <Jx.TreeItem::Jx.TreeItem>
+     */
+    initializeItem: function(options) {
+        options = options || {};
+        this.sl = [];
+        var label = options.label || 'new node';
+        this.data = options.data || null;
+        this.contextMenu = options.contextMenu || null;
+        
+        this.imgNode = options.imgNode || Jx.baseURL + 'images/tree_none.png';
+        this.imgIcon = options.imgIcon || Jx.baseURL + 'images/tree_page.png';
+                
+        this.domObj = document.createElement('li');
+        this.domObj.className = 'jxTreeNode';
+        this.currentClassName = 'jxTreeNode';
+      
+        var elm = document.createElement('img');
+        elm.className = 'jxTreeNodeImage';
+        //elm.src = this.imgNode;
+        Jx.addToImgQueue({domElement: elm, src: this.imgNode});
+        this.domObj.appendChild(elm);
+        
+        elm = document.createElement('img');
+        elm.className = 'jxTreeNodeIcon';
+        //elm.src = this.imgIcon;
+        Jx.addToImgQueue({domElement: elm, src: this.imgIcon});
+        this.domObj.appendChild(elm);
+      
+        elm = document.createElement('a');
+        elm.href = 'javascript:void(0)';
+        elm.onclick = this.selected.bindAsEventListener(this);
+        elm.ondblclick = this.selected.bindAsEventListener(this);
+        elm.oncontextmenu = this.showMenu.bindAsEventListener(this);
+        elm.innerHTML = label;
+        this.domObj.appendChild(elm);
+        
+        //this.update(false);
+        //TODO: this could cause a memory leak in remove
+        this.domObj.jxTreeItem = this;
+        this.domObj.childNodes[2].jxTreeItem = this;
+        
+        this.onClick = options.onClick || null;
+        this.enabled = typeof options.enabled != 'undefined' ? options.enabled : true;
+        if (this.enabled) {
+            Element.removeClassName(this.domObj, 'jxDisabled');
+        } else {
+            Element.addClassName(this.domObj, 'jxDisabled');
+        }
+        var clearer = document.createElement('span');
+        clearer.className = 'jxClearer';
+        this.domObj.appendChild(clearer);
+    },
+    /**
+     * Method: finalize
+     * Clean up the TreeItem and remove all DOM references
+     */
+    finalize: function() { this.finalizeItem(); },
+    /**
+     * Method: finalizeItem
+     * Clean up the TreeItem and remove all DOM references
+     */
+    finalizeItem: function() {  
+        if (!this.domObj) {
+            return;
+        }
+        this.domObj.childNodes[2].onclick = null;
+        this.domObj.childNodes[2].ondblclick = null;
+        this.domObj.childNodes[2].oncontextmenu = null;
+        this.contextMenu = null;
+        this.onClick = null;
+        for (var i=this.sl.length; i>=0; i--) {
+            this.removeSelectionListener(this.sl[i]);
+        }
+        this.parent = null;
+        this.domObj.jxTreeItem = null;
+        this.domObj = null;
+    },
+    /**
+     * Method: clone
+     * Create a clone of the TreeItem
+     * 
+     * Returns: 
+     * {<Jx.TreeItem>} a copy of the TreeItem
+     */
+    clone : function() {
+        var options = { label : this.domObj.childNodes[2].innerHTML, 
+                        data : this.data,
+                        onClick : this.onClick,
+                        imgNode : this.imgNode,
+                        imgIcon : this.imgIcon
+                        };
+        var item = new Jx.TreeItem(options);
+        return item;
+    },
+    /**
+     * Method: update
+     * Update the CSS of the TreeItem's DOM element in case it has changed
+     * position
+     *
+     * Parameters:
+     * shouldDescend - {Boolean} propagate changes to child nodes?
+     */
+    update : function(shouldDescend) {
+        var isLast = (arguments.length > 1) ? arguments[1] : 
+                     (this.parent && this.parent.isLastNode(this));
+        if (isLast) {
+            Element.removeClassName(this.domObj, 'jxTreeNode');
+            Element.addClassName(this.domObj, 'jxTreeNodeLast');
+        } else {
+            Element.removeClassName(this.domObj, 'jxTreeNodeLast');
+            Element.addClassName(this.domObj, 'jxTreeNode');
+        }
+    },
+    /**
+     * Method: selected
+     * Called when the DOM element for the TreeItem is clicked, the
+     * node is selected.
+     *
+     * Parameters:
+     * e - {Event} the DOM event
+     */
+    selected : function(e) {
+        this.lastEvent = e?e:event;
+        this.processEvent(this.sl,'selectionChanged',this);
+    },
+    /**
+     * Method: showMenu
+     * Called when the DOM element for the TreeItem is right-clicked.  The
+     * node is selected and the context menu displayed (if there is one).
+     *
+     * Parameters:
+     * e - {Event} the DOM event
+     */
+    showMenu: function(e) {
+        this.lastEvent = e?e:event;
+        this.processEvent(this.sl,'selectionChanged',this);
+        if (this.contextMenu) {
+            this.contextMenu.show(this.lastEvent);
+        }
+        Event.stop(e);
+    },
+    /**
+     * Method: addSelectionListener
+     * Add a selection listener.
+     *
+     * Parameters:
+     * obj - {Object} the object to add as a selection listener
+     */
+    addSelectionListener: function(obj){this.addListener(this.sl, obj);},
+    /**
+     * Method: removeSelectionListener
+     * Remove a selection listener.
+     *
+     * Parameters:
+     * obj - {Object} the object to remove as a selection listener
+     */
+    removeSelectionListener: function(obj) {this.removeListener(this.sl, obj);},
+    /**
+     * Method: getName
+     * Get the label associated with a TreeItem
+     *
+     * Returns: 
+     * {String} the name
+     */
+    getName : function() { return this.domObj.childNodes[2].innerHTML; },
+    /**
+     * Method: setName
+     * Set the label of a TreeItem
+     *
+     * Parameters:
+     * name - {String} the new label
+     */
+    setName : function(name) { this.domObj.childNodes[2].innerHTML = name; },
+    /**
+     * Method: propertyChanged
+     * A property of an object has changed, synchronize the state of the 
+     * TreeItem with the state of the object
+     *
+     * Parameters:
+     * obj - {Object} the object whose state has changed
+     */
+    propertyChanged : function(obj) {
+        this.enabled = obj.isEnabled();
+        if (this.enabled) {
+            Element.removeClassName(this.domObj, 'jxDisabled');
+        } else {
+            Element.addClassName(this.domObj, 'jxDisabled');
+        }
+    }
+};
+Object.extend(Jx.TreeItem.prototype, Jx.Listener.prototype);
+
+/**
+ * Class: Jx.TreeFolder
+ *
+ * A Jx.TreeFolder is an item in a tree that can contain other items.  It is
+ * expandable and collapsible.
+ *
+ * Inherits From:
+ * <Jx.TreeItem>
+ */
+Jx.TreeFolder = Class.create();
+Object.extend(Jx.TreeFolder.prototype, Jx.TreeItem.prototype);
+Object.extend(Jx.TreeFolder.prototype, {
+    /**
+     * Property: subDomObj
+     * {HTMLElement} an HTML container for the things inside the folder
+     */
+    subDomObj : null,
+    /**
+     * Property: nodes
+     * {Array} an array of references to the javascript objects that are
+     * children of this folder
+     */
+    nodes : null,
+    /**
+     * Property: isOpen
+     * {Boolean} is the folder open or not?
+     */
+    isOpen : false,
+    /**
+     * Property: dl
+     * {Array} disclosure listeners
+     */
+    dl : null,
+    /**
+     * Constructor: Jx.TreeFolder
+     * Create a new instance of Jx.TreeFolder
+     *
+     * Parameters:
+     * options - {Object} an object containing any of the options of a
+     * <Jx.TreeItem> (see <Jx.TreeItem::Jx.TreeItem>) plus the following
+     * optional attributes that control how the TreeFolder functions.
+     *
+     * Options:
+     * imgTreePlus - {String} a URL to an image for opening the folder
+     * imgTreeMinus - {String} a URL to an image for closing the folder
+     * imgTreeFolder - {String} a URL to an image to represent the folder
+     *      when it is closed
+     * imgTreeFolderOpen - {String} a URL to an image to represent the folder
+     *      when it is open
+     */
+    initialize : function( options ) {
+        this.initializeFolder(options);
+    },
+    /**
+     * Method: initializeFolder
+     * Internal method for initializing a folder.
+     *
+     * Parameters:
+     * options - {Object} see <Jx.TreeFolder::Jx.TreeFolder> for options.
+     */
+    initializeFolder : function(options) {
+        options = options || {};
+        this.initializeItem(options);
+        
+        this.imgTreePlus = options.imgTreePlus || Jx.baseURL + 'images/tree_plus.png';
+        this.imgTreeMinus = options.imgTreeMinus || Jx.baseURL + 'images/tree_minus.png';
+        
+        this.imgTreeFolder = options.imgTreeFolder || Jx.baseURL + 'images/tree_folder.png';
+        this.imgTreeFolderOpen = options.imgTreeFolderOpen || Jx.baseURL + 'images/tree_folder_open.png';
+        
+        //console.log('imgTreePlus is ' + this.imgTreePlus);
+        //this.domObj.childNodes[0].src = this.imgTreePlus;
+        //this.domObj.childNodes[1].src = this.imgTreeFolder;
+        Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreePlus});
+        Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolder});
+        
+        this.domObj.childNodes[0].onclick = this.clicked.bindAsEventListener(this);
+                
+        this.nodes = [];
+        this.subDomObj = document.createElement('ul');
+        this.domObj.appendChild(this.subDomObj);
+        this.subDomObj.className = 'jxTree';
+        this.isOpen = options.isOpen || false;
+        this.dl = [];
+        if (this.isOpen) {
+            this.expand();
+        } else {
+            this.collapse();
+        }
+    //this.makeDroppable();
+    },
+    /**
+     * Method: finalize
+     * Clean up a TreeFolder.
+     */
+    finalize: function() {
+        this.finalizeFolder();
+        this.finalizeItem();
+        this.subDomObj = null;
+    },
+    /**
+     * Method: finalizeFolder
+     * Internal method to clean up folder-related stuff.
+     */
+    finalizeFolder: function() {
+        this.domObj.childNodes[0].onclick = null;
+        for (var i=this.nodes.length-1; i>=0; i--) {
+            this.nodes[i].finalize();
+            if (this.nodes[i].domObj) this.subDomObj.removeChild(this.nodes[i].domObj);
+            this.nodes.pop();
+        }
+        for (var i=this.dl.length-1; i>=0; i--) {
+            this.removeDisclosureListener(this.dl[i]);
+        }
+    },
+    /*
+    makeDroppable : function() {
+        if (!document.Jx.TreeCurrentTimeout) document.Jx.TreeCurrentTimeout = null;
+        Droppables.add(this.domObj.childNodes[2], {
+            greedy : true,
+            onHover : function(draggable, droppable, overlap) { 
+                var dropped = droppable.parentNode.jxTreeItem;
+                if (document.Jx.TreeCurrentTimeout && 
+                    document.currentDroppable != droppable) {
+                    window.clearTimeout(document.Jx.TreeCurrentTimeout);
+                    document.Jx.TreeCurrentTimeout = null;
+                }
+                if (!document.Jx.TreeCurrentTimeout && 
+                    dropped.nodes && 
+                    !dropped.isOpen)
+                {
+                    document.Jx.TreeCurrentTimeout = window.setTimeout(dropped.expand.bind(dropped), 700);
+                }
+                
+                if (!document.currentHighlight != droppable) {
+                    if (droppable == draggable)
+                    {
+                        Droppables.remove(droppable);
+                    }
+                    if (document.currentDroppable && 
+                        document.currentDroppable != droppable) {
+                        Element.removeClassName(document.currentDroppable, 
+                                                'jxTreeDropzone');
+                    }
+                    
+                    Element.addClassName(droppable, 'jxTreeDropzone');
+                    document.currentDroppable = droppable;
+                }
+            },
+            onDrop : function(draggable, droppable) {
+                var dragged = draggable.jxTreeItem;
+                var dropped = droppable.parentNode.jxTreeItem;
+
+                Element.removeClassName(droppable, 
+                                            'jxTreeDropzone');
+                if (dropped.nodes) {
+                    dragged.parent.remove(dragged);
+                    dropped.append(dragged);
+                    dropped.expand();
+                } else if (dropped.parent != null) {
+                    dragged.parent.remove(dragged);
+                    dropped.parent.insert(dragged,dropped);
+                }
+            }
+        });
+    },
+    */
+    /**
+     * Method: clone
+     * Create a clone of the TreeFolder
+     * 
+     * Returns: 
+     * {<Jx.TreeFolder>} a copy of the TreeFolder
+     */
+    clone : function() {
+        var options = { label : this.domObj.childNodes[2].innerHTML, 
+                        data : this.data,
+                        onClick : this.onClick,
+                        imgTreePlus : this.imgTreePlus,
+                        imgTreeMinus : this.imgTreeMinus,
+                        imgTreeFolder : this.imgTreeFolder,
+                        imgTreeFolderOpen : this.imgTreeFolderOpen
+                        };
+        var node = new Jx.TreeFolder(options);
+        for (var i=0;i<this.nodes.length;i++) {
+            node.append(this.nodes[i].clone());
+        }
+        return node;
+    },
+    /**
+     * Method: isLastNode
+     * Indicates if a node is the last thing in the folder.
+     *
+     * Parameters:
+     * node - {Jx.TreeItem} the node to check
+     *
+     * Returns:
+     *
+     * {Boolean}
+     */
+    isLastNode : function(node) {
+        if (this.nodes.length == 0) {
+            return false;
+        } else {
+            return this.nodes[this.nodes.length-1] == node;
+        }
+    },
+    /**
+     * Method: update
+     * Update the CSS of the TreeFolder's DOM element in case it has changed
+     * position.
+     *
+     * Parameters:
+     * shouldDescend - {Boolean} propagate changes to child nodes?
+     */
+    update : function(bDescend) {
+        /* avoid update if not attached to tree yet */
+        if (!this.parent) return;
+        var bLast = false;
+        if (arguments.length > 1) {
+            bLast = arguments[1];
+        } else {
+            bLast = (this.parent && this.parent.isLastNode(this));
+        }
+        
+        if (bLast) {
+            this.domObj.className = 'jxTreeNodeLast';
+            this.subDomObj.className = 'jxTree';
+        } else {
+            this.domObj.className = 'jxTreeNode';
+            this.subDomObj.className = 'jxTree jxTreeNest';
+        }
+        
+        if (this.isOpen) {
+            //this.domObj.childNodes[0].src = this.imgTreeMinus;
+            //this.domObj.childNodes[1].src = this.imgTreeFolderOpen;
+            Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreeMinus});
+            Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolderOpen});
+        } else {
+            //this.domObj.childNodes[0].src = this.imgTreePlus;
+            //this.domObj.childNodes[1].src = this.imgTreeFolder;
+            Jx.addToImgQueue({domElement: this.domObj.childNodes[0], src: this.imgTreePlus});
+            Jx.addToImgQueue({domElement: this.domObj.childNodes[1], src: this.imgTreeFolder});
+        }
+        
+        if (this.nodes && bDescend) {
+            //this.nodes.each(function(n){n.update(true);});
+            for(var i=0; i<this.nodes.length; i++) {
+                this.nodes[i].update(false, i==this.nodes.length-1);
+            }
+        }
+    },
+    /**
+     * Method: append
+     * append a node at the end of the sub-tree
+     *
+     * Parameters:
+     * node - {Object} the node to append.
+     */
+    append : function( node ) {
+        node.parent = this;
+        this.nodes.push(node);
+        this.subDomObj.appendChild( node.domObj );
+        this.update(true);
+    },
+    /**
+     * Method: insert
+     * insert a node after refNode.  If refNode is null, insert at beginning
+     *
+     * Parameters:
+     * node - {Object} the node to insert
+     * refNode - {Object} the node to insert before
+     */
+    insert : function( node, refNode ) {
+        node.parent = this;
+        //if refNode is not supplied, insert at the beginning.
+        if (!refNode) {
+            this.nodes.unshift(node);
+            //sanity check to make sure there is actually something there
+            if (this.subDomObj.childNodes.length ==0) {
+                this.subDomObj.appendChild(node.domObj);
+            } else {
+                this.subDomObj.insertBefore(node.domObj, this.subDomObj.childNodes[0]);                
+            }
+        } else {
+            //walk all nodes looking for the ref node.  Track if it actually
+            //happens so we can append if it fails.
+            var b = false;
+            for(var i=0;i<this.nodes.length;i++) {
+                if (this.nodes[i] == refNode) {
+                    //increment to append after ref node.  If this pushes us
+                    //past the end, it'll get appended below anyway
+                    i = i + 1;
+                    if (i < this.nodes.length) {
+                        this.nodes.splice(i, 0, node);
+                        this.subDomObj.insertBefore(node.domObj, this.subDomObj.childNodes[i]);
+                        b = true;
+                        break;
+                    }
+                }
+            }
+            //if the node wasn't inserted, it is because refNode didn't exist
+            //and so the fallback is to just append the node.
+            if (!b) {
+                this.nodes.push(node); 
+                this.subDomObj.appendChild(node.domObj); 
+            }
+        }
+        this.update(true);
+        //if (this.parent)
+        //    this.parent.update(true);        
+    },
+    /**
+     * Method: remove
+     * remove the specified node from the tree
+     *
+     * Parameters:
+     * node - {Object} the node to remove
+     */
+    remove : function(node) {
+        node.parent = null;
+        for(var i=0;i<this.nodes.length;i++) {
+            if (this.nodes[i] == node) {
+                this.nodes.splice(i, 1);
+                this.subDomObj.removeChild(this.subDomObj.childNodes[i]);
+                break;
+            }
+        }
+        this.update(true);
+        //if (this.parent)
+        //    this.parent.update(true);        
+    },
+    /**
+     * Method: replace
+     * Replace a node with another node
+     *
+     * Parameters:
+     * newNode - {Object} the node to put into the tree
+     * refNode - {Object} the node to replace
+     *
+     * Returns:
+     * {Boolean} true if the replacement was successful.
+     */
+    replace: function( newNode, refNode ) {
+        //walk all nodes looking for the ref node. 
+        var b = false;
+        for(var i=0;i<this.nodes.length;i++) {
+            if (this.nodes[i] == refNode) {
+                if (i < this.nodes.length) {
+                    newNode.parent = this;
+                    this.nodes.splice(i, 1, newNode);
+                    this.subDomObj.replaceChild(newNode.domObj, refNode.domObj);
+                    return true;
+                }
+            }
+        }
+        return false;
+    },
+    
+    /**
+     * Method: clicked
+     * handle the user clicking on this folder by expanding or
+     * collapsing it.
+     *
+     * Parameters: 
+     * e - {Event} the event object
+     */
+    clicked : function(e) {
+        e = e?e:event;
+        if (this.isOpen) {
+            this.collapse();
+        } else {
+            this.expand();
+        }
+    },
+    /**
+     * Method: expand
+     * Expands the folder
+     */
+    expand : function() {
+        this.isOpen = true;
+        this.subDomObj.style.display = 'block';
+        this.update(true);
+        this.processEvent(this.dl, 'disclosed', this);    
+    },
+    /**
+     * Method: collapse
+     * Collapses the folder
+     */
+    collapse : function() {
+        this.isOpen = false;
+        this.subDomObj.style.display = 'none';
+        this.update(true);
+        this.processEvent(this.dl, 'disclosed', this);
+    },
+    /**
+     * Method: addDisclosureListener
+     * Add a disclosure (when the folder is opened) listener
+     *
+     * Parameters:
+     * obj - {Object} a discloser listener to add
+     */
+    addDisclosureListener: function(obj){this.addListener(this.dl, obj);},
+    /**
+     * Method: removeDisclosureListener
+     * Remove a disclosure listener
+     *
+     * Parameters:
+     * obj - {Object} a discloser listener to remove
+     */
+    removeDisclosureListener: function(obj) {this.removeListener(this.dl, obj);},
+    /**
+     * Method: findChild
+     * Get a reference to a child node by recursively searching the tree
+     * 
+     * Parameters:
+     * path - {Array} an array of labels of nodes to search for
+     *
+     * Returns:
+     * {Object} the node or null if the path was not found
+     */
+    findChild : function(path) {
+        //path is empty - we are asking for this node
+        if (path.length == 0)
+            return this;
+        
+        //path has only one thing in it - looking for something in this folder
+        if (path.length == 1)
+        {
+            for (var i=0; i<this.nodes.length; i++)
+            {
+                if (this.nodes[i].getName() == path[0])
+                    return this.nodes[i];
+            }
+            return null;
+        }
+        //path has more than one thing in it, find a folder and descend into it    
+        var childName = path.shift();
+        for (var i=0; i<this.nodes.length; i++)
+        {
+            if (this.nodes[i].getName() == childName && this.nodes[i].findChild)
+                return this.nodes[i].findChild(path);
+        }
+        return null;
+    }
+});
+
+/**
+ * Class: Jx.Tree
+ * Jx.Tree displays hierarchical data in a tree structure of folders and nodes.
+ *
+ * Inherits From:
+ * <Jx.TreeFolder>
+ */
+Jx.Tree = Class.create();
+Object.extend( Jx.Tree.prototype, Jx.TreeFolder.prototype );
+Object.extend( Jx.Tree.prototype, {
+    /**
+     * Constructor: Jx.Tree
+     * Create a new instance of Jx.Tree
+     *
+     * Parameters:
+     * id - {String} the id of the DOM element to create the tree inside.
+     */
+    initialize : function( id ) {
+        this.subDomObj = document.createElement('ul');
+        this.subDomObj.className = 'jxTreeRoot';
+        $(id).appendChild(this.subDomObj);
+        this.nodes = [];
+        this.dl = [];
+        this.isOpen = true;
+    },
+    /**
+     * Method: finalize
+     * Clean up a Jx.Tree instance
+     */
+    finalize: function() { 
+        this.clear(); 
+        this.subDomObj.parentNode.removeChild(this.subDomObj); 
+    },
+    /**
+     * Method: clear
+     * Clear the tree of all child nodes
+     */
+    clear: function() {
+        for (var i=this.nodes.length-1; i>=0; i--) {
+            this.subDomObj.removeChild(this.nodes[i].domObj);
+            this.nodes[i].finalize();
+            this.nodes.pop();
+        }
+    },
+    /**
+     * Method: update
+     * Update the CSS of the Tree's DOM element in case it has changed
+     * position
+     *
+     * Parameters:
+     * shouldDescend - {Boolean} propagate changes to child nodes?
+     */
+    update: function(shouldDescend) {
+        var bLast = true;
+        if (this.subDomObj)
+        {
+            if (bLast) {
+                Element.removeClassName(this.subDomObj, 'jxTreeNest');
+            } else {
+                Element.addClassName(this.subDomObj, 'jxTreeNest');
+            }
+        }
+        if (this.nodes && shouldDescend) {
+            this.nodes.each(function(n){n.update(false);});
+        }
+    },
+    /**
+     * Method: append
+     * Append a node at the end of the sub-tree
+     * 
+     * Parameters:
+     * node - {Object} the node to append.
+     */
+    append: function( node ) {
+        node.parent = this;
+        this.nodes.push(node);
+        this.subDomObj.appendChild( node.domObj );
+        this.update(true);        
+    }
+});/**
+ * this file is to be loaded/included after all other Jx files 
+ *
+ * Copyright &copy; 2008, DM Solutions Group Inc.
+ */
+/******************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/ 
+
+if (Jx.COMBINED_CSS) {
+    //console.log('Jx.COMBINED_CSS');
+    document.write('<link type="text/css" rel="stylesheet" href="'+Jx.baseURL+'lib/jx_combined.css" />\n');
+} else {
+    //console.log('no Jx.COMBINED_CSS');
+    for (var styleSheet in Jx.importRules) {
+        var url = Jx.baseURL+styleSheet;
+        document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');
+    }
+    document.write('<!--[if IE]>');
+    for (var styleSheet in Jx.importRulesIE) {
+        var url = Jx.baseURL+styleSheet;
+        document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');
+    }
+    document.write('<![endif]-->\n');
+}
\ No newline at end of file

Deleted: sandbox/aboudreault/jx/lib/jx_compressed.js
===================================================================
--- trunk/jx/lib/jx_compressed.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/jx/lib/jx_compressed.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,639 +0,0 @@
-
-var Prototype={Version:'1.5.0',BrowserFeatures:{XPath:!!document.evaluate},ScriptFragment:'(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',emptyFunction:function(){},K:function(x){return x}}
-var Class={create:function(){return function(){this.initialize.apply(this,arguments);}}}
-var Abstract=new Object();Object.extend=function(destination,source){for(var property in source){destination[property]=source[property];}
-return destination;}
-Object.extend(Object,{inspect:function(object){try{if(object===undefined)return'undefined';if(object===null)return'null';return object.inspect?object.inspect():object.toString();}catch(e){if(e instanceof RangeError)return'...';throw e;}},keys:function(object){var keys=[];for(var property in object)
-keys.push(property);return keys;},values:function(object){var values=[];for(var property in object)
-values.push(object[property]);return values;},clone:function(object){return Object.extend({},object);}});Function.prototype.bind=function(){var __method=this,args=$A(arguments),object=args.shift();return function(){return __method.apply(object,args.concat($A(arguments)));}}
-Function.prototype.bindAsEventListener=function(object){var __method=this,args=$A(arguments),object=args.shift();return function(event){return __method.apply(object,[(event||window.event)].concat(args).concat($A(arguments)));}}
-Object.extend(Number.prototype,{toColorPart:function(){var digits=this.toString(16);if(this<16)return'0'+digits;return digits;},succ:function(){return this+1;},times:function(iterator){$R(0,this,true).each(iterator);return this;}});var Try={these:function(){var returnValue;for(var i=0,length=arguments.length;i<length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
-return returnValue;}}
-var PeriodicalExecuter=Class.create();PeriodicalExecuter.prototype={initialize:function(callback,frequency){this.callback=callback;this.frequency=frequency;this.currentlyExecuting=false;this.registerCallback();},registerCallback:function(){this.timer=setInterval(this.onTimerEvent.bind(this),this.frequency*1000);},stop:function(){if(!this.timer)return;clearInterval(this.timer);this.timer=null;},onTimerEvent:function(){if(!this.currentlyExecuting){try{this.currentlyExecuting=true;this.callback(this);}finally{this.currentlyExecuting=false;}}}}
-String.interpret=function(value){return value==null?'':String(value);}
-Object.extend(String.prototype,{gsub:function(pattern,replacement){var result='',source=this,match;replacement=arguments.callee.prepareReplacement(replacement);while(source.length>0){if(match=source.match(pattern)){result+=source.slice(0,match.index);result+=String.interpret(replacement(match));source=source.slice(match.index+match[0].length);}else{result+=source,source='';}}
-return result;},sub:function(pattern,replacement,count){replacement=this.gsub.prepareReplacement(replacement);count=count===undefined?1:count;return this.gsub(pattern,function(match){if(--count<0)return match[0];return replacement(match);});},scan:function(pattern,iterator){this.gsub(pattern,iterator);return this;},truncate:function(length,truncation){length=length||30;truncation=truncation===undefined?'...':truncation;return this.length>length?this.slice(0,length-truncation.length)+truncation:this;},strip:function(){return this.replace(/^\s+/,'').replace(/\s+$/,'');},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,'');},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,'img'),'');},extractScripts:function(){var matchAll=new RegExp(Prototype.ScriptFragment,'img');var matchOne=new RegExp(Prototype.ScriptFragment,'im');return(this.match(matchAll)||[]).map(function(scriptTag){return(scriptTag.match(matchOne)||['',''])[1];});},evalScripts:function(){return this.extractScripts().map(function(script){return eval(script)});},escapeHTML:function(){var div=document.createElement('div');var text=document.createTextNode(this);div.appendChild(text);return div.innerHTML;},unescapeHTML:function(){var div=document.createElement('div');div.innerHTML=this.stripTags();return div.childNodes[0]?(div.childNodes.length>1?$A(div.childNodes).inject('',function(memo,node){return memo+node.nodeValue}):div.childNodes[0].nodeValue):'';},toQueryParams:function(separator){var match=this.strip().match(/([^?#]*)(#.*)?$/);if(!match)return{};return match[1].split(separator||'&').inject({},function(hash,pair){if((pair=pair.split('='))[0]){var name=decodeURIComponent(pair[0]);var value=pair[1]?decodeURIComponent(pair[1]):undefined;if(hash[name]!==undefined){if(hash[name].constructor!=Array)
-hash[name]=[hash[name]];if(value)hash[name].push(value);}
-else hash[name]=value;}
-return hash;});},toArray:function(){return this.split('');},succ:function(){return this.slice(0,this.length-1)+
-String.fromCharCode(this.charCodeAt(this.length-1)+1);},camelize:function(){var parts=this.split('-'),len=parts.length;if(len==1)return parts[0];var camelized=this.charAt(0)=='-'?parts[0].charAt(0).toUpperCase()+parts[0].substring(1):parts[0];for(var i=1;i<len;i++)
-camelized+=parts[i].charAt(0).toUpperCase()+parts[i].substring(1);return camelized;},capitalize:function(){return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase();},underscore:function(){return this.gsub(/::/,'/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();},dasherize:function(){return this.gsub(/_/,'-');},inspect:function(useDoubleQuotes){var escapedString=this.replace(/\\/g,'\\\\');if(useDoubleQuotes)
-return'"'+escapedString.replace(/"/g,'\\"')+'"';else
-return"'"+escapedString.replace(/'/g,'\\\'')+"'";}});String.prototype.gsub.prepareReplacement=function(replacement){if(typeof replacement=='function')return replacement;var template=new Template(replacement);return function(match){return template.evaluate(match)};}
-String.prototype.parseQuery=String.prototype.toQueryParams;var Template=Class.create();Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;Template.prototype={initialize:function(template,pattern){this.template=template.toString();this.pattern=pattern||Template.Pattern;},evaluate:function(object){return this.template.gsub(this.pattern,function(match){var before=match[1];if(before=='\\')return match[2];return before+String.interpret(object[match[3]]);});}}
-var $break=new Object();var $continue=new Object();var Enumerable={each:function(iterator){var index=0;try{this._each(function(value){try{iterator(value,index++);}catch(e){if(e!=$continue)throw e;}});}catch(e){if(e!=$break)throw e;}
-return this;},eachSlice:function(number,iterator){var index=-number,slices=[],array=this.toArray();while((index+=number)<array.length)
-slices.push(array.slice(index,index+number));return slices.map(iterator);},all:function(iterator){var result=true;this.each(function(value,index){result=result&&!!(iterator||Prototype.K)(value,index);if(!result)throw $break;});return result;},any:function(iterator){var result=false;this.each(function(value,index){if(result=!!(iterator||Prototype.K)(value,index))
-throw $break;});return result;},collect:function(iterator){var results=[];this.each(function(value,index){results.push((iterator||Prototype.K)(value,index));});return results;},detect:function(iterator){var result;this.each(function(value,index){if(iterator(value,index)){result=value;throw $break;}});return result;},findAll:function(iterator){var results=[];this.each(function(value,index){if(iterator(value,index))
-results.push(value);});return results;},grep:function(pattern,iterator){var results=[];this.each(function(value,index){var stringValue=value.toString();if(stringValue.match(pattern))
-results.push((iterator||Prototype.K)(value,index));})
-return results;},include:function(object){var found=false;this.each(function(value){if(value==object){found=true;throw $break;}});return found;},inGroupsOf:function(number,fillWith){fillWith=fillWith===undefined?null:fillWith;return this.eachSlice(number,function(slice){while(slice.length<number)slice.push(fillWith);return slice;});},inject:function(memo,iterator){this.each(function(value,index){memo=iterator(memo,value,index);});return memo;},invoke:function(method){var args=$A(arguments).slice(1);return this.map(function(value){return value[method].apply(value,args);});},max:function(iterator){var result;this.each(function(value,index){value=(iterator||Prototype.K)(value,index);if(result==undefined||value>=result)
-result=value;});return result;},min:function(iterator){var result;this.each(function(value,index){value=(iterator||Prototype.K)(value,index);if(result==undefined||value<result)
-result=value;});return result;},partition:function(iterator){var trues=[],falses=[];this.each(function(value,index){((iterator||Prototype.K)(value,index)?trues:falses).push(value);});return[trues,falses];},pluck:function(property){var results=[];this.each(function(value,index){results.push(value[property]);});return results;},reject:function(iterator){var results=[];this.each(function(value,index){if(!iterator(value,index))
-results.push(value);});return results;},sortBy:function(iterator){return this.map(function(value,index){return{value:value,criteria:iterator(value,index)};}).sort(function(left,right){var a=left.criteria,b=right.criteria;return a<b?-1:a>b?1:0;}).pluck('value');},toArray:function(){return this.map();},zip:function(){var iterator=Prototype.K,args=$A(arguments);if(typeof args.last()=='function')
-iterator=args.pop();var collections=[this].concat(args).map($A);return this.map(function(value,index){return iterator(collections.pluck(index));});},size:function(){return this.toArray().length;},inspect:function(){return'#<Enumerable:'+this.toArray().inspect()+'>';}}
-Object.extend(Enumerable,{map:Enumerable.collect,find:Enumerable.detect,select:Enumerable.findAll,member:Enumerable.include,entries:Enumerable.toArray});var $A=Array.from=function(iterable){if(!iterable)return[];if(iterable.toArray){return iterable.toArray();}else{var results=[];for(var i=0,length=iterable.length;i<length;i++)
-results.push(iterable[i]);return results;}}
-Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse)
-Array.prototype._reverse=Array.prototype.reverse;Object.extend(Array.prototype,{_each:function(iterator){for(var i=0,length=this.length;i<length;i++)
-iterator(this[i]);},clear:function(){this.length=0;return this;},first:function(){return this[0];},last:function(){return this[this.length-1];},compact:function(){return this.select(function(value){return value!=null;});},flatten:function(){return this.inject([],function(array,value){return array.concat(value&&value.constructor==Array?value.flatten():[value]);});},without:function(){var values=$A(arguments);return this.select(function(value){return!values.include(value);});},indexOf:function(object){for(var i=0,length=this.length;i<length;i++)
-if(this[i]==object)return i;return-1;},reverse:function(inline){return(inline!==false?this:this.toArray())._reverse();},reduce:function(){return this.length>1?this:this[0];},uniq:function(){return this.inject([],function(array,value){return array.include(value)?array:array.concat([value]);});},clone:function(){return[].concat(this);},size:function(){return this.length;},inspect:function(){return'['+this.map(Object.inspect).join(', ')+']';}});Array.prototype.toArray=Array.prototype.clone;function $w(string){string=string.strip();return string?string.split(/\s+/):[];}
-if(window.opera){Array.prototype.concat=function(){var array=[];for(var i=0,length=this.length;i<length;i++)array.push(this[i]);for(var i=0,length=arguments.length;i<length;i++){if(arguments[i].constructor==Array){for(var j=0,arrayLength=arguments[i].length;j<arrayLength;j++)
-array.push(arguments[i][j]);}else{array.push(arguments[i]);}}
-return array;}}
-var Hash=function(obj){Object.extend(this,obj||{});};Object.extend(Hash,{toQueryString:function(obj){var parts=[];this.prototype._each.call(obj,function(pair){if(!pair.key)return;if(pair.value&&pair.value.constructor==Array){var values=pair.value.compact();if(values.length<2)pair.value=values.reduce();else{key=encodeURIComponent(pair.key);values.each(function(value){value=value!=undefined?encodeURIComponent(value):'';parts.push(key+'='+encodeURIComponent(value));});return;}}
-if(pair.value==undefined)pair[1]='';parts.push(pair.map(encodeURIComponent).join('='));});return parts.join('&');}});Object.extend(Hash.prototype,Enumerable);Object.extend(Hash.prototype,{_each:function(iterator){for(var key in this){var value=this[key];if(value&&value==Hash.prototype[key])continue;var pair=[key,value];pair.key=key;pair.value=value;iterator(pair);}},keys:function(){return this.pluck('key');},values:function(){return this.pluck('value');},merge:function(hash){return $H(hash).inject(this,function(mergedHash,pair){mergedHash[pair.key]=pair.value;return mergedHash;});},remove:function(){var result;for(var i=0,length=arguments.length;i<length;i++){var value=this[arguments[i]];if(value!==undefined){if(result===undefined)result=value;else{if(result.constructor!=Array)result=[result];result.push(value)}}
-delete this[arguments[i]];}
-return result;},toQueryString:function(){return Hash.toQueryString(this);},inspect:function(){return'#<Hash:{'+this.map(function(pair){return pair.map(Object.inspect).join(': ');}).join(', ')+'}>';}});function $H(object){if(object&&object.constructor==Hash)return object;return new Hash(object);};ObjectRange=Class.create();Object.extend(ObjectRange.prototype,Enumerable);Object.extend(ObjectRange.prototype,{initialize:function(start,end,exclusive){this.start=start;this.end=end;this.exclusive=exclusive;},_each:function(iterator){var value=this.start;while(this.include(value)){iterator(value);value=value.succ();}},include:function(value){if(value<this.start)
-return false;if(this.exclusive)
-return value<this.end;return value<=this.end;}});var $R=function(start,end,exclusive){return new ObjectRange(start,end,exclusive);}
-var Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest()},function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')})||false;},activeRequestCount:0}
-Ajax.Responders={responders:[],_each:function(iterator){this.responders._each(iterator);},register:function(responder){if(!this.include(responder))
-this.responders.push(responder);},unregister:function(responder){this.responders=this.responders.without(responder);},dispatch:function(callback,request,transport,json){this.each(function(responder){if(typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}});}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++;},onComplete:function(){Ajax.activeRequestCount--;}});Ajax.Base=function(){};Ajax.Base.prototype={setOptions:function(options){this.options={method:'post',asynchronous:true,contentType:'application/x-www-form-urlencoded',encoding:'UTF-8',parameters:''}
-Object.extend(this.options,options||{});this.options.method=this.options.method.toLowerCase();if(typeof this.options.parameters=='string')
-this.options.parameters=this.options.parameters.toQueryParams();}}
-Ajax.Request=Class.create();Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];Ajax.Request.prototype=Object.extend(new Ajax.Base(),{_complete:false,initialize:function(url,options){this.transport=Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){this.url=url;this.method=this.options.method;var params=this.options.parameters;if(!['get','post'].include(this.method)){params['_method']=this.method;this.method='post';}
-params=Hash.toQueryString(params);if(params&&/Konqueror|Safari|KHTML/.test(navigator.userAgent))params+='&_='
-if(this.method=='get'&&params)
-this.url+=(this.url.indexOf('?')>-1?'&':'?')+params;try{Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous)
-setTimeout(function(){this.respondToReadyState(1)}.bind(this),10);this.transport.onreadystatechange=this.onStateChange.bind(this);this.setRequestHeaders();var body=this.method=='post'?(this.options.postBody||params):null;this.transport.send(body);if(!this.options.asynchronous&&this.transport.overrideMimeType)
-this.onStateChange();}
-catch(e){this.dispatchException(e);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState>1&&!((readyState==4)&&this._complete))
-this.respondToReadyState(this.transport.readyState);},setRequestHeaders:function(){var headers={'X-Requested-With':'XMLHttpRequest','X-Prototype-Version':Prototype.Version,'Accept':'text/javascript, text/html, application/xml, text/xml, */*'};if(this.method=='post'){headers['Content-type']=this.options.contentType+
-(this.options.encoding?'; charset='+this.options.encoding:'');if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005)
-headers['Connection']='close';}
-if(typeof this.options.requestHeaders=='object'){var extras=this.options.requestHeaders;if(typeof extras.push=='function')
-for(var i=0,length=extras.length;i<length;i+=2)
-headers[extras[i]]=extras[i+1];else
-$H(extras).each(function(pair){headers[pair.key]=pair.value});}
-for(var name in headers)
-this.transport.setRequestHeader(name,headers[name]);},success:function(){return!this.transport.status||(this.transport.status>=200&&this.transport.status<300);},respondToReadyState:function(readyState){var state=Ajax.Request.Events[readyState];var transport=this.transport,json=this.evalJSON();if(state=='Complete'){try{this._complete=true;(this.options['on'+this.transport.status]||this.options['on'+(this.success()?'Success':'Failure')]||Prototype.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);}
-if((this.getHeader('Content-type')||'text/javascript').strip().match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
-this.evalResponse();}
-try{(this.options['on'+state]||Prototype.emptyFunction)(transport,json);Ajax.Responders.dispatch('on'+state,this,transport,json);}catch(e){this.dispatchException(e);}
-if(state=='Complete'){this.transport.onreadystatechange=Prototype.emptyFunction;}},getHeader:function(name){try{return this.transport.getResponseHeader(name);}catch(e){return null}},evalJSON:function(){try{var json=this.getHeader('X-JSON');return json?eval('('+json+')'):null;}catch(e){return null}},evalResponse:function(){try{return eval(this.transport.responseText);}catch(e){this.dispatchException(e);}},dispatchException:function(exception){(this.options.onException||Prototype.emptyFunction)(this,exception);Ajax.Responders.dispatch('onException',this,exception);}});Ajax.Updater=Class.create();Object.extend(Object.extend(Ajax.Updater.prototype,Ajax.Request.prototype),{initialize:function(container,url,options){this.container={success:(container.success||container),failure:(container.failure||(container.success?null:container))}
-this.transport=Ajax.getTransport();this.setOptions(options);var onComplete=this.options.onComplete||Prototype.emptyFunction;this.options.onComplete=(function(transport,param){this.updateContent();onComplete(transport,param);}).bind(this);this.request(url);},updateContent:function(){var receiver=this.container[this.success()?'success':'failure'];var response=this.transport.responseText;if(!this.options.evalScripts)response=response.stripScripts();if(receiver=$(receiver)){if(this.options.insertion)
-new this.options.insertion(receiver,response);else
-receiver.update(response);}
-if(this.success()){if(this.onComplete)
-setTimeout(this.onComplete.bind(this),10);}}});Ajax.PeriodicalUpdater=Class.create();Ajax.PeriodicalUpdater.prototype=Object.extend(new Ajax.Base(),{initialize:function(container,url,options){this.setOptions(options);this.onComplete=this.options.onComplete;this.frequency=(this.options.frequency||2);this.decay=(this.options.decay||1);this.updater={};this.container=container;this.url=url;this.start();},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent();},stop:function(){this.updater.options.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,arguments);},updateComplete:function(request){if(this.options.decay){this.decay=(request.responseText==this.lastText?this.decay*this.options.decay:1);this.lastText=request.responseText;}
-this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1000);},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options);}});function $(element){if(arguments.length>1){for(var i=0,elements=[],length=arguments.length;i<length;i++)
-elements.push($(arguments[i]));return elements;}
-if(typeof element=='string')
-element=document.getElementById(element);return Element.extend(element);}
-if(Prototype.BrowserFeatures.XPath){document._getElementsByXPath=function(expression,parentElement){var results=[];var query=document.evaluate(expression,$(parentElement)||document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);for(var i=0,length=query.snapshotLength;i<length;i++)
-results.push(query.snapshotItem(i));return results;};}
-document.getElementsByClassName=function(className,parentElement){if(Prototype.BrowserFeatures.XPath){var q=".//*[contains(concat(' ', @class, ' '), ' "+className+" ')]";return document._getElementsByXPath(q,parentElement);}else{var children=($(parentElement)||document.body).getElementsByTagName('*');var elements=[],child;for(var i=0,length=children.length;i<length;i++){child=children[i];if(Element.hasClassName(child,className))
-elements.push(Element.extend(child));}
-return elements;}};if(!window.Element)
-var Element=new Object();Element.extend=function(element){if(!element||_nativeExtensions||element.nodeType==3)return element;if(!element._extended&&element.tagName&&element!=window){var methods=Object.clone(Element.Methods),cache=Element.extend.cache;if(element.tagName=='FORM')
-Object.extend(methods,Form.Methods);if(['INPUT','TEXTAREA','SELECT'].include(element.tagName))
-Object.extend(methods,Form.Element.Methods);Object.extend(methods,Element.Methods.Simulated);for(var property in methods){var value=methods[property];if(typeof value=='function'&&!(property in element))
-element[property]=cache.findOrStore(value);}}
-element._extended=true;return element;};Element.extend.cache={findOrStore:function(value){return this[value]=this[value]||function(){return value.apply(null,[this].concat($A(arguments)));}}};Element.Methods={visible:function(element){return $(element).style.display!='none';},toggle:function(element){element=$(element);Element[Element.visible(element)?'hide':'show'](element);return element;},hide:function(element){$(element).style.display='none';return element;},show:function(element){$(element).style.display='';return element;},remove:function(element){element=$(element);element.parentNode.removeChild(element);return element;},update:function(element,html){html=typeof html=='undefined'?'':html.toString();$(element).innerHTML=html.stripScripts();setTimeout(function(){html.evalScripts()},10);return element;},replace:function(element,html){element=$(element);html=typeof html=='undefined'?'':html.toString();if(element.outerHTML){element.outerHTML=html.stripScripts();}else{var range=element.ownerDocument.createRange();range.selectNodeContents(element);element.parentNode.replaceChild(range.createContextualFragment(html.stripScripts()),element);}
-setTimeout(function(){html.evalScripts()},10);return element;},inspect:function(element){element=$(element);var result='<'+element.tagName.toLowerCase();$H({'id':'id','className':'class'}).each(function(pair){var property=pair.first(),attribute=pair.last();var value=(element[property]||'').toString();if(value)result+=' '+attribute+'='+value.inspect(true);});return result+'>';},recursivelyCollect:function(element,property){element=$(element);var elements=[];while(element=element[property])
-if(element.nodeType==1)
-elements.push(Element.extend(element));return elements;},ancestors:function(element){return $(element).recursivelyCollect('parentNode');},descendants:function(element){return $A($(element).getElementsByTagName('*'));},immediateDescendants:function(element){if(!(element=$(element).firstChild))return[];while(element&&element.nodeType!=1)element=element.nextSibling;if(element)return[element].concat($(element).nextSiblings());return[];},previousSiblings:function(element){return $(element).recursivelyCollect('previousSibling');},nextSiblings:function(element){return $(element).recursivelyCollect('nextSibling');},siblings:function(element){element=$(element);return element.previousSiblings().reverse().concat(element.nextSiblings());},match:function(element,selector){if(typeof selector=='string')
-selector=new Selector(selector);return selector.match($(element));},up:function(element,expression,index){return Selector.findElement($(element).ancestors(),expression,index);},down:function(element,expression,index){return Selector.findElement($(element).descendants(),expression,index);},previous:function(element,expression,index){return Selector.findElement($(element).previousSiblings(),expression,index);},next:function(element,expression,index){return Selector.findElement($(element).nextSiblings(),expression,index);},getElementsBySelector:function(){var args=$A(arguments),element=$(args.shift());return Selector.findChildElements(element,args);},getElementsByClassName:function(element,className){return document.getElementsByClassName(className,element);},readAttribute:function(element,name){element=$(element);if(document.all&&!window.opera){var t=Element._attributeTranslations;if(t.values[name])return t.values[name](element,name);if(t.names[name])name=t.names[name];var attribute=element.attributes[name];if(attribute)return attribute.nodeValue;}
-return element.getAttribute(name);},getHeight:function(element){return $(element).getDimensions().height;},getWidth:function(element){return $(element).getDimensions().width;},classNames:function(element){return new Element.ClassNames(element);},hasClassName:function(element,className){if(!(element=$(element)))return;var elementClassName=element.className;if(elementClassName.length==0)return false;if(elementClassName==className||elementClassName.match(new RegExp("(^|\\s)"+className+"(\\s|$)")))
-return true;return false;},addClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element).add(className);return element;},removeClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element).remove(className);return element;},toggleClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element)[element.hasClassName(className)?'remove':'add'](className);return element;},observe:function(){Event.observe.apply(Event,arguments);return $A(arguments).first();},stopObserving:function(){Event.stopObserving.apply(Event,arguments);return $A(arguments).first();},cleanWhitespace:function(element){element=$(element);var node=element.firstChild;while(node){var nextNode=node.nextSibling;if(node.nodeType==3&&!/\S/.test(node.nodeValue))
-element.removeChild(node);node=nextNode;}
-return element;},empty:function(element){return $(element).innerHTML.match(/^\s*$/);},descendantOf:function(element,ancestor){element=$(element),ancestor=$(ancestor);while(element=element.parentNode)
-if(element==ancestor)return true;return false;},scrollTo:function(element){element=$(element);var pos=Position.cumulativeOffset(element);window.scrollTo(pos[0],pos[1]);return element;},getStyle:function(element,style){element=$(element);if(['float','cssFloat'].include(style))
-style=(typeof element.style.styleFloat!='undefined'?'styleFloat':'cssFloat');style=style.camelize();var value=element.style[style];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css[style]:null;}else if(element.currentStyle){value=element.currentStyle[style];}}
-if((value=='auto')&&['width','height'].include(style)&&(element.getStyle('display')!='none'))
-value=element['offset'+style.capitalize()]+'px';if(window.opera&&['left','top','right','bottom'].include(style))
-if(Element.getStyle(element,'position')=='static')value='auto';if(style=='opacity'){if(value)return parseFloat(value);if(value=(element.getStyle('filter')||'').match(/alpha\(opacity=(.*)\)/))
-if(value[1])return parseFloat(value[1])/100;return 1.0;}
-return value=='auto'?null:value;},setStyle:function(element,style){element=$(element);for(var name in style){var value=style[name];if(name=='opacity'){if(value==1){value=(/Gecko/.test(navigator.userAgent)&&!/Konqueror|Safari|KHTML/.test(navigator.userAgent))?0.999999:1.0;if(/MSIE/.test(navigator.userAgent)&&!window.opera)
-element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');}else if(value===''){if(/MSIE/.test(navigator.userAgent)&&!window.opera)
-element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');}else{if(value<0.00001)value=0;if(/MSIE/.test(navigator.userAgent)&&!window.opera)
-element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'')+'alpha(opacity='+value*100+')';}}else if(['float','cssFloat'].include(name))name=(typeof element.style.styleFloat!='undefined')?'styleFloat':'cssFloat';element.style[name.camelize()]=value;}
-return element;},getDimensions:function(element){element=$(element);var display=$(element).getStyle('display');if(display!='none'&&display!=null)
-return{width:element.offsetWidth,height:element.offsetHeight};var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;var originalDisplay=els.display;els.visibility='hidden';els.position='absolute';els.display='block';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display=originalDisplay;els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},makePositioned:function(element){element=$(element);var pos=Element.getStyle(element,'position');if(pos=='static'||!pos){element._madePositioned=true;element.style.position='relative';if(window.opera){element.style.top=0;element.style.left=0;}}
-return element;},undoPositioned:function(element){element=$(element);if(element._madePositioned){element._madePositioned=undefined;element.style.position=element.style.top=element.style.left=element.style.bottom=element.style.right='';}
-return element;},makeClipping:function(element){element=$(element);if(element._overflow)return element;element._overflow=element.style.overflow||'auto';if((Element.getStyle(element,'overflow')||'visible')!='hidden')
-element.style.overflow='hidden';return element;},undoClipping:function(element){element=$(element);if(!element._overflow)return element;element.style.overflow=element._overflow=='auto'?'':element._overflow;element._overflow=null;return element;}};Object.extend(Element.Methods,{childOf:Element.Methods.descendantOf});Element._attributeTranslations={};Element._attributeTranslations.names={colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",datetime:"dateTime",accesskey:"accessKey",tabindex:"tabIndex",enctype:"encType",maxlength:"maxLength",readonly:"readOnly",longdesc:"longDesc"};Element._attributeTranslations.values={_getAttr:function(element,attribute){return element.getAttribute(attribute,2);},_flag:function(element,attribute){return $(element).hasAttribute(attribute)?attribute:null;},style:function(element){return element.style.cssText.toLowerCase();},title:function(element){var node=element.getAttributeNode('title');return node.specified?node.nodeValue:null;}};Object.extend(Element._attributeTranslations.values,{href:Element._attributeTranslations.values._getAttr,src:Element._attributeTranslations.values._getAttr,disabled:Element._attributeTranslations.values._flag,checked:Element._attributeTranslations.values._flag,readonly:Element._attributeTranslations.values._flag,multiple:Element._attributeTranslations.values._flag});Element.Methods.Simulated={hasAttribute:function(element,attribute){var t=Element._attributeTranslations;attribute=t.names[attribute]||attribute;return $(element).getAttributeNode(attribute).specified;}};if(document.all&&!window.opera){Element.Methods.update=function(element,html){element=$(element);html=typeof html=='undefined'?'':html.toString();var tagName=element.tagName.toUpperCase();if(['THEAD','TBODY','TR','TD'].include(tagName)){var div=document.createElement('div');switch(tagName){case'THEAD':case'TBODY':div.innerHTML='<table><tbody>'+html.stripScripts()+'</tbody></table>';depth=2;break;case'TR':div.innerHTML='<table><tbody><tr>'+html.stripScripts()+'</tr></tbody></table>';depth=3;break;case'TD':div.innerHTML='<table><tbody><tr><td>'+html.stripScripts()+'</td></tr></tbody></table>';depth=4;}
-$A(element.childNodes).each(function(node){element.removeChild(node)});depth.times(function(){div=div.firstChild});$A(div.childNodes).each(function(node){element.appendChild(node)});}else{element.innerHTML=html.stripScripts();}
-setTimeout(function(){html.evalScripts()},10);return element;}};Object.extend(Element,Element.Methods);var _nativeExtensions=false;if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
-['','Form','Input','TextArea','Select'].each(function(tag){var className='HTML'+tag+'Element';if(window[className])return;var klass=window[className]={};klass.prototype=document.createElement(tag?tag.toLowerCase():'div').__proto__;});Element.addMethods=function(methods){Object.extend(Element.Methods,methods||{});function copy(methods,destination,onlyIfAbsent){onlyIfAbsent=onlyIfAbsent||false;var cache=Element.extend.cache;for(var property in methods){var value=methods[property];if(!onlyIfAbsent||!(property in destination))
-destination[property]=cache.findOrStore(value);}}
-if(typeof HTMLElement!='undefined'){copy(Element.Methods,HTMLElement.prototype);copy(Element.Methods.Simulated,HTMLElement.prototype,true);copy(Form.Methods,HTMLFormElement.prototype);[HTMLInputElement,HTMLTextAreaElement,HTMLSelectElement].each(function(klass){copy(Form.Element.Methods,klass.prototype);});_nativeExtensions=true;}}
-var Toggle=new Object();Toggle.display=Element.toggle;Abstract.Insertion=function(adjacency){this.adjacency=adjacency;}
-Abstract.Insertion.prototype={initialize:function(element,content){this.element=$(element);this.content=content.stripScripts();if(this.adjacency&&this.element.insertAdjacentHTML){try{this.element.insertAdjacentHTML(this.adjacency,this.content);}catch(e){var tagName=this.element.tagName.toUpperCase();if(['TBODY','TR'].include(tagName)){this.insertContent(this.contentFromAnonymousTable());}else{throw e;}}}else{this.range=this.element.ownerDocument.createRange();if(this.initializeRange)this.initializeRange();this.insertContent([this.range.createContextualFragment(this.content)]);}
-setTimeout(function(){content.evalScripts()},10);},contentFromAnonymousTable:function(){var div=document.createElement('div');div.innerHTML='<table><tbody>'+this.content+'</tbody></table>';return $A(div.childNodes[0].childNodes[0].childNodes);}}
-var Insertion=new Object();Insertion.Before=Class.create();Insertion.Before.prototype=Object.extend(new Abstract.Insertion('beforeBegin'),{initializeRange:function(){this.range.setStartBefore(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.parentNode.insertBefore(fragment,this.element);}).bind(this));}});Insertion.Top=Class.create();Insertion.Top.prototype=Object.extend(new Abstract.Insertion('afterBegin'),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(true);},insertContent:function(fragments){fragments.reverse(false).each((function(fragment){this.element.insertBefore(fragment,this.element.firstChild);}).bind(this));}});Insertion.Bottom=Class.create();Insertion.Bottom.prototype=Object.extend(new Abstract.Insertion('beforeEnd'),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.appendChild(fragment);}).bind(this));}});Insertion.After=Class.create();Insertion.After.prototype=Object.extend(new Abstract.Insertion('afterEnd'),{initializeRange:function(){this.range.setStartAfter(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.parentNode.insertBefore(fragment,this.element.nextSibling);}).bind(this));}});Element.ClassNames=Class.create();Element.ClassNames.prototype={initialize:function(element){this.element=$(element);},_each:function(iterator){this.element.className.split(/\s+/).select(function(name){return name.length>0;})._each(iterator);},set:function(className){this.element.className=className;},add:function(classNameToAdd){if(this.include(classNameToAdd))return;this.set($A(this).concat(classNameToAdd).join(' '));},remove:function(classNameToRemove){if(!this.include(classNameToRemove))return;this.set($A(this).without(classNameToRemove).join(' '));},toString:function(){return $A(this).join(' ');}};Object.extend(Element.ClassNames.prototype,Enumerable);var Selector=Class.create();Selector.prototype={initialize:function(expression){this.params={classNames:[]};this.expression=expression.toString().strip();this.parseExpression();this.compileMatcher();},parseExpression:function(){function abort(message){throw'Parse error in selector: '+message;}
-if(this.expression=='')abort('empty expression');var params=this.params,expr=this.expression,match,modifier,clause,rest;while(match=expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)){params.attributes=params.attributes||[];params.attributes.push({name:match[2],operator:match[3],value:match[4]||match[5]||''});expr=match[1];}
-if(expr=='*')return this.params.wildcard=true;while(match=expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)){modifier=match[1],clause=match[2],rest=match[3];switch(modifier){case'#':params.id=clause;break;case'.':params.classNames.push(clause);break;case'':case undefined:params.tagName=clause.toUpperCase();break;default:abort(expr.inspect());}
-expr=rest;}
-if(expr.length>0)abort(expr.inspect());},buildMatchExpression:function(){var params=this.params,conditions=[],clause;if(params.wildcard)
-conditions.push('true');if(clause=params.id)
-conditions.push('element.readAttribute("id") == '+clause.inspect());if(clause=params.tagName)
-conditions.push('element.tagName.toUpperCase() == '+clause.inspect());if((clause=params.classNames).length>0)
-for(var i=0,length=clause.length;i<length;i++)
-conditions.push('element.hasClassName('+clause[i].inspect()+')');if(clause=params.attributes){clause.each(function(attribute){var value='element.readAttribute('+attribute.name.inspect()+')';var splitValueBy=function(delimiter){return value+' && '+value+'.split('+delimiter.inspect()+')';}
-switch(attribute.operator){case'=':conditions.push(value+' == '+attribute.value.inspect());break;case'~=':conditions.push(splitValueBy(' ')+'.include('+attribute.value.inspect()+')');break;case'|=':conditions.push(splitValueBy('-')+'.first().toUpperCase() == '+attribute.value.toUpperCase().inspect());break;case'!=':conditions.push(value+' != '+attribute.value.inspect());break;case'':case undefined:conditions.push('element.hasAttribute('+attribute.name.inspect()+')');break;default:throw'Unknown operator '+attribute.operator+' in selector';}});}
-return conditions.join(' && ');},compileMatcher:function(){this.match=new Function('element','if (!element.tagName) return false; element = $(element); return '+this.buildMatchExpression());},findElements:function(scope){var element;if(element=$(this.params.id))
-if(this.match(element))
-if(!scope||Element.childOf(element,scope))
-return[element];scope=(scope||document).getElementsByTagName(this.params.tagName||'*');var results=[];for(var i=0,length=scope.length;i<length;i++)
-if(this.match(element=scope[i]))
-results.push(Element.extend(element));return results;},toString:function(){return this.expression;}}
-Object.extend(Selector,{matchElements:function(elements,expression){var selector=new Selector(expression);return elements.select(selector.match.bind(selector)).map(Element.extend);},findElement:function(elements,expression,index){if(typeof expression=='number')index=expression,expression=false;return Selector.matchElements(elements,expression||'*')[index||0];},findChildElements:function(element,expressions){return expressions.map(function(expression){return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null],function(results,expr){var selector=new Selector(expr);return results.inject([],function(elements,result){return elements.concat(selector.findElements(result||element));});});}).flatten();}});function $$(){return Selector.findChildElements(document,$A(arguments));}
-var Form={reset:function(form){$(form).reset();return form;},serializeElements:function(elements,getHash){var data=elements.inject({},function(result,element){if(!element.disabled&&element.name){var key=element.name,value=$(element).getValue();if(value!=undefined){if(result[key]){if(result[key].constructor!=Array)result[key]=[result[key]];result[key].push(value);}
-else result[key]=value;}}
-return result;});return getHash?data:Hash.toQueryString(data);}};Form.Methods={serialize:function(form,getHash){return Form.serializeElements(Form.getElements(form),getHash);},getElements:function(form){return $A($(form).getElementsByTagName('*')).inject([],function(elements,child){if(Form.Element.Serializers[child.tagName.toLowerCase()])
-elements.push(Element.extend(child));return elements;});},getInputs:function(form,typeName,name){form=$(form);var inputs=form.getElementsByTagName('input');if(!typeName&&!name)return $A(inputs).map(Element.extend);for(var i=0,matchingInputs=[],length=inputs.length;i<length;i++){var input=inputs[i];if((typeName&&input.type!=typeName)||(name&&input.name!=name))
-continue;matchingInputs.push(Element.extend(input));}
-return matchingInputs;},disable:function(form){form=$(form);form.getElements().each(function(element){element.blur();element.disabled='true';});return form;},enable:function(form){form=$(form);form.getElements().each(function(element){element.disabled='';});return form;},findFirstElement:function(form){return $(form).getElements().find(function(element){return element.type!='hidden'&&!element.disabled&&['input','select','textarea'].include(element.tagName.toLowerCase());});},focusFirstElement:function(form){form=$(form);form.findFirstElement().activate();return form;}}
-Object.extend(Form,Form.Methods);Form.Element={focus:function(element){$(element).focus();return element;},select:function(element){$(element).select();return element;}}
-Form.Element.Methods={serialize:function(element){element=$(element);if(!element.disabled&&element.name){var value=element.getValue();if(value!=undefined){var pair={};pair[element.name]=value;return Hash.toQueryString(pair);}}
-return'';},getValue:function(element){element=$(element);var method=element.tagName.toLowerCase();return Form.Element.Serializers[method](element);},clear:function(element){$(element).value='';return element;},present:function(element){return $(element).value!='';},activate:function(element){element=$(element);element.focus();if(element.select&&(element.tagName.toLowerCase()!='input'||!['button','reset','submit'].include(element.type)))
-element.select();return element;},disable:function(element){element=$(element);element.disabled=true;return element;},enable:function(element){element=$(element);element.blur();element.disabled=false;return element;}}
-Object.extend(Form.Element,Form.Element.Methods);var Field=Form.Element;var $F=Form.Element.getValue;Form.Element.Serializers={input:function(element){switch(element.type.toLowerCase()){case'checkbox':case'radio':return Form.Element.Serializers.inputSelector(element);default:return Form.Element.Serializers.textarea(element);}},inputSelector:function(element){return element.checked?element.value:null;},textarea:function(element){return element.value;},select:function(element){return this[element.type=='select-one'?'selectOne':'selectMany'](element);},selectOne:function(element){var index=element.selectedIndex;return index>=0?this.optionValue(element.options[index]):null;},selectMany:function(element){var values,length=element.length;if(!length)return null;for(var i=0,values=[];i<length;i++){var opt=element.options[i];if(opt.selected)values.push(this.optionValue(opt));}
-return values;},optionValue:function(opt){return Element.extend(opt).hasAttribute('value')?opt.value:opt.text;}}
-Abstract.TimedObserver=function(){}
-Abstract.TimedObserver.prototype={initialize:function(element,frequency,callback){this.frequency=frequency;this.element=$(element);this.callback=callback;this.lastValue=this.getValue();this.registerCallback();},registerCallback:function(){setInterval(this.onTimerEvent.bind(this),this.frequency*1000);},onTimerEvent:function(){var value=this.getValue();var changed=('string'==typeof this.lastValue&&'string'==typeof value?this.lastValue!=value:String(this.lastValue)!=String(value));if(changed){this.callback(this.element,value);this.lastValue=value;}}}
-Form.Element.Observer=Class.create();Form.Element.Observer.prototype=Object.extend(new Abstract.TimedObserver(),{getValue:function(){return Form.Element.getValue(this.element);}});Form.Observer=Class.create();Form.Observer.prototype=Object.extend(new Abstract.TimedObserver(),{getValue:function(){return Form.serialize(this.element);}});Abstract.EventObserver=function(){}
-Abstract.EventObserver.prototype={initialize:function(element,callback){this.element=$(element);this.callback=callback;this.lastValue=this.getValue();if(this.element.tagName.toLowerCase()=='form')
-this.registerFormCallbacks();else
-this.registerCallback(this.element);},onElementEvent:function(){var value=this.getValue();if(this.lastValue!=value){this.callback(this.element,value);this.lastValue=value;}},registerFormCallbacks:function(){Form.getElements(this.element).each(this.registerCallback.bind(this));},registerCallback:function(element){if(element.type){switch(element.type.toLowerCase()){case'checkbox':case'radio':Event.observe(element,'click',this.onElementEvent.bind(this));break;default:Event.observe(element,'change',this.onElementEvent.bind(this));break;}}}}
-Form.Element.EventObserver=Class.create();Form.Element.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.Element.getValue(this.element);}});Form.EventObserver=Class.create();Form.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.serialize(this.element);}});if(!window.Event){var Event=new Object();}
-Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_HOME:36,KEY_END:35,KEY_PAGEUP:33,KEY_PAGEDOWN:34,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},pointerX:function(event){return event.pageX||(event.clientX+
-(document.documentElement.scrollLeft||document.body.scrollLeft));},pointerY:function(event){return event.pageY||(event.clientY+
-(document.documentElement.scrollTop||document.body.scrollTop));},stop:function(event){if(event.preventDefault){event.preventDefault();event.stopPropagation();}else{event.returnValue=false;event.cancelBubble=true;}},findElement:function(event,tagName){var element=Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
-element=element.parentNode;return element;},observers:false,_observeAndCache:function(element,name,observer,useCapture){if(!this.observers)this.observers=[];if(element.addEventListener){this.observers.push([element,name,observer,useCapture]);element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){this.observers.push([element,name,observer,useCapture]);element.attachEvent('on'+name,observer);}},unloadCache:function(){if(!Event.observers)return;for(var i=0,length=Event.observers.length;i<length;i++){Event.stopObserving.apply(this,Event.observers[i]);Event.observers[i][0]=null;}
-Event.observers=false;},observe:function(element,name,observer,useCapture){element=$(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent))
-name='keydown';Event._observeAndCache(element,name,observer,useCapture);},stopObserving:function(element,name,observer,useCapture){element=$(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent))
-name='keydown';if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element.detachEvent){try{element.detachEvent('on'+name,observer);}catch(e){}}}});if(navigator.appVersion.match(/\bMSIE\b/))
-Event.observe(window,'unload',Event.unloadCache,false);var Position={includeScrollOffsets:false,prepare:function(){this.deltaX=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;this.deltaY=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;},realOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.scrollTop||0;valueL+=element.scrollLeft||0;element=element.parentNode;}while(element);return[valueL,valueT];},cumulativeOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;element=element.offsetParent;}while(element);return[valueL,valueT];},positionedOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;element=element.offsetParent;if(element){if(element.tagName=='BODY')break;var p=Element.getStyle(element,'position');if(p=='relative'||p=='absolute')break;}}while(element);return[valueL,valueT];},offsetParent:function(element){if(element.offsetParent)return element.offsetParent;if(element==document.body)return element;while((element=element.parentNode)&&element!=document.body)
-if(Element.getStyle(element,'position')!='static')
-return element;return document.body;},within:function(element,x,y){if(this.includeScrollOffsets)
-return this.withinIncludingScrolloffsets(element,x,y);this.xcomp=x;this.ycomp=y;this.offset=this.cumulativeOffset(element);return(y>=this.offset[1]&&y<this.offset[1]+element.offsetHeight&&x>=this.offset[0]&&x<this.offset[0]+element.offsetWidth);},withinIncludingScrolloffsets:function(element,x,y){var offsetcache=this.realOffset(element);this.xcomp=x+offsetcache[0]-this.deltaX;this.ycomp=y+offsetcache[1]-this.deltaY;this.offset=this.cumulativeOffset(element);return(this.ycomp>=this.offset[1]&&this.ycomp<this.offset[1]+element.offsetHeight&&this.xcomp>=this.offset[0]&&this.xcomp<this.offset[0]+element.offsetWidth);},overlap:function(mode,element){if(!mode)return 0;if(mode=='vertical')
-return((this.offset[1]+element.offsetHeight)-this.ycomp)/element.offsetHeight;if(mode=='horizontal')
-return((this.offset[0]+element.offsetWidth)-this.xcomp)/element.offsetWidth;},page:function(forElement){var valueT=0,valueL=0;var element=forElement;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;if(element.offsetParent==document.body)
-if(Element.getStyle(element,'position')=='absolute')break;}while(element=element.offsetParent);element=forElement;do{if(!window.opera||element.tagName=='BODY'){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;}}while(element=element.parentNode);return[valueL,valueT];},clone:function(source,target){var options=Object.extend({setLeft:true,setTop:true,setWidth:true,setHeight:true,offsetTop:0,offsetLeft:0},arguments[2]||{})
-source=$(source);var p=Position.page(source);target=$(target);var delta=[0,0];var parent=null;if(Element.getStyle(target,'position')=='absolute'){parent=Position.offsetParent(target);delta=Position.page(parent);}
-if(parent==document.body){delta[0]-=document.body.offsetLeft;delta[1]-=document.body.offsetTop;}
-if(options.setLeft)target.style.left=(p[0]-delta[0]+options.offsetLeft)+'px';if(options.setTop)target.style.top=(p[1]-delta[1]+options.offsetTop)+'px';if(options.setWidth)target.style.width=source.offsetWidth+'px';if(options.setHeight)target.style.height=source.offsetHeight+'px';},absolutize:function(element){element=$(element);if(element.style.position=='absolute')return;Position.prepare();var offsets=Position.positionedOffset(element);var top=offsets[1];var left=offsets[0];var width=element.clientWidth;var height=element.clientHeight;element._originalLeft=left-parseFloat(element.style.left||0);element._originalTop=top-parseFloat(element.style.top||0);element._originalWidth=element.style.width;element._originalHeight=element.style.height;element.style.position='absolute';element.style.top=top+'px';element.style.left=left+'px';element.style.width=width+'px';element.style.height=height+'px';},relativize:function(element){element=$(element);if(element.style.position=='relative')return;Position.prepare();element.style.position='relative';var top=parseFloat(element.style.top||0)-(element._originalTop||0);var left=parseFloat(element.style.left||0)-(element._originalLeft||0);element.style.top=top+'px';element.style.left=left+'px';element.style.height=element._originalHeight;element.style.width=element._originalWidth;}}
-if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){Position.cumulativeOffset=function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;if(element.offsetParent==document.body)
-if(Element.getStyle(element,'position')=='absolute')break;element=element.offsetParent;}while(element);return[valueL,valueT];}}
-Element.addMethods();var Builder={NODEMAP:{AREA:'map',CAPTION:'table',COL:'table',COLGROUP:'table',LEGEND:'fieldset',OPTGROUP:'select',OPTION:'select',PARAM:'object',TBODY:'table',TD:'table',TFOOT:'table',TH:'table',THEAD:'table',TR:'table'},node:function(elementName){elementName=elementName.toUpperCase();var parentTag=this.NODEMAP[elementName]||'div';var parentElement=document.createElement(parentTag);try{parentElement.innerHTML="<"+elementName+"></"+elementName+">";}catch(e){}
-var element=parentElement.firstChild||null;if(element&&(element.tagName.toUpperCase()!=elementName))
-element=element.getElementsByTagName(elementName)[0];if(!element)element=document.createElement(elementName);if(!element)return;if(arguments[1])
-if(this._isStringOrNumber(arguments[1])||(arguments[1]instanceof Array)){this._children(element,arguments[1]);}else{var attrs=this._attributes(arguments[1]);if(attrs.length){try{parentElement.innerHTML="<"+elementName+" "+
-attrs+"></"+elementName+">";}catch(e){}
-element=parentElement.firstChild||null;if(!element){element=document.createElement(elementName);for(attr in arguments[1])
-element[attr=='class'?'className':attr]=arguments[1][attr];}
-if(element.tagName.toUpperCase()!=elementName)
-element=parentElement.getElementsByTagName(elementName)[0];}}
-if(arguments[2])
-this._children(element,arguments[2]);return element;},_text:function(text){return document.createTextNode(text);},ATTR_MAP:{'className':'class','htmlFor':'for'},_attributes:function(attributes){var attrs=[];for(attribute in attributes)
-attrs.push((attribute in this.ATTR_MAP?this.ATTR_MAP[attribute]:attribute)+'="'+attributes[attribute].toString().escapeHTML()+'"');return attrs.join(" ");},_children:function(element,children){if(typeof children=='object'){children.flatten().each(function(e){if(typeof e=='object')
-element.appendChild(e)
-else
-if(Builder._isStringOrNumber(e))
-element.appendChild(Builder._text(e));});}else
-if(Builder._isStringOrNumber(children))
-element.appendChild(Builder._text(children));},_isStringOrNumber:function(param){return(typeof param=='string'||typeof param=='number');},build:function(html){var element=this.node('div');$(element).update(html.strip());return element.down();},dump:function(scope){if(typeof scope!='object'&&typeof scope!='function')scope=window;var tags=("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY "+"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET "+"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);tags.each(function(tag){scope[tag]=function(){return Builder.node.apply(Builder,[tag].concat($A(arguments)));}});}}
-String.prototype.parseColor=function(){var color='#';if(this.slice(0,4)=='rgb('){var cols=this.slice(4,this.length-1).split(',');var i=0;do{color+=parseInt(cols[i]).toColorPart()}while(++i<3);}else{if(this.slice(0,1)=='#'){if(this.length==4)for(var i=1;i<4;i++)color+=(this.charAt(i)+this.charAt(i)).toLowerCase();if(this.length==7)color=this.toLowerCase();}}
-return(color.length==7?color:(arguments[0]||this));}
-Element.collectTextNodes=function(element){return $A($(element).childNodes).collect(function(node){return(node.nodeType==3?node.nodeValue:(node.hasChildNodes()?Element.collectTextNodes(node):''));}).flatten().join('');}
-Element.collectTextNodesIgnoreClass=function(element,className){return $A($(element).childNodes).collect(function(node){return(node.nodeType==3?node.nodeValue:((node.hasChildNodes()&&!Element.hasClassName(node,className))?Element.collectTextNodesIgnoreClass(node,className):''));}).flatten().join('');}
-Element.setContentZoom=function(element,percent){element=$(element);element.setStyle({fontSize:(percent/100)+'em'});if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);return element;}
-Element.getOpacity=function(element){return $(element).getStyle('opacity');}
-Element.setOpacity=function(element,value){return $(element).setStyle({opacity:value});}
-Element.getInlineOpacity=function(element){return $(element).style.opacity||'';}
-Element.forceRerendering=function(element){try{element=$(element);var n=document.createTextNode(' ');element.appendChild(n);element.removeChild(n);}catch(e){}};Array.prototype.call=function(){var args=arguments;this.each(function(f){f.apply(this,args)});}
-var Effect={_elementDoesNotExistError:{name:'ElementDoesNotExistError',message:'The specified DOM element does not exist, but is required for this effect to operate'},tagifyText:function(element){if(typeof Builder=='undefined')
-throw("Effect.tagifyText requires including script.aculo.us' builder.js library");var tagifyStyle='position:relative';if(/MSIE/.test(navigator.userAgent)&&!window.opera)tagifyStyle+=';zoom:1';element=$(element);$A(element.childNodes).each(function(child){if(child.nodeType==3){child.nodeValue.toArray().each(function(character){element.insertBefore(Builder.node('span',{style:tagifyStyle},character==' '?String.fromCharCode(160):character),child);});Element.remove(child);}});},multiple:function(element,effect){var elements;if(((typeof element=='object')||(typeof element=='function'))&&(element.length))
-elements=element;else
-elements=$(element).childNodes;var options=Object.extend({speed:0.1,delay:0.0},arguments[2]||{});var masterDelay=options.delay;$A(elements).each(function(element,index){new effect(element,Object.extend(options,{delay:index*options.speed+masterDelay}));});},PAIRS:{'slide':['SlideDown','SlideUp'],'blind':['BlindDown','BlindUp'],'appear':['Appear','Fade']},toggle:function(element,effect){element=$(element);effect=(effect||'appear').toLowerCase();var options=Object.extend({queue:{position:'end',scope:(element.id||'global'),limit:1}},arguments[2]||{});Effect[element.visible()?Effect.PAIRS[effect][1]:Effect.PAIRS[effect][0]](element,options);}};var Effect2=Effect;Effect.Transitions={linear:Prototype.K,sinoidal:function(pos){return(-Math.cos(pos*Math.PI)/2)+0.5;},reverse:function(pos){return 1-pos;},flicker:function(pos){return((-Math.cos(pos*Math.PI)/4)+0.75)+Math.random()/4;},wobble:function(pos){return(-Math.cos(pos*Math.PI*(9*pos))/2)+0.5;},pulse:function(pos,pulses){pulses=pulses||5;return(Math.round((pos%(1/pulses))*pulses)==0?((pos*pulses*2)-Math.floor(pos*pulses*2)):1-((pos*pulses*2)-Math.floor(pos*pulses*2)));},none:function(pos){return 0;},full:function(pos){return 1;}};Effect.ScopedQueue=Class.create();Object.extend(Object.extend(Effect.ScopedQueue.prototype,Enumerable),{initialize:function(){this.effects=[];this.interval=null;},_each:function(iterator){this.effects._each(iterator);},add:function(effect){var timestamp=new Date().getTime();var position=(typeof effect.options.queue=='string')?effect.options.queue:effect.options.queue.position;switch(position){case'front':this.effects.findAll(function(e){return e.state=='idle'}).each(function(e){e.startOn+=effect.finishOn;e.finishOn+=effect.finishOn;});break;case'with-last':timestamp=this.effects.pluck('startOn').max()||timestamp;break;case'end':timestamp=this.effects.pluck('finishOn').max()||timestamp;break;}
-effect.startOn+=timestamp;effect.finishOn+=timestamp;if(!effect.options.queue.limit||(this.effects.length<effect.options.queue.limit))
-this.effects.push(effect);if(!this.interval)
-this.interval=setInterval(this.loop.bind(this),15);},remove:function(effect){this.effects=this.effects.reject(function(e){return e==effect});if(this.effects.length==0){clearInterval(this.interval);this.interval=null;}},loop:function(){var timePos=new Date().getTime();for(var i=0,len=this.effects.length;i<len;i++)
-if(this.effects[i])this.effects[i].loop(timePos);}});Effect.Queues={instances:$H(),get:function(queueName){if(typeof queueName!='string')return queueName;if(!this.instances[queueName])
-this.instances[queueName]=new Effect.ScopedQueue();return this.instances[queueName];}}
-Effect.Queue=Effect.Queues.get('global');Effect.DefaultOptions={transition:Effect.Transitions.sinoidal,duration:1.0,fps:60.0,sync:false,from:0.0,to:1.0,delay:0.0,queue:'parallel'}
-Effect.Base=function(){};Effect.Base.prototype={position:null,start:function(options){this.options=Object.extend(Object.extend({},Effect.DefaultOptions),options||{});this.currentFrame=0;this.state='idle';this.startOn=this.options.delay*1000;this.finishOn=this.startOn+(this.options.duration*1000);this.event('beforeStart');if(!this.options.sync)
-Effect.Queues.get(typeof this.options.queue=='string'?'global':this.options.queue.scope).add(this);},loop:function(timePos){if(timePos>=this.startOn){if(timePos>=this.finishOn){this.render(1.0);this.cancel();this.event('beforeFinish');if(this.finish)this.finish();this.event('afterFinish');return;}
-var pos=(timePos-this.startOn)/(this.finishOn-this.startOn);var frame=Math.round(pos*this.options.fps*this.options.duration);if(frame>this.currentFrame){this.render(pos);this.currentFrame=frame;}}},render:function(pos){if(this.state=='idle'){this.state='running';this.event('beforeSetup');if(this.setup)this.setup();this.event('afterSetup');}
-if(this.state=='running'){if(this.options.transition)pos=this.options.transition(pos);pos*=(this.options.to-this.options.from);pos+=this.options.from;this.position=pos;this.event('beforeUpdate');if(this.update)this.update(pos);this.event('afterUpdate');}},cancel:function(){if(!this.options.sync)
-Effect.Queues.get(typeof this.options.queue=='string'?'global':this.options.queue.scope).remove(this);this.state='finished';},event:function(eventName){if(this.options[eventName+'Internal'])this.options[eventName+'Internal'](this);if(this.options[eventName])this.options[eventName](this);},inspect:function(){var data=$H();for(property in this)
-if(typeof this[property]!='function')data[property]=this[property];return'#<Effect:'+data.inspect()+',options:'+$H(this.options).inspect()+'>';}}
-Effect.Parallel=Class.create();Object.extend(Object.extend(Effect.Parallel.prototype,Effect.Base.prototype),{initialize:function(effects){this.effects=effects||[];this.start(arguments[1]);},update:function(position){this.effects.invoke('render',position);},finish:function(position){this.effects.each(function(effect){effect.render(1.0);effect.cancel();effect.event('beforeFinish');if(effect.finish)effect.finish(position);effect.event('afterFinish');});}});Effect.Event=Class.create();Object.extend(Object.extend(Effect.Event.prototype,Effect.Base.prototype),{initialize:function(){var options=Object.extend({duration:0},arguments[0]||{});this.start(options);},update:Prototype.emptyFunction});Effect.Opacity=Class.create();Object.extend(Object.extend(Effect.Opacity.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);if(/MSIE/.test(navigator.userAgent)&&!window.opera&&(!this.element.currentStyle.hasLayout))
-this.element.setStyle({zoom:1});var options=Object.extend({from:this.element.getOpacity()||0.0,to:1.0},arguments[1]||{});this.start(options);},update:function(position){this.element.setOpacity(position);}});Effect.Move=Class.create();Object.extend(Object.extend(Effect.Move.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({x:0,y:0,mode:'relative'},arguments[1]||{});this.start(options);},setup:function(){this.element.makePositioned();this.originalLeft=parseFloat(this.element.getStyle('left')||'0');this.originalTop=parseFloat(this.element.getStyle('top')||'0');if(this.options.mode=='absolute'){this.options.x=this.options.x-this.originalLeft;this.options.y=this.options.y-this.originalTop;}},update:function(position){this.element.setStyle({left:Math.round(this.options.x*position+this.originalLeft)+'px',top:Math.round(this.options.y*position+this.originalTop)+'px'});}});Effect.MoveBy=function(element,toTop,toLeft){return new Effect.Move(element,Object.extend({x:toLeft,y:toTop},arguments[3]||{}));};Effect.Scale=Class.create();Object.extend(Object.extend(Effect.Scale.prototype,Effect.Base.prototype),{initialize:function(element,percent){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({scaleX:true,scaleY:true,scaleContent:true,scaleFromCenter:false,scaleMode:'box',scaleFrom:100.0,scaleTo:percent},arguments[2]||{});this.start(options);},setup:function(){this.restoreAfterFinish=this.options.restoreAfterFinish||false;this.elementPositioning=this.element.getStyle('position');this.originalStyle={};['top','left','width','height','fontSize'].each(function(k){this.originalStyle[k]=this.element.style[k];}.bind(this));this.originalTop=this.element.offsetTop;this.originalLeft=this.element.offsetLeft;var fontSize=this.element.getStyle('font-size')||'100%';['em','px','%','pt'].each(function(fontSizeType){if(fontSize.indexOf(fontSizeType)>0){this.fontSize=parseFloat(fontSize);this.fontSizeType=fontSizeType;}}.bind(this));this.factor=(this.options.scaleTo-this.options.scaleFrom)/100;this.dims=null;if(this.options.scaleMode=='box')
-this.dims=[this.element.offsetHeight,this.element.offsetWidth];if(/^content/.test(this.options.scaleMode))
-this.dims=[this.element.scrollHeight,this.element.scrollWidth];if(!this.dims)
-this.dims=[this.options.scaleMode.originalHeight,this.options.scaleMode.originalWidth];},update:function(position){var currentScale=(this.options.scaleFrom/100.0)+(this.factor*position);if(this.options.scaleContent&&this.fontSize)
-this.element.setStyle({fontSize:this.fontSize*currentScale+this.fontSizeType});this.setDimensions(this.dims[0]*currentScale,this.dims[1]*currentScale);},finish:function(position){if(this.restoreAfterFinish)this.element.setStyle(this.originalStyle);},setDimensions:function(height,width){var d={};if(this.options.scaleX)d.width=Math.round(width)+'px';if(this.options.scaleY)d.height=Math.round(height)+'px';if(this.options.scaleFromCenter){var topd=(height-this.dims[0])/2;var leftd=(width-this.dims[1])/2;if(this.elementPositioning=='absolute'){if(this.options.scaleY)d.top=this.originalTop-topd+'px';if(this.options.scaleX)d.left=this.originalLeft-leftd+'px';}else{if(this.options.scaleY)d.top=-topd+'px';if(this.options.scaleX)d.left=-leftd+'px';}}
-this.element.setStyle(d);}});Effect.Highlight=Class.create();Object.extend(Object.extend(Effect.Highlight.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({startcolor:'#ffff99'},arguments[1]||{});this.start(options);},setup:function(){if(this.element.getStyle('display')=='none'){this.cancel();return;}
-this.oldStyle={};if(!this.options.keepBackgroundImage){this.oldStyle.backgroundImage=this.element.getStyle('background-image');this.element.setStyle({backgroundImage:'none'});}
-if(!this.options.endcolor)
-this.options.endcolor=this.element.getStyle('background-color').parseColor('#ffffff');if(!this.options.restorecolor)
-this.options.restorecolor=this.element.getStyle('background-color');this._base=$R(0,2).map(function(i){return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16)}.bind(this));this._delta=$R(0,2).map(function(i){return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i]}.bind(this));},update:function(position){this.element.setStyle({backgroundColor:$R(0,2).inject('#',function(m,v,i){return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart());}.bind(this))});},finish:function(){this.element.setStyle(Object.extend(this.oldStyle,{backgroundColor:this.options.restorecolor}));}});Effect.ScrollTo=Class.create();Object.extend(Object.extend(Effect.ScrollTo.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);this.start(arguments[1]||{});},setup:function(){Position.prepare();var offsets=Position.cumulativeOffset(this.element);if(this.options.offset)offsets[1]+=this.options.offset;var max=window.innerHeight?window.height-window.innerHeight:document.body.scrollHeight-
-(document.documentElement.clientHeight?document.documentElement.clientHeight:document.body.clientHeight);this.scrollStart=Position.deltaY;this.delta=(offsets[1]>max?max:offsets[1])-this.scrollStart;},update:function(position){Position.prepare();window.scrollTo(Position.deltaX,this.scrollStart+(position*this.delta));}});Effect.Fade=function(element){element=$(element);var oldOpacity=element.getInlineOpacity();var options=Object.extend({from:element.getOpacity()||1.0,to:0.0,afterFinishInternal:function(effect){if(effect.options.to!=0)return;effect.element.hide().setStyle({opacity:oldOpacity});}},arguments[1]||{});return new Effect.Opacity(element,options);}
-Effect.Appear=function(element){element=$(element);var options=Object.extend({from:(element.getStyle('display')=='none'?0.0:element.getOpacity()||0.0),to:1.0,afterFinishInternal:function(effect){effect.element.forceRerendering();},beforeSetup:function(effect){effect.element.setOpacity(effect.options.from).show();}},arguments[1]||{});return new Effect.Opacity(element,options);}
-Effect.Puff=function(element){element=$(element);var oldStyle={opacity:element.getInlineOpacity(),position:element.getStyle('position'),top:element.style.top,left:element.style.left,width:element.style.width,height:element.style.height};return new Effect.Parallel([new Effect.Scale(element,200,{sync:true,scaleFromCenter:true,scaleContent:true,restoreAfterFinish:true}),new Effect.Opacity(element,{sync:true,to:0.0})],Object.extend({duration:1.0,beforeSetupInternal:function(effect){Position.absolutize(effect.effects[0].element)},afterFinishInternal:function(effect){effect.effects[0].element.hide().setStyle(oldStyle);}},arguments[1]||{}));}
-Effect.BlindUp=function(element){element=$(element);element.makeClipping();return new Effect.Scale(element,0,Object.extend({scaleContent:false,scaleX:false,restoreAfterFinish:true,afterFinishInternal:function(effect){effect.element.hide().undoClipping();}},arguments[1]||{}));}
-Effect.BlindDown=function(element){element=$(element);var elementDimensions=element.getDimensions();return new Effect.Scale(element,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:0,scaleMode:{originalHeight:elementDimensions.height,originalWidth:elementDimensions.width},restoreAfterFinish:true,afterSetup:function(effect){effect.element.makeClipping().setStyle({height:'0px'}).show();},afterFinishInternal:function(effect){effect.element.undoClipping();}},arguments[1]||{}));}
-Effect.SwitchOff=function(element){element=$(element);var oldOpacity=element.getInlineOpacity();return new Effect.Appear(element,Object.extend({duration:0.4,from:0,transition:Effect.Transitions.flicker,afterFinishInternal:function(effect){new Effect.Scale(effect.element,1,{duration:0.3,scaleFromCenter:true,scaleX:false,scaleContent:false,restoreAfterFinish:true,beforeSetup:function(effect){effect.element.makePositioned().makeClipping();},afterFinishInternal:function(effect){effect.element.hide().undoClipping().undoPositioned().setStyle({opacity:oldOpacity});}})}},arguments[1]||{}));}
-Effect.DropOut=function(element){element=$(element);var oldStyle={top:element.getStyle('top'),left:element.getStyle('left'),opacity:element.getInlineOpacity()};return new Effect.Parallel([new Effect.Move(element,{x:0,y:100,sync:true}),new Effect.Opacity(element,{sync:true,to:0.0})],Object.extend({duration:0.5,beforeSetup:function(effect){effect.effects[0].element.makePositioned();},afterFinishInternal:function(effect){effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);}},arguments[1]||{}));}
-Effect.Shake=function(element){element=$(element);var oldStyle={top:element.getStyle('top'),left:element.getStyle('left')};return new Effect.Move(element,{x:20,y:0,duration:0.05,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-20,y:0,duration:0.05,afterFinishInternal:function(effect){effect.element.undoPositioned().setStyle(oldStyle);}})}})}})}})}})}});}
-Effect.SlideDown=function(element){element=$(element).cleanWhitespace();var oldInnerBottom=element.down().getStyle('bottom');var elementDimensions=element.getDimensions();return new Effect.Scale(element,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:window.opera?0:1,scaleMode:{originalHeight:elementDimensions.height,originalWidth:elementDimensions.width},restoreAfterFinish:true,afterSetup:function(effect){effect.element.makePositioned();effect.element.down().makePositioned();if(window.opera)effect.element.setStyle({top:''});effect.element.makeClipping().setStyle({height:'0px'}).show();},afterUpdateInternal:function(effect){effect.element.down().setStyle({bottom:(effect.dims[0]-effect.element.clientHeight)+'px'});},afterFinishInternal:function(effect){effect.element.undoClipping().undoPositioned();effect.element.down().undoPositioned().setStyle({bottom:oldInnerBottom});}},arguments[1]||{}));}
-Effect.SlideUp=function(element){element=$(element).cleanWhitespace();var oldInnerBottom=element.down().getStyle('bottom');return new Effect.Scale(element,window.opera?0:1,Object.extend({scaleContent:false,scaleX:false,scaleMode:'box',scaleFrom:100,restoreAfterFinish:true,beforeStartInternal:function(effect){effect.element.makePositioned();effect.element.down().makePositioned();if(window.opera)effect.element.setStyle({top:''});effect.element.makeClipping().show();},afterUpdateInternal:function(effect){effect.element.down().setStyle({bottom:(effect.dims[0]-effect.element.clientHeight)+'px'});},afterFinishInternal:function(effect){effect.element.hide().undoClipping().undoPositioned().setStyle({bottom:oldInnerBottom});effect.element.down().undoPositioned();}},arguments[1]||{}));}
-Effect.Squish=function(element){return new Effect.Scale(element,window.opera?1:0,{restoreAfterFinish:true,beforeSetup:function(effect){effect.element.makeClipping();},afterFinishInternal:function(effect){effect.element.hide().undoClipping();}});}
-Effect.Grow=function(element){element=$(element);var options=Object.extend({direction:'center',moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.full},arguments[1]||{});var oldStyle={top:element.style.top,left:element.style.left,height:element.style.height,width:element.style.width,opacity:element.getInlineOpacity()};var dims=element.getDimensions();var initialMoveX,initialMoveY;var moveX,moveY;switch(options.direction){case'top-left':initialMoveX=initialMoveY=moveX=moveY=0;break;case'top-right':initialMoveX=dims.width;initialMoveY=moveY=0;moveX=-dims.width;break;case'bottom-left':initialMoveX=moveX=0;initialMoveY=dims.height;moveY=-dims.height;break;case'bottom-right':initialMoveX=dims.width;initialMoveY=dims.height;moveX=-dims.width;moveY=-dims.height;break;case'center':initialMoveX=dims.width/2;initialMoveY=dims.height/2;moveX=-dims.width/2;moveY=-dims.height/2;break;}
-return new Effect.Move(element,{x:initialMoveX,y:initialMoveY,duration:0.01,beforeSetup:function(effect){effect.element.hide().makeClipping().makePositioned();},afterFinishInternal:function(effect){new Effect.Parallel([new Effect.Opacity(effect.element,{sync:true,to:1.0,from:0.0,transition:options.opacityTransition}),new Effect.Move(effect.element,{x:moveX,y:moveY,sync:true,transition:options.moveTransition}),new Effect.Scale(effect.element,100,{scaleMode:{originalHeight:dims.height,originalWidth:dims.width},sync:true,scaleFrom:window.opera?1:0,transition:options.scaleTransition,restoreAfterFinish:true})],Object.extend({beforeSetup:function(effect){effect.effects[0].element.setStyle({height:'0px'}).show();},afterFinishInternal:function(effect){effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);}},options))}});}
-Effect.Shrink=function(element){element=$(element);var options=Object.extend({direction:'center',moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.none},arguments[1]||{});var oldStyle={top:element.style.top,left:element.style.left,height:element.style.height,width:element.style.width,opacity:element.getInlineOpacity()};var dims=element.getDimensions();var moveX,moveY;switch(options.direction){case'top-left':moveX=moveY=0;break;case'top-right':moveX=dims.width;moveY=0;break;case'bottom-left':moveX=0;moveY=dims.height;break;case'bottom-right':moveX=dims.width;moveY=dims.height;break;case'center':moveX=dims.width/2;moveY=dims.height/2;break;}
-return new Effect.Parallel([new Effect.Opacity(element,{sync:true,to:0.0,from:1.0,transition:options.opacityTransition}),new Effect.Scale(element,window.opera?1:0,{sync:true,transition:options.scaleTransition,restoreAfterFinish:true}),new Effect.Move(element,{x:moveX,y:moveY,sync:true,transition:options.moveTransition})],Object.extend({beforeStartInternal:function(effect){effect.effects[0].element.makePositioned().makeClipping();},afterFinishInternal:function(effect){effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle);}},options));}
-Effect.Pulsate=function(element){element=$(element);var options=arguments[1]||{};var oldOpacity=element.getInlineOpacity();var transition=options.transition||Effect.Transitions.sinoidal;var reverser=function(pos){return transition(1-Effect.Transitions.pulse(pos,options.pulses))};reverser.bind(transition);return new Effect.Opacity(element,Object.extend(Object.extend({duration:2.0,from:0,afterFinishInternal:function(effect){effect.element.setStyle({opacity:oldOpacity});}},options),{transition:reverser}));}
-Effect.Fold=function(element){element=$(element);var oldStyle={top:element.style.top,left:element.style.left,width:element.style.width,height:element.style.height};element.makeClipping();return new Effect.Scale(element,5,Object.extend({scaleContent:false,scaleX:false,afterFinishInternal:function(effect){new Effect.Scale(element,1,{scaleContent:false,scaleY:false,afterFinishInternal:function(effect){effect.element.hide().undoClipping().setStyle(oldStyle);}});}},arguments[1]||{}));};Effect.Morph=Class.create();Object.extend(Object.extend(Effect.Morph.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({style:{}},arguments[1]||{});if(typeof options.style=='string'){if(options.style.indexOf(':')==-1){var cssText='',selector='.'+options.style;$A(document.styleSheets).reverse().each(function(styleSheet){if(styleSheet.cssRules)cssRules=styleSheet.cssRules;else if(styleSheet.rules)cssRules=styleSheet.rules;$A(cssRules).reverse().each(function(rule){if(selector==rule.selectorText){cssText=rule.style.cssText;throw $break;}});if(cssText)throw $break;});this.style=cssText.parseStyle();options.afterFinishInternal=function(effect){effect.element.addClassName(effect.options.style);effect.transforms.each(function(transform){if(transform.style!='opacity')
-effect.element.style[transform.style.camelize()]='';});}}else this.style=options.style.parseStyle();}else this.style=$H(options.style)
-this.start(options);},setup:function(){function parseColor(color){if(!color||['rgba(0, 0, 0, 0)','transparent'].include(color))color='#ffffff';color=color.parseColor();return $R(0,2).map(function(i){return parseInt(color.slice(i*2+1,i*2+3),16)});}
-this.transforms=this.style.map(function(pair){var property=pair[0].underscore().dasherize(),value=pair[1],unit=null;if(value.parseColor('#zzzzzz')!='#zzzzzz'){value=value.parseColor();unit='color';}else if(property=='opacity'){value=parseFloat(value);if(/MSIE/.test(navigator.userAgent)&&!window.opera&&(!this.element.currentStyle.hasLayout))
-this.element.setStyle({zoom:1});}else if(Element.CSS_LENGTH.test(value))
-var components=value.match(/^([\+\-]?[0-9\.]+)(.*)$/),value=parseFloat(components[1]),unit=(components.length==3)?components[2]:null;var originalValue=this.element.getStyle(property);return $H({style:property,originalValue:unit=='color'?parseColor(originalValue):parseFloat(originalValue||0),targetValue:unit=='color'?parseColor(value):value,unit:unit});}.bind(this)).reject(function(transform){return((transform.originalValue==transform.targetValue)||(transform.unit!='color'&&(isNaN(transform.originalValue)||isNaN(transform.targetValue))))});},update:function(position){var style=$H(),value=null;this.transforms.each(function(transform){value=transform.unit=='color'?$R(0,2).inject('#',function(m,v,i){return m+(Math.round(transform.originalValue[i]+
-(transform.targetValue[i]-transform.originalValue[i])*position)).toColorPart()}):transform.originalValue+Math.round(((transform.targetValue-transform.originalValue)*position)*1000)/1000+transform.unit;style[transform.style]=value;});this.element.setStyle(style);}});Effect.Transform=Class.create();Object.extend(Effect.Transform.prototype,{initialize:function(tracks){this.tracks=[];this.options=arguments[1]||{};this.addTracks(tracks);},addTracks:function(tracks){tracks.each(function(track){var data=$H(track).values().first();this.tracks.push($H({ids:$H(track).keys().first(),effect:Effect.Morph,options:{style:data}}));}.bind(this));return this;},play:function(){return new Effect.Parallel(this.tracks.map(function(track){var elements=[$(track.ids)||$$(track.ids)].flatten();return elements.map(function(e){return new track.effect(e,Object.extend({sync:true},track.options))});}).flatten(),this.options);}});Element.CSS_PROPERTIES=$w('backgroundColor backgroundPosition borderBottomColor borderBottomStyle '+'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth '+'borderRightColor borderRightStyle borderRightWidth borderSpacing '+'borderTopColor borderTopStyle borderTopWidth bottom clip color '+'fontSize fontWeight height left letterSpacing lineHeight '+'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+'maxWidth minHeight minWidth opacity outlineColor outlineOffset '+'outlineWidth paddingBottom paddingLeft paddingRight paddingTop '+'right textIndent top width wordSpacing zIndex');Element.CSS_LENGTH=/^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;String.prototype.parseStyle=function(){var element=Element.extend(document.createElement('div'));element.innerHTML='<div style="'+this+'"></div>';var style=element.down().style,styleRules=$H();Element.CSS_PROPERTIES.each(function(property){if(style[property])styleRules[property]=style[property];});if(/MSIE/.test(navigator.userAgent)&&!window.opera&&this.indexOf('opacity')>-1){styleRules.opacity=this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];}
-return styleRules;};Element.morph=function(element,style){new Effect.Morph(element,Object.extend({style:style},arguments[2]||{}));return element;};['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom','collectTextNodes','collectTextNodesIgnoreClass','morph'].each(function(f){Element.Methods[f]=Element[f];});Element.Methods.visualEffect=function(element,effect,options){s=effect.gsub(/_/,'-').camelize();effect_class=s.charAt(0).toUpperCase()+s.substring(1);new Effect[effect_class](element,options);return $(element);};Element.addMethods();if(typeof Effect=='undefined')
-throw("dragdrop.js requires including script.aculo.us' effects.js library");var Droppables={drops:[],remove:function(element){this.drops=this.drops.reject(function(d){return d.element==$(element)});},add:function(element){element=$(element);var options=Object.extend({greedy:true,hoverclass:null,tree:false},arguments[1]||{});if(options.containment){options._containers=[];var containment=options.containment;if((typeof containment=='object')&&(containment.constructor==Array)){containment.each(function(c){options._containers.push($(c))});}else{options._containers.push($(containment));}}
-if(options.accept)options.accept=[options.accept].flatten();Element.makePositioned(element);options.element=element;this.drops.push(options);},findDeepestChild:function(drops){deepest=drops[0];for(i=1;i<drops.length;++i)
-if(Element.isParent(drops[i].element,deepest.element))
-deepest=drops[i];return deepest;},isContained:function(element,drop){var containmentNode;if(drop.tree){containmentNode=element.treeNode;}else{containmentNode=element.parentNode;}
-return drop._containers.detect(function(c){return containmentNode==c});},isAffected:function(point,element,drop){return((drop.element!=element)&&((!drop._containers)||this.isContained(element,drop))&&((!drop.accept)||(Element.classNames(element).detect(function(v){return drop.accept.include(v)})))&&Position.within(drop.element,point[0],point[1]));},deactivate:function(drop){if(drop.hoverclass)
-Element.removeClassName(drop.element,drop.hoverclass);this.last_active=null;},activate:function(drop){if(drop.hoverclass)
-Element.addClassName(drop.element,drop.hoverclass);this.last_active=drop;},show:function(point,element){if(!this.drops.length)return;var affected=[];if(this.last_active)this.deactivate(this.last_active);this.drops.each(function(drop){if(Droppables.isAffected(point,element,drop))
-affected.push(drop);});if(affected.length>0){drop=Droppables.findDeepestChild(affected);Position.within(drop.element,point[0],point[1]);if(drop.onHover)
-drop.onHover(element,drop.element,Position.overlap(drop.overlap,drop.element));Droppables.activate(drop);}},fire:function(event,element){if(!this.last_active)return;Position.prepare();if(this.isAffected([Event.pointerX(event),Event.pointerY(event)],element,this.last_active))
-if(this.last_active.onDrop)
-this.last_active.onDrop(element,this.last_active.element,event);},reset:function(){if(this.last_active)
-this.deactivate(this.last_active);}}
-var Draggables={drags:[],observers:[],register:function(draggable){if(this.drags.length==0){this.eventMouseUp=this.endDrag.bindAsEventListener(this);this.eventMouseMove=this.updateDrag.bindAsEventListener(this);this.eventKeypress=this.keyPress.bindAsEventListener(this);Event.observe(document,"mouseup",this.eventMouseUp);Event.observe(document,"mousemove",this.eventMouseMove);Event.observe(document,"keypress",this.eventKeypress);}
-this.drags.push(draggable);},unregister:function(draggable){this.drags=this.drags.reject(function(d){return d==draggable});if(this.drags.length==0){Event.stopObserving(document,"mouseup",this.eventMouseUp);Event.stopObserving(document,"mousemove",this.eventMouseMove);Event.stopObserving(document,"keypress",this.eventKeypress);}},activate:function(draggable){if(draggable.options.delay){this._timeout=setTimeout(function(){Draggables._timeout=null;window.focus();Draggables.activeDraggable=draggable;}.bind(this),draggable.options.delay);}else{window.focus();this.activeDraggable=draggable;}},deactivate:function(){this.activeDraggable=null;},updateDrag:function(event){if(!this.activeDraggable)return;var pointer=[Event.pointerX(event),Event.pointerY(event)];if(this._lastPointer&&(this._lastPointer.inspect()==pointer.inspect()))return;this._lastPointer=pointer;this.activeDraggable.updateDrag(event,pointer);},endDrag:function(event){if(this._timeout){clearTimeout(this._timeout);this._timeout=null;}
-if(!this.activeDraggable)return;this._lastPointer=null;this.activeDraggable.endDrag(event);this.activeDraggable=null;},keyPress:function(event){if(this.activeDraggable)
-this.activeDraggable.keyPress(event);},addObserver:function(observer){this.observers.push(observer);this._cacheObserverCallbacks();},removeObserver:function(element){this.observers=this.observers.reject(function(o){return o.element==element});this._cacheObserverCallbacks();},notify:function(eventName,draggable,event){if(this[eventName+'Count']>0)
-this.observers.each(function(o){if(o[eventName])o[eventName](eventName,draggable,event);});if(draggable.options[eventName])draggable.options[eventName](draggable,event);},_cacheObserverCallbacks:function(){['onStart','onEnd','onDrag'].each(function(eventName){Draggables[eventName+'Count']=Draggables.observers.select(function(o){return o[eventName];}).length;});}}
-var Draggable=Class.create();Draggable._dragging={};Draggable.prototype={initialize:function(element){var defaults={handle:false,reverteffect:function(element,top_offset,left_offset){var dur=Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;new Effect.Move(element,{x:-left_offset,y:-top_offset,duration:dur,queue:{scope:'_draggable',position:'end'}});},endeffect:function(element){var toOpacity=typeof element._opacity=='number'?element._opacity:1.0;new Effect.Opacity(element,{duration:0.2,from:0.7,to:toOpacity,queue:{scope:'_draggable',position:'end'},afterFinish:function(){Draggable._dragging[element]=false}});},zindex:1000,revert:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,snap:false,delay:0};if(!arguments[1]||typeof arguments[1].endeffect=='undefined')
-Object.extend(defaults,{starteffect:function(element){element._opacity=Element.getOpacity(element);Draggable._dragging[element]=true;new Effect.Opacity(element,{duration:0.2,from:element._opacity,to:0.7});}});var options=Object.extend(defaults,arguments[1]||{});this.element=$(element);if(options.handle&&(typeof options.handle=='string'))
-this.handle=this.element.down('.'+options.handle,0);if(!this.handle)this.handle=$(options.handle);if(!this.handle)this.handle=this.element;if(options.scroll&&!options.scroll.scrollTo&&!options.scroll.outerHTML){options.scroll=$(options.scroll);this._isScrollChild=Element.childOf(this.element,options.scroll);}
-Element.makePositioned(this.element);this.delta=this.currentDelta();this.options=options;this.dragging=false;this.eventMouseDown=this.initDrag.bindAsEventListener(this);Event.observe(this.handle,"mousedown",this.eventMouseDown);Draggables.register(this);},destroy:function(){Event.stopObserving(this.handle,"mousedown",this.eventMouseDown);Draggables.unregister(this);},currentDelta:function(){return([parseInt(Element.getStyle(this.element,'left')||'0'),parseInt(Element.getStyle(this.element,'top')||'0')]);},initDrag:function(event){if(typeof Draggable._dragging[this.element]!='undefined'&&Draggable._dragging[this.element])return;if(Event.isLeftClick(event)){var src=Event.element(event);if((tag_name=src.tagName.toUpperCase())&&(tag_name=='INPUT'||tag_name=='SELECT'||tag_name=='OPTION'||tag_name=='BUTTON'||tag_name=='TEXTAREA'))return;var pointer=[Event.pointerX(event),Event.pointerY(event)];var pos=Position.cumulativeOffset(this.element);this.offset=[0,1].map(function(i){return(pointer[i]-pos[i])});Draggables.activate(this);Event.stop(event);}},startDrag:function(event){this.dragging=true;if(this.options.zindex){this.originalZ=parseInt(Element.getStyle(this.element,'z-index')||0);this.element.style.zIndex=this.options.zindex;}
-if(this.options.ghosting){this._clone=this.element.cloneNode(true);Position.absolutize(this.element);this.element.parentNode.insertBefore(this._clone,this.element);}
-if(this.options.scroll){if(this.options.scroll==window){var where=this._getWindowScroll(this.options.scroll);this.originalScrollLeft=where.left;this.originalScrollTop=where.top;}else{this.originalScrollLeft=this.options.scroll.scrollLeft;this.originalScrollTop=this.options.scroll.scrollTop;}}
-Draggables.notify('onStart',this,event);if(this.options.starteffect)this.options.starteffect(this.element);},updateDrag:function(event,pointer){if(!this.dragging)this.startDrag(event);Position.prepare();Droppables.show(pointer,this.element);Draggables.notify('onDrag',this,event);this.draw(pointer);if(this.options.change)this.options.change(this);if(this.options.scroll){this.stopScrolling();var p;if(this.options.scroll==window){with(this._getWindowScroll(this.options.scroll)){p=[left,top,left+width,top+height];}}else{p=Position.page(this.options.scroll);p[0]+=this.options.scroll.scrollLeft+Position.deltaX;p[1]+=this.options.scroll.scrollTop+Position.deltaY;p.push(p[0]+this.options.scroll.offsetWidth);p.push(p[1]+this.options.scroll.offsetHeight);}
-var speed=[0,0];if(pointer[0]<(p[0]+this.options.scrollSensitivity))speed[0]=pointer[0]-(p[0]+this.options.scrollSensitivity);if(pointer[1]<(p[1]+this.options.scrollSensitivity))speed[1]=pointer[1]-(p[1]+this.options.scrollSensitivity);if(pointer[0]>(p[2]-this.options.scrollSensitivity))speed[0]=pointer[0]-(p[2]-this.options.scrollSensitivity);if(pointer[1]>(p[3]-this.options.scrollSensitivity))speed[1]=pointer[1]-(p[3]-this.options.scrollSensitivity);this.startScrolling(speed);}
-if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);Event.stop(event);},finishDrag:function(event,success){this.dragging=false;if(this.options.ghosting){Position.relativize(this.element);Element.remove(this._clone);this._clone=null;}
-if(success)Droppables.fire(event,this.element);Draggables.notify('onEnd',this,event);var revert=this.options.revert;if(revert&&typeof revert=='function')revert=revert(this.element);var d=this.currentDelta();if(revert&&this.options.reverteffect){this.options.reverteffect(this.element,d[1]-this.delta[1],d[0]-this.delta[0]);}else{this.delta=d;}
-if(this.options.zindex)
-this.element.style.zIndex=this.originalZ;if(this.options.endeffect)
-this.options.endeffect(this.element);Draggables.deactivate(this);Droppables.reset();},keyPress:function(event){if(event.keyCode!=Event.KEY_ESC)return;this.finishDrag(event,false);Event.stop(event);},endDrag:function(event){if(!this.dragging)return;this.stopScrolling();this.finishDrag(event,true);Event.stop(event);},draw:function(point){var pos=Position.cumulativeOffset(this.element);if(this.options.ghosting){var r=Position.realOffset(this.element);pos[0]+=r[0]-Position.deltaX;pos[1]+=r[1]-Position.deltaY;}
-var d=this.currentDelta();pos[0]-=d[0];pos[1]-=d[1];if(this.options.scroll&&(this.options.scroll!=window&&this._isScrollChild)){pos[0]-=this.options.scroll.scrollLeft-this.originalScrollLeft;pos[1]-=this.options.scroll.scrollTop-this.originalScrollTop;}
-var p=[0,1].map(function(i){return(point[i]-pos[i]-this.offset[i])}.bind(this));if(this.options.snap){if(typeof this.options.snap=='function'){p=this.options.snap(p[0],p[1],this);}else{if(this.options.snap instanceof Array){p=p.map(function(v,i){return Math.round(v/this.options.snap[i])*this.options.snap[i]}.bind(this))}else{p=p.map(function(v){return Math.round(v/this.options.snap)*this.options.snap}.bind(this))}}}
-var style=this.element.style;if((!this.options.constraint)||(this.options.constraint=='horizontal'))
-style.left=p[0]+"px";if((!this.options.constraint)||(this.options.constraint=='vertical'))
-style.top=p[1]+"px";if(style.visibility=="hidden")style.visibility="";},stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null;Draggables._lastScrollPointer=null;}},startScrolling:function(speed){if(!(speed[0]||speed[1]))return;this.scrollSpeed=[speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];this.lastScrolled=new Date();this.scrollInterval=setInterval(this.scroll.bind(this),10);},scroll:function(){var current=new Date();var delta=current-this.lastScrolled;this.lastScrolled=current;if(this.options.scroll==window){with(this._getWindowScroll(this.options.scroll)){if(this.scrollSpeed[0]||this.scrollSpeed[1]){var d=delta/1000;this.options.scroll.scrollTo(left+d*this.scrollSpeed[0],top+d*this.scrollSpeed[1]);}}}else{this.options.scroll.scrollLeft+=this.scrollSpeed[0]*delta/1000;this.options.scroll.scrollTop+=this.scrollSpeed[1]*delta/1000;}
-Position.prepare();Droppables.show(Draggables._lastPointer,this.element);Draggables.notify('onDrag',this);if(this._isScrollChild){Draggables._lastScrollPointer=Draggables._lastScrollPointer||$A(Draggables._lastPointer);Draggables._lastScrollPointer[0]+=this.scrollSpeed[0]*delta/1000;Draggables._lastScrollPointer[1]+=this.scrollSpeed[1]*delta/1000;if(Draggables._lastScrollPointer[0]<0)
-Draggables._lastScrollPointer[0]=0;if(Draggables._lastScrollPointer[1]<0)
-Draggables._lastScrollPointer[1]=0;this.draw(Draggables._lastScrollPointer);}
-if(this.options.change)this.options.change(this);},_getWindowScroll:function(w){var T,L,W,H;with(w.document){if(w.document.documentElement&&documentElement.scrollTop){T=documentElement.scrollTop;L=documentElement.scrollLeft;}else if(w.document.body){T=body.scrollTop;L=body.scrollLeft;}
-if(w.innerWidth){W=w.innerWidth;H=w.innerHeight;}else if(w.document.documentElement&&documentElement.clientWidth){W=documentElement.clientWidth;H=documentElement.clientHeight;}else{W=body.offsetWidth;H=body.offsetHeight}}
-return{top:T,left:L,width:W,height:H};}}
-var SortableObserver=Class.create();SortableObserver.prototype={initialize:function(element,observer){this.element=$(element);this.observer=observer;this.lastValue=Sortable.serialize(this.element);},onStart:function(){this.lastValue=Sortable.serialize(this.element);},onEnd:function(){Sortable.unmark();if(this.lastValue!=Sortable.serialize(this.element))
-this.observer(this.element)}}
-var Sortable={SERIALIZE_RULE:/^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,sortables:{},_findRootElement:function(element){while(element.tagName.toUpperCase()!="BODY"){if(element.id&&Sortable.sortables[element.id])return element;element=element.parentNode;}},options:function(element){element=Sortable._findRootElement($(element));if(!element)return;return Sortable.sortables[element.id];},destroy:function(element){var s=Sortable.options(element);if(s){Draggables.removeObserver(s.element);s.droppables.each(function(d){Droppables.remove(d)});s.draggables.invoke('destroy');delete Sortable.sortables[s.element.id];}},create:function(element){element=$(element);var options=Object.extend({element:element,tag:'li',dropOnEmpty:false,tree:false,treeTag:'ul',overlap:'vertical',constraint:'vertical',containment:element,handle:false,only:false,delay:0,hoverclass:null,ghosting:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,format:this.SERIALIZE_RULE,onChange:Prototype.emptyFunction,onUpdate:Prototype.emptyFunction},arguments[1]||{});this.destroy(element);var options_for_draggable={revert:true,scroll:options.scroll,scrollSpeed:options.scrollSpeed,scrollSensitivity:options.scrollSensitivity,delay:options.delay,ghosting:options.ghosting,constraint:options.constraint,handle:options.handle};if(options.starteffect)
-options_for_draggable.starteffect=options.starteffect;if(options.reverteffect)
-options_for_draggable.reverteffect=options.reverteffect;else
-if(options.ghosting)options_for_draggable.reverteffect=function(element){element.style.top=0;element.style.left=0;};if(options.endeffect)
-options_for_draggable.endeffect=options.endeffect;if(options.zindex)
-options_for_draggable.zindex=options.zindex;var options_for_droppable={overlap:options.overlap,containment:options.containment,tree:options.tree,hoverclass:options.hoverclass,onHover:Sortable.onHover}
-var options_for_tree={onHover:Sortable.onEmptyHover,overlap:options.overlap,containment:options.containment,hoverclass:options.hoverclass}
-Element.cleanWhitespace(element);options.draggables=[];options.droppables=[];if(options.dropOnEmpty||options.tree){Droppables.add(element,options_for_tree);options.droppables.push(element);}
-(this.findElements(element,options)||[]).each(function(e){var handle=options.handle?$(e).down('.'+options.handle,0):e;options.draggables.push(new Draggable(e,Object.extend(options_for_draggable,{handle:handle})));Droppables.add(e,options_for_droppable);if(options.tree)e.treeNode=element;options.droppables.push(e);});if(options.tree){(Sortable.findTreeElements(element,options)||[]).each(function(e){Droppables.add(e,options_for_tree);e.treeNode=element;options.droppables.push(e);});}
-this.sortables[element.id]=options;Draggables.addObserver(new SortableObserver(element,options.onUpdate));},findElements:function(element,options){return Element.findChildren(element,options.only,options.tree?true:false,options.tag);},findTreeElements:function(element,options){return Element.findChildren(element,options.only,options.tree?true:false,options.treeTag);},onHover:function(element,dropon,overlap){if(Element.isParent(dropon,element))return;if(overlap>.33&&overlap<.66&&Sortable.options(dropon).tree){return;}else if(overlap>0.5){Sortable.mark(dropon,'before');if(dropon.previousSibling!=element){var oldParentNode=element.parentNode;element.style.visibility="hidden";dropon.parentNode.insertBefore(element,dropon);if(dropon.parentNode!=oldParentNode)
-Sortable.options(oldParentNode).onChange(element);Sortable.options(dropon.parentNode).onChange(element);}}else{Sortable.mark(dropon,'after');var nextElement=dropon.nextSibling||null;if(nextElement!=element){var oldParentNode=element.parentNode;element.style.visibility="hidden";dropon.parentNode.insertBefore(element,nextElement);if(dropon.parentNode!=oldParentNode)
-Sortable.options(oldParentNode).onChange(element);Sortable.options(dropon.parentNode).onChange(element);}}},onEmptyHover:function(element,dropon,overlap){var oldParentNode=element.parentNode;var droponOptions=Sortable.options(dropon);if(!Element.isParent(dropon,element)){var index;var children=Sortable.findElements(dropon,{tag:droponOptions.tag,only:droponOptions.only});var child=null;if(children){var offset=Element.offsetSize(dropon,droponOptions.overlap)*(1.0-overlap);for(index=0;index<children.length;index+=1){if(offset-Element.offsetSize(children[index],droponOptions.overlap)>=0){offset-=Element.offsetSize(children[index],droponOptions.overlap);}else if(offset-(Element.offsetSize(children[index],droponOptions.overlap)/2)>=0){child=index+1<children.length?children[index+1]:null;break;}else{child=children[index];break;}}}
-dropon.insertBefore(element,child);Sortable.options(oldParentNode).onChange(element);droponOptions.onChange(element);}},unmark:function(){if(Sortable._marker)Sortable._marker.hide();},mark:function(dropon,position){var sortable=Sortable.options(dropon.parentNode);if(sortable&&!sortable.ghosting)return;if(!Sortable._marker){Sortable._marker=($('dropmarker')||Element.extend(document.createElement('DIV'))).hide().addClassName('dropmarker').setStyle({position:'absolute'});document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);}
-var offsets=Position.cumulativeOffset(dropon);Sortable._marker.setStyle({left:offsets[0]+'px',top:offsets[1]+'px'});if(position=='after')
-if(sortable.overlap=='horizontal')
-Sortable._marker.setStyle({left:(offsets[0]+dropon.clientWidth)+'px'});else
-Sortable._marker.setStyle({top:(offsets[1]+dropon.clientHeight)+'px'});Sortable._marker.show();},_tree:function(element,options,parent){var children=Sortable.findElements(element,options)||[];for(var i=0;i<children.length;++i){var match=children[i].id.match(options.format);if(!match)continue;var child={id:encodeURIComponent(match?match[1]:null),element:element,parent:parent,children:[],position:parent.children.length,container:$(children[i]).down(options.treeTag)}
-if(child.container)
-this._tree(child.container,options,child)
-parent.children.push(child);}
-return parent;},tree:function(element){element=$(element);var sortableOptions=this.options(element);var options=Object.extend({tag:sortableOptions.tag,treeTag:sortableOptions.treeTag,only:sortableOptions.only,name:element.id,format:sortableOptions.format},arguments[1]||{});var root={id:null,parent:null,children:[],container:element,position:0}
-return Sortable._tree(element,options,root);},_constructIndex:function(node){var index='';do{if(node.id)index='['+node.position+']'+index;}while((node=node.parent)!=null);return index;},sequence:function(element){element=$(element);var options=Object.extend(this.options(element),arguments[1]||{});return $(this.findElements(element,options)||[]).map(function(item){return item.id.match(options.format)?item.id.match(options.format)[1]:'';});},setSequence:function(element,new_sequence){element=$(element);var options=Object.extend(this.options(element),arguments[2]||{});var nodeMap={};this.findElements(element,options).each(function(n){if(n.id.match(options.format))
-nodeMap[n.id.match(options.format)[1]]=[n,n.parentNode];n.parentNode.removeChild(n);});new_sequence.each(function(ident){var n=nodeMap[ident];if(n){n[1].appendChild(n[0]);delete nodeMap[ident];}});},serialize:function(element){element=$(element);var options=Object.extend(Sortable.options(element),arguments[1]||{});var name=encodeURIComponent((arguments[1]&&arguments[1].name)?arguments[1].name:element.id);if(options.tree){return Sortable.tree(element,arguments[1]).children.map(function(item){return[name+Sortable._constructIndex(item)+"[id]="+
-encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));}).flatten().join('&');}else{return Sortable.sequence(element,arguments[1]).map(function(item){return name+"[]="+encodeURIComponent(item);}).join('&');}}}
-Element.isParent=function(child,element){if(!child.parentNode||child==element)return false;if(child.parentNode==element)return true;return Element.isParent(child.parentNode,element);}
-Element.findChildren=function(element,only,recursive,tagName){if(!element.hasChildNodes())return null;tagName=tagName.toUpperCase();if(only)only=[only].flatten();var elements=[];$A(element.childNodes).each(function(e){if(e.tagName&&e.tagName.toUpperCase()==tagName&&(!only||(Element.classNames(e).detect(function(v){return only.include(v)}))))
-elements.push(e);if(recursive){var grandchildren=Element.findChildren(e,only,recursive,tagName);if(grandchildren)elements.push(grandchildren);}});return(elements.length>0?elements.flatten():[]);}
-Element.offsetSize=function(element,type){return element['offset'+((type=='vertical'||type=='height')?'Height':'Width')];}
-if(typeof Effect=='undefined')
-throw("controls.js requires including script.aculo.us' effects.js library");var Autocompleter={}
-Autocompleter.Base=function(){};Autocompleter.Base.prototype={baseInitialize:function(element,update,options){this.element=$(element);this.update=$(update);this.hasFocus=false;this.changed=false;this.active=false;this.index=0;this.entryCount=0;if(this.setOptions)
-this.setOptions(options);else
-this.options=options||{};this.options.paramName=this.options.paramName||this.element.name;this.options.tokens=this.options.tokens||[];this.options.frequency=this.options.frequency||0.4;this.options.minChars=this.options.minChars||1;this.options.onShow=this.options.onShow||function(element,update){if(!update.style.position||update.style.position=='absolute'){update.style.position='absolute';Position.clone(element,update,{setHeight:false,offsetTop:element.offsetHeight});}
-Effect.Appear(update,{duration:0.15});};this.options.onHide=this.options.onHide||function(element,update){new Effect.Fade(update,{duration:0.15})};if(typeof(this.options.tokens)=='string')
-this.options.tokens=new Array(this.options.tokens);this.observer=null;this.element.setAttribute('autocomplete','off');Element.hide(this.update);Event.observe(this.element,"blur",this.onBlur.bindAsEventListener(this));Event.observe(this.element,"keypress",this.onKeyPress.bindAsEventListener(this));},show:function(){if(Element.getStyle(this.update,'display')=='none')this.options.onShow(this.element,this.update);if(!this.iefix&&(navigator.appVersion.indexOf('MSIE')>0)&&(navigator.userAgent.indexOf('Opera')<0)&&(Element.getStyle(this.update,'position')=='absolute')){new Insertion.After(this.update,'<iframe id="'+this.update.id+'_iefix" '+'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" '+'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');this.iefix=$(this.update.id+'_iefix');}
-if(this.iefix)setTimeout(this.fixIEOverlapping.bind(this),50);},fixIEOverlapping:function(){Position.clone(this.update,this.iefix,{setTop:(!this.update.style.height)});this.iefix.style.zIndex=1;this.update.style.zIndex=2;Element.show(this.iefix);},hide:function(){this.stopIndicator();if(Element.getStyle(this.update,'display')!='none')this.options.onHide(this.element,this.update);if(this.iefix)Element.hide(this.iefix);},startIndicator:function(){if(this.options.indicator)Element.show(this.options.indicator);},stopIndicator:function(){if(this.options.indicator)Element.hide(this.options.indicator);},onKeyPress:function(event){if(this.active)
-switch(event.keyCode){case Event.KEY_TAB:case Event.KEY_RETURN:this.selectEntry();Event.stop(event);case Event.KEY_ESC:this.hide();this.active=false;Event.stop(event);return;case Event.KEY_LEFT:case Event.KEY_RIGHT:return;case Event.KEY_UP:this.markPrevious();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;case Event.KEY_DOWN:this.markNext();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;}
-else
-if(event.keyCode==Event.KEY_TAB||event.keyCode==Event.KEY_RETURN||(navigator.appVersion.indexOf('AppleWebKit')>0&&event.keyCode==0))return;this.changed=true;this.hasFocus=true;if(this.observer)clearTimeout(this.observer);this.observer=setTimeout(this.onObserverEvent.bind(this),this.options.frequency*1000);},activate:function(){this.changed=false;this.hasFocus=true;this.getUpdatedChoices();},onHover:function(event){var element=Event.findElement(event,'LI');if(this.index!=element.autocompleteIndex)
-{this.index=element.autocompleteIndex;this.render();}
-Event.stop(event);},onClick:function(event){var element=Event.findElement(event,'LI');this.index=element.autocompleteIndex;this.selectEntry();this.hide();},onBlur:function(event){setTimeout(this.hide.bind(this),250);this.hasFocus=false;this.active=false;},render:function(){if(this.entryCount>0){for(var i=0;i<this.entryCount;i++)
-this.index==i?Element.addClassName(this.getEntry(i),"selected"):Element.removeClassName(this.getEntry(i),"selected");if(this.hasFocus){this.show();this.active=true;}}else{this.active=false;this.hide();}},markPrevious:function(){if(this.index>0)this.index--
-else this.index=this.entryCount-1;this.getEntry(this.index).scrollIntoView(true);},markNext:function(){if(this.index<this.entryCount-1)this.index++
-else this.index=0;this.getEntry(this.index).scrollIntoView(false);},getEntry:function(index){return this.update.firstChild.childNodes[index];},getCurrentEntry:function(){return this.getEntry(this.index);},selectEntry:function(){this.active=false;this.updateElement(this.getCurrentEntry());},updateElement:function(selectedElement){if(this.options.updateElement){this.options.updateElement(selectedElement);return;}
-var value='';if(this.options.select){var nodes=document.getElementsByClassName(this.options.select,selectedElement)||[];if(nodes.length>0)value=Element.collectTextNodes(nodes[0],this.options.select);}else
-value=Element.collectTextNodesIgnoreClass(selectedElement,'informal');var lastTokenPos=this.findLastToken();if(lastTokenPos!=-1){var newValue=this.element.value.substr(0,lastTokenPos+1);var whitespace=this.element.value.substr(lastTokenPos+1).match(/^\s+/);if(whitespace)
-newValue+=whitespace[0];this.element.value=newValue+value;}else{this.element.value=value;}
-this.element.focus();if(this.options.afterUpdateElement)
-this.options.afterUpdateElement(this.element,selectedElement);},updateChoices:function(choices){if(!this.changed&&this.hasFocus){this.update.innerHTML=choices;Element.cleanWhitespace(this.update);Element.cleanWhitespace(this.update.down());if(this.update.firstChild&&this.update.down().childNodes){this.entryCount=this.update.down().childNodes.length;for(var i=0;i<this.entryCount;i++){var entry=this.getEntry(i);entry.autocompleteIndex=i;this.addObservers(entry);}}else{this.entryCount=0;}
-this.stopIndicator();this.index=0;if(this.entryCount==1&&this.options.autoSelect){this.selectEntry();this.hide();}else{this.render();}}},addObservers:function(element){Event.observe(element,"mouseover",this.onHover.bindAsEventListener(this));Event.observe(element,"click",this.onClick.bindAsEventListener(this));},onObserverEvent:function(){this.changed=false;if(this.getToken().length>=this.options.minChars){this.startIndicator();this.getUpdatedChoices();}else{this.active=false;this.hide();}},getToken:function(){var tokenPos=this.findLastToken();if(tokenPos!=-1)
-var ret=this.element.value.substr(tokenPos+1).replace(/^\s+/,'').replace(/\s+$/,'');else
-var ret=this.element.value;return/\n/.test(ret)?'':ret;},findLastToken:function(){var lastTokenPos=-1;for(var i=0;i<this.options.tokens.length;i++){var thisTokenPos=this.element.value.lastIndexOf(this.options.tokens[i]);if(thisTokenPos>lastTokenPos)
-lastTokenPos=thisTokenPos;}
-return lastTokenPos;}}
-Ajax.Autocompleter=Class.create();Object.extend(Object.extend(Ajax.Autocompleter.prototype,Autocompleter.Base.prototype),{initialize:function(element,update,url,options){this.baseInitialize(element,update,options);this.options.asynchronous=true;this.options.onComplete=this.onComplete.bind(this);this.options.defaultParams=this.options.parameters||null;this.url=url;},getUpdatedChoices:function(){entry=encodeURIComponent(this.options.paramName)+'='+
-encodeURIComponent(this.getToken());this.options.parameters=this.options.callback?this.options.callback(this.element,entry):entry;if(this.options.defaultParams)
-this.options.parameters+='&'+this.options.defaultParams;new Ajax.Request(this.url,this.options);},onComplete:function(request){this.updateChoices(request.responseText);}});Autocompleter.Local=Class.create();Autocompleter.Local.prototype=Object.extend(new Autocompleter.Base(),{initialize:function(element,update,array,options){this.baseInitialize(element,update,options);this.options.array=array;},getUpdatedChoices:function(){this.updateChoices(this.options.selector(this));},setOptions:function(options){this.options=Object.extend({choices:10,partialSearch:true,partialChars:2,ignoreCase:true,fullSearch:false,selector:function(instance){var ret=[];var partial=[];var entry=instance.getToken();var count=0;for(var i=0;i<instance.options.array.length&&ret.length<instance.options.choices;i++){var elem=instance.options.array[i];var foundPos=instance.options.ignoreCase?elem.toLowerCase().indexOf(entry.toLowerCase()):elem.indexOf(entry);while(foundPos!=-1){if(foundPos==0&&elem.length!=entry.length){ret.push("<li><strong>"+elem.substr(0,entry.length)+"</strong>"+
-elem.substr(entry.length)+"</li>");break;}else if(entry.length>=instance.options.partialChars&&instance.options.partialSearch&&foundPos!=-1){if(instance.options.fullSearch||/\s/.test(elem.substr(foundPos-1,1))){partial.push("<li>"+elem.substr(0,foundPos)+"<strong>"+
-elem.substr(foundPos,entry.length)+"</strong>"+elem.substr(foundPos+entry.length)+"</li>");break;}}
-foundPos=instance.options.ignoreCase?elem.toLowerCase().indexOf(entry.toLowerCase(),foundPos+1):elem.indexOf(entry,foundPos+1);}}
-if(partial.length)
-ret=ret.concat(partial.slice(0,instance.options.choices-ret.length))
-return"<ul>"+ret.join('')+"</ul>";}},options||{});}});Field.scrollFreeActivate=function(field){setTimeout(function(){Field.activate(field);},1);}
-Ajax.InPlaceEditor=Class.create();Ajax.InPlaceEditor.defaultHighlightColor="#FFFF99";Ajax.InPlaceEditor.prototype={initialize:function(element,url,options){this.url=url;this.element=$(element);this.options=Object.extend({paramName:"value",okButton:true,okText:"ok",cancelLink:true,cancelText:"cancel",savingText:"Saving...",clickToEditText:"Click to edit",okText:"ok",rows:1,onComplete:function(transport,element){new Effect.Highlight(element,{startcolor:this.options.highlightcolor});},onFailure:function(transport){alert("Error communicating with the server: "+transport.responseText.stripTags());},callback:function(form){return Form.serialize(form);},handleLineBreaks:true,loadingText:'Loading...',savingClassName:'inplaceeditor-saving',loadingClassName:'inplaceeditor-loading',formClassName:'inplaceeditor-form',highlightcolor:Ajax.InPlaceEditor.defaultHighlightColor,highlightendcolor:"#FFFFFF",externalControl:null,submitOnBlur:false,ajaxOptions:{},evalScripts:false},options||{});if(!this.options.formId&&this.element.id){this.options.formId=this.element.id+"-inplaceeditor";if($(this.options.formId)){this.options.formId=null;}}
-if(this.options.externalControl){this.options.externalControl=$(this.options.externalControl);}
-this.originalBackground=Element.getStyle(this.element,'background-color');if(!this.originalBackground){this.originalBackground="transparent";}
-this.element.title=this.options.clickToEditText;this.onclickListener=this.enterEditMode.bindAsEventListener(this);this.mouseoverListener=this.enterHover.bindAsEventListener(this);this.mouseoutListener=this.leaveHover.bindAsEventListener(this);Event.observe(this.element,'click',this.onclickListener);Event.observe(this.element,'mouseover',this.mouseoverListener);Event.observe(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.observe(this.options.externalControl,'click',this.onclickListener);Event.observe(this.options.externalControl,'mouseover',this.mouseoverListener);Event.observe(this.options.externalControl,'mouseout',this.mouseoutListener);}},enterEditMode:function(evt){if(this.saving)return;if(this.editing)return;this.editing=true;this.onEnterEditMode();if(this.options.externalControl){Element.hide(this.options.externalControl);}
-Element.hide(this.element);this.createForm();this.element.parentNode.insertBefore(this.form,this.element);if(!this.options.loadTextURL)Field.scrollFreeActivate(this.editField);if(evt){Event.stop(evt);}
-return false;},createForm:function(){this.form=document.createElement("form");this.form.id=this.options.formId;Element.addClassName(this.form,this.options.formClassName)
-this.form.onsubmit=this.onSubmit.bind(this);this.createEditField();if(this.options.textarea){var br=document.createElement("br");this.form.appendChild(br);}
-if(this.options.okButton){okButton=document.createElement("input");okButton.type="submit";okButton.value=this.options.okText;okButton.className='editor_ok_button';this.form.appendChild(okButton);}
-if(this.options.cancelLink){cancelLink=document.createElement("a");cancelLink.href="javascript:void(0)";cancelLink.appendChild(document.createTextNode(this.options.cancelText));cancelLink.onclick=this.onclickCancel.bind(this);cancelLink.className='editor_cancel';this.form.appendChild(cancelLink);}},hasHTMLLineBreaks:function(string){if(!this.options.handleLineBreaks)return false;return string.match(/<br/i)||string.match(/<p>/i);},convertHTMLLineBreaks:function(string){return string.replace(/<br>/gi,"\n").replace(/<br\/>/gi,"\n").replace(/<\/p>/gi,"\n").replace(/<p>/gi,"");},createEditField:function(){var text;if(this.options.loadTextURL){text=this.options.loadingText;}else{text=this.getText();}
-var obj=this;if(this.options.rows==1&&!this.hasHTMLLineBreaks(text)){this.options.textarea=false;var textField=document.createElement("input");textField.obj=this;textField.type="text";textField.name=this.options.paramName;textField.value=text;textField.style.backgroundColor=this.options.highlightcolor;textField.className='editor_field';var size=this.options.size||this.options.cols||0;if(size!=0)textField.size=size;if(this.options.submitOnBlur)
-textField.onblur=this.onSubmit.bind(this);this.editField=textField;}else{this.options.textarea=true;var textArea=document.createElement("textarea");textArea.obj=this;textArea.name=this.options.paramName;textArea.value=this.convertHTMLLineBreaks(text);textArea.rows=this.options.rows;textArea.cols=this.options.cols||40;textArea.className='editor_field';if(this.options.submitOnBlur)
-textArea.onblur=this.onSubmit.bind(this);this.editField=textArea;}
-if(this.options.loadTextURL){this.loadExternalText();}
-this.form.appendChild(this.editField);},getText:function(){return this.element.innerHTML;},loadExternalText:function(){Element.addClassName(this.form,this.options.loadingClassName);this.editField.disabled=true;new Ajax.Request(this.options.loadTextURL,Object.extend({asynchronous:true,onComplete:this.onLoadedExternalText.bind(this)},this.options.ajaxOptions));},onLoadedExternalText:function(transport){Element.removeClassName(this.form,this.options.loadingClassName);this.editField.disabled=false;this.editField.value=transport.responseText.stripTags();Field.scrollFreeActivate(this.editField);},onclickCancel:function(){this.onComplete();this.leaveEditMode();return false;},onFailure:function(transport){this.options.onFailure(transport);if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;this.oldInnerHTML=null;}
-return false;},onSubmit:function(){var form=this.form;var value=this.editField.value;this.onLoading();if(this.options.evalScripts){new Ajax.Request(this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this),asynchronous:true,evalScripts:true},this.options.ajaxOptions));}else{new Ajax.Updater({success:this.element,failure:null},this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this)},this.options.ajaxOptions));}
-if(arguments.length>1){Event.stop(arguments[0]);}
-return false;},onLoading:function(){this.saving=true;this.removeForm();this.leaveHover();this.showSaving();},showSaving:function(){this.oldInnerHTML=this.element.innerHTML;this.element.innerHTML=this.options.savingText;Element.addClassName(this.element,this.options.savingClassName);this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);},removeForm:function(){if(this.form){if(this.form.parentNode)Element.remove(this.form);this.form=null;}},enterHover:function(){if(this.saving)return;this.element.style.backgroundColor=this.options.highlightcolor;if(this.effect){this.effect.cancel();}
-Element.addClassName(this.element,this.options.hoverClassName)},leaveHover:function(){if(this.options.backgroundColor){this.element.style.backgroundColor=this.oldBackground;}
-Element.removeClassName(this.element,this.options.hoverClassName)
-if(this.saving)return;this.effect=new Effect.Highlight(this.element,{startcolor:this.options.highlightcolor,endcolor:this.options.highlightendcolor,restorecolor:this.originalBackground});},leaveEditMode:function(){Element.removeClassName(this.element,this.options.savingClassName);this.removeForm();this.leaveHover();this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);if(this.options.externalControl){Element.show(this.options.externalControl);}
-this.editing=false;this.saving=false;this.oldInnerHTML=null;this.onLeaveEditMode();},onComplete:function(transport){this.leaveEditMode();this.options.onComplete.bind(this)(transport,this.element);},onEnterEditMode:function(){},onLeaveEditMode:function(){},dispose:function(){if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;}
-this.leaveEditMode();Event.stopObserving(this.element,'click',this.onclickListener);Event.stopObserving(this.element,'mouseover',this.mouseoverListener);Event.stopObserving(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.stopObserving(this.options.externalControl,'click',this.onclickListener);Event.stopObserving(this.options.externalControl,'mouseover',this.mouseoverListener);Event.stopObserving(this.options.externalControl,'mouseout',this.mouseoutListener);}}};Ajax.InPlaceCollectionEditor=Class.create();Object.extend(Ajax.InPlaceCollectionEditor.prototype,Ajax.InPlaceEditor.prototype);Object.extend(Ajax.InPlaceCollectionEditor.prototype,{createEditField:function(){if(!this.cached_selectTag){var selectTag=document.createElement("select");var collection=this.options.collection||[];var optionTag;collection.each(function(e,i){optionTag=document.createElement("option");optionTag.value=(e instanceof Array)?e[0]:e;if((typeof this.options.value=='undefined')&&((e instanceof Array)?this.element.innerHTML==e[1]:e==optionTag.value))optionTag.selected=true;if(this.options.value==optionTag.value)optionTag.selected=true;optionTag.appendChild(document.createTextNode((e instanceof Array)?e[1]:e));selectTag.appendChild(optionTag);}.bind(this));this.cached_selectTag=selectTag;}
-this.editField=this.cached_selectTag;if(this.options.loadTextURL)this.loadExternalText();this.form.appendChild(this.editField);this.options.callback=function(form,value){return"value="+encodeURIComponent(value);}}});Form.Element.DelayedObserver=Class.create();Form.Element.DelayedObserver.prototype={initialize:function(element,delay,callback){this.delay=delay||0.5;this.element=$(element);this.callback=callback;this.timer=null;this.lastValue=$F(this.element);Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));},delayedListener:function(event){if(this.lastValue==$F(this.element))return;if(this.timer)clearTimeout(this.timer);this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);this.lastValue=$F(this.element);},onTimerEvent:function(){this.timer=null;this.callback(this.element,$F(this.element));}};if(!Control)var Control={};Control.Slider=Class.create();Control.Slider.prototype={initialize:function(handle,track,options){var slider=this;if(handle instanceof Array){this.handles=handle.collect(function(e){return $(e)});}else{this.handles=[$(handle)];}
-this.track=$(track);this.options=options||{};this.axis=this.options.axis||'horizontal';this.increment=this.options.increment||1;this.step=parseInt(this.options.step||'1');this.range=this.options.range||$R(0,1);this.value=0;this.values=this.handles.map(function(){return 0});this.spans=this.options.spans?this.options.spans.map(function(s){return $(s)}):false;this.options.startSpan=$(this.options.startSpan||null);this.options.endSpan=$(this.options.endSpan||null);this.restricted=this.options.restricted||false;this.maximum=this.options.maximum||this.range.end;this.minimum=this.options.minimum||this.range.start;this.alignX=parseInt(this.options.alignX||'0');this.alignY=parseInt(this.options.alignY||'0');this.trackLength=this.maximumOffset()-this.minimumOffset();this.handleLength=this.isVertical()?(this.handles[0].offsetHeight!=0?this.handles[0].offsetHeight:this.handles[0].style.height.replace(/px$/,"")):(this.handles[0].offsetWidth!=0?this.handles[0].offsetWidth:this.handles[0].style.width.replace(/px$/,""));this.active=false;this.dragging=false;this.disabled=false;if(this.options.disabled)this.setDisabled();this.allowedValues=this.options.values?this.options.values.sortBy(Prototype.K):false;if(this.allowedValues){this.minimum=this.allowedValues.min();this.maximum=this.allowedValues.max();}
-this.eventMouseDown=this.startDrag.bindAsEventListener(this);this.eventMouseUp=this.endDrag.bindAsEventListener(this);this.eventMouseMove=this.update.bindAsEventListener(this);this.handles.each(function(h,i){i=slider.handles.length-1-i;slider.setValue(parseFloat((slider.options.sliderValue instanceof Array?slider.options.sliderValue[i]:slider.options.sliderValue)||slider.range.start),i);Element.makePositioned(h);Event.observe(h,"mousedown",slider.eventMouseDown);});Event.observe(this.track,"mousedown",this.eventMouseDown);Event.observe(document,"mouseup",this.eventMouseUp);Event.observe(document,"mousemove",this.eventMouseMove);this.initialized=true;},dispose:function(){var slider=this;Event.stopObserving(this.track,"mousedown",this.eventMouseDown);Event.stopObserving(document,"mouseup",this.eventMouseUp);Event.stopObserving(document,"mousemove",this.eventMouseMove);this.handles.each(function(h){Event.stopObserving(h,"mousedown",slider.eventMouseDown);});},setDisabled:function(){this.disabled=true;},setEnabled:function(){this.disabled=false;},getNearestValue:function(value){if(this.allowedValues){if(value>=this.allowedValues.max())return(this.allowedValues.max());if(value<=this.allowedValues.min())return(this.allowedValues.min());var offset=Math.abs(this.allowedValues[0]-value);var newValue=this.allowedValues[0];this.allowedValues.each(function(v){var currentOffset=Math.abs(v-value);if(currentOffset<=offset){newValue=v;offset=currentOffset;}});return newValue;}
-if(value>this.range.end)return this.range.end;if(value<this.range.start)return this.range.start;return value;},setValue:function(sliderValue,handleIdx){if(!this.active){this.activeHandleIdx=handleIdx||0;this.activeHandle=this.handles[this.activeHandleIdx];this.updateStyles();}
-handleIdx=handleIdx||this.activeHandleIdx||0;if(this.initialized&&this.restricted){if((handleIdx>0)&&(sliderValue<this.values[handleIdx-1]))
-sliderValue=this.values[handleIdx-1];if((handleIdx<(this.handles.length-1))&&(sliderValue>this.values[handleIdx+1]))
-sliderValue=this.values[handleIdx+1];}
-sliderValue=this.getNearestValue(sliderValue);this.values[handleIdx]=sliderValue;this.value=this.values[0];this.handles[handleIdx].style[this.isVertical()?'top':'left']=this.translateToPx(sliderValue);this.drawSpans();if(!this.dragging||!this.event)this.updateFinished();},setValueBy:function(delta,handleIdx){this.setValue(this.values[handleIdx||this.activeHandleIdx||0]+delta,handleIdx||this.activeHandleIdx||0);},translateToPx:function(value){return Math.round(((this.trackLength-this.handleLength)/(this.range.end-this.range.start))*(value-this.range.start))+"px";},translateToValue:function(offset){return((offset/(this.trackLength-this.handleLength)*(this.range.end-this.range.start))+this.range.start);},getRange:function(range){var v=this.values.sortBy(Prototype.K);range=range||0;return $R(v[range],v[range+1]);},minimumOffset:function(){return(this.isVertical()?this.alignY:this.alignX);},maximumOffset:function(){return(this.isVertical()?(this.track.offsetHeight!=0?this.track.offsetHeight:this.track.style.height.replace(/px$/,""))-this.alignY:(this.track.offsetWidth!=0?this.track.offsetWidth:this.track.style.width.replace(/px$/,""))-this.alignY);},isVertical:function(){return(this.axis=='vertical');},drawSpans:function(){var slider=this;if(this.spans)
-$R(0,this.spans.length-1).each(function(r){slider.setSpan(slider.spans[r],slider.getRange(r))});if(this.options.startSpan)
-this.setSpan(this.options.startSpan,$R(0,this.values.length>1?this.getRange(0).min():this.value));if(this.options.endSpan)
-this.setSpan(this.options.endSpan,$R(this.values.length>1?this.getRange(this.spans.length-1).max():this.value,this.maximum));},setSpan:function(span,range){if(this.isVertical()){span.style.top=this.translateToPx(range.start);span.style.height=this.translateToPx(range.end-range.start+this.range.start);}else{span.style.left=this.translateToPx(range.start);span.style.width=this.translateToPx(range.end-range.start+this.range.start);}},updateStyles:function(){this.handles.each(function(h){Element.removeClassName(h,'selected')});Element.addClassName(this.activeHandle,'selected');},startDrag:function(event){if(Event.isLeftClick(event)){if(!this.disabled){this.active=true;var handle=Event.element(event);var pointer=[Event.pointerX(event),Event.pointerY(event)];var track=handle;if(track==this.track){var offsets=Position.cumulativeOffset(this.track);this.event=event;this.setValue(this.translateToValue((this.isVertical()?pointer[1]-offsets[1]:pointer[0]-offsets[0])-(this.handleLength/2)));var offsets=Position.cumulativeOffset(this.activeHandle);this.offsetX=(pointer[0]-offsets[0]);this.offsetY=(pointer[1]-offsets[1]);}else{while((this.handles.indexOf(handle)==-1)&&handle.parentNode)
-handle=handle.parentNode;if(this.handles.indexOf(handle)!=-1){this.activeHandle=handle;this.activeHandleIdx=this.handles.indexOf(this.activeHandle);this.updateStyles();var offsets=Position.cumulativeOffset(this.activeHandle);this.offsetX=(pointer[0]-offsets[0]);this.offsetY=(pointer[1]-offsets[1]);}}}
-Event.stop(event);}},update:function(event){if(this.active){if(!this.dragging)this.dragging=true;this.draw(event);if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);Event.stop(event);}},draw:function(event){var pointer=[Event.pointerX(event),Event.pointerY(event)];var offsets=Position.cumulativeOffset(this.track);pointer[0]-=this.offsetX+offsets[0];pointer[1]-=this.offsetY+offsets[1];this.event=event;this.setValue(this.translateToValue(this.isVertical()?pointer[1]:pointer[0]));if(this.initialized&&this.options.onSlide)
-this.options.onSlide(this.values.length>1?this.values:this.value,this);},endDrag:function(event){if(this.active&&this.dragging){this.finishDrag(event,true);Event.stop(event);}
-this.active=false;this.dragging=false;},finishDrag:function(event,success){this.active=false;this.dragging=false;this.updateFinished();},updateFinished:function(){if(this.initialized&&this.options.onChange)
-this.options.onChange(this.values.length>1?this.values:this.value,this);this.event=null;}};if(!("console"in window)||!("firebug"in console)){var names=["log","debug","info","warn","error","assert","dir","dirxml","group","groupEnd","time","timeEnd","count","trace","profile","profileEnd"];window.console={};for(var i=0;i<names.length;++i){window.console[names[i]]=function(){};}}
-var ua=navigator.userAgent.toLowerCase();var isIE=ua.indexOf("msie")>-1,isIE7=ua.indexOf("msie 7")>-1;if(isIE&&!isIE7){try{document.execCommand("BackgroundImageCache",false,true);}catch(e){}}
-if(typeof Jx=='undefined'){var Jx={};Jx.COMBINED_CSS=true;var aScripts=document.getElementsByTagName('SCRIPT');for(var i=0;i<aScripts.length;i++){var s=aScripts[i].src;var n=s.indexOf('lib/jx');if(n!=-1){Jx.baseURL=s.substring(0,n);break;}}}
-Jx.importRules={};Jx.importRulesIE={};Jx.addStyleSheet=function(styleSheet,ieOnly){if(ieOnly){this.importRulesIE[styleSheet]=styleSheet;}else{this.importRules[styleSheet]=styleSheet;}};Jx.addStyleSheet('reset.css');Jx.applyPNGFilter=function(o){var t=Jx.baseURL+"images/a_pixel.png";if(o.src!=t){var s=o.src;o.src=t;o.runtimeStyle.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";}};Jx.imgQueue=[];Jx.imgLoaded={};Jx.imagesLoading=0;Jx.addToImgQueue=function(obj){if(Jx.imgLoaded[obj.src]){obj.domElement.src=obj.src;}else{Jx.imgQueue.push(obj);Jx.imgLoaded[obj.src]=true;}
-Jx.checkImgQueue();};Jx.checkImgQueue=function(){while(Jx.imagesLoading<2&&Jx.imgQueue.length>0){Jx.loadNextImg();}};Jx.loadNextImg=function(){var obj=Jx.imgQueue.shift();if(obj){++Jx.imagesLoading;obj.domElement.onload=function(){--Jx.imagesLoading;Jx.checkImgQueue();};obj.domElement.onerror=function(){--Jx.imagesLoading;Jx.checkImgQueue();};obj.domElement.src=obj.src;}};Jx.Listener=Class.create();Jx.Listener.prototype={addListener:function(list,obj){list.push(obj);},removeListener:function(list,obj){for(var i=0;i<list.length;i++){if(list[i]==obj){list.splice(i,1);break;}}},processEvent:function(list,fnName,obj){list.each(function(o){if(o[fnName]){o[fnName](obj);}});}};Jx.UniqueId=Class.create();Jx.UniqueId.prototype={uniqueIdRefs:null,initUniqueId:function(){this.uniqueIdRefs=[];},deregisterIds:function(){this.uniqueIdRefs.length=0;},registerIds:function(aIds,domObj){if(aIds.indexOf(domObj.id)!=-1){this.uniqueIdRefs[domObj.id]=domObj;}
-for(var i=0;i<domObj.childNodes.length;i++){this.registerIds(aIds,domObj.childNodes[i]);}},getObj:function(id){return this.uniqueIdRefs[id]||null;}};Jx.Action=Class.create();Jx.Action.prototype={pcl:null,enabled:null,initialize:function(f){this.pcl=[];this.enabled=true;this.actionPerformed=f;},addPropertyChangeListener:function(obj){this.addListener(this.pcl,obj);},removePropertyChangeListener:function(obj){this.removeListener(this.pcl,obj);},isEnabled:function(){return this.enabled;},setEnabled:function(b){if(this.enabled==b){return;}
-this.enabled=b;this.processEvent(this.pcl,'propertyChanged',this);},bindTo:function(item){this.addPropertyChangeListener(item);item.addActionListener(this);},unbindFrom:function(item){this.removePropertyChangeListener(item);item.removeActionListener(this);},actionPerformed:function(obj){alert('actionPerformed');}};Object.extend(Jx.Action.prototype,Jx.Listener.prototype);Object.extend(Element,{getBoxSizing:function(elem){var result='content-box';elem=$(elem);if(elem.currentStyle||window.opera){var cm=document["compatMode"];if(cm=="BackCompat"||cm=="QuirksMode"){result='border-box';}else{result='content-box';}}else{if(arguments.length==0){node=document.documentElement;}
-var sizing=Element.getStyle(elem,"-moz-box-sizing");if(!sizing){sizing=Element.getStyle(elem,"box-sizing");}
-result=(sizing?sizing:'content-box');}
-return result;},getContentBoxSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var w=elem.offsetWidth;var h=elem.offsetHeight;var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);Element.toggleMeasurable(elem);w=w-padding.left-padding.right-border.left-border.right;h=h-padding.bottom-padding.top-border.bottom-border.top;return{width:w,height:h};},getBorderBoxSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var w=elem.offsetWidth;var h=elem.offsetHeight;Element.toggleMeasurable(elem);return{width:w,height:h};},setContentBoxSize:function(elem,size){elem=$(elem);if(Element.getBoxSizing(elem)=='border-box'){var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);if(typeof size.width!='undefined'){var width=(size.width+padding.left+padding.right+border.left+border.right);if(width<0){width=0;}
-elem.style.width=width+'px';}
-if(typeof size.height!='undefined'){var height=(size.height+padding.top+padding.bottom+border.top+border.bottom);if(height<0){height=0;}
-elem.style.height=height+'px';}}else{if(typeof size.width!='undefined'){elem.style.width=size.width+'px';}
-if(typeof size.height!='undefined'){elem.style.height=size.height+'px';}}},setBorderBoxSize:function(elem,size){elem=$(elem);if(Element.getBoxSizing(elem)=='content-box'){var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);var margin=Element.getMarginSize(elem);if(typeof size.width!='undefined'){var width=(size.width-padding.left-padding.right-border.left-border.right-margin.left-margin.right);if(width<0){width=0;}
-elem.style.width=width+'px';}
-if(typeof size.height!='undefined'){var height=(size.height-padding.top-padding.bottom-border.top-border.bottom-margin.top-margin.bottom);if(height<0){height=0;}
-elem.style.height=height+'px';}}else{if(typeof size.width!='undefined'&&size.width>=0){elem.style.width=size.width+'px';}
-if(typeof size.height!='undefined'&&size.height>=0){elem.style.height=size.height+'px';}}},getPaddingSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'padding-left'));var t=Element.getNumber(Element.getStyle(elem,'padding-top'));var r=Element.getNumber(Element.getStyle(elem,'padding-right'));var b=Element.getNumber(Element.getStyle(elem,'padding-bottom'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getBorderSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'border-left-width'));var t=Element.getNumber(Element.getStyle(elem,'border-top-width'));var r=Element.getNumber(Element.getStyle(elem,'border-right-width'));var b=Element.getNumber(Element.getStyle(elem,'border-bottom-width'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getMarginSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'margin-left'));var t=Element.getNumber(Element.getStyle(elem,'margin-top'));var r=Element.getNumber(Element.getStyle(elem,'margin-right'));var b=Element.getNumber(Element.getStyle(elem,'margin-bottom'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getNumber:function(n){var result=n==null||isNaN(parseInt(n))?0:parseInt(n);return result;},getPageDimensions:function(){return{width:Element.getInsideWindowWidth(),height:Element.getInsideWindowHeight()};},getInsideWindowWidth:function(){if(window.innerWidth){return window.innerWidth;}else if(document.compatMode&&document.compatMode.indexOf("CSS1")>=0){return document.body.parentElement.clientWidth;}else if(document.body&&document.body.clientWidth){return document.body.clientWidth;}
-return 0;},getInsideWindowHeight:function(){if(window.innerHeight){return window.innerHeight;}else if(document.compatMode&&document.compatMode.indexOf("CSS1")>=0){return document.body.parentElement.clientHeight;}else if(document.body&&document.body.clientHeight){return document.body.clientHeight;}
-return 0;},toggleMeasurable:function(elem){if(Element.getStyle(elem,'display')=='none'){elem.old={};elem.old.display=elem.style.display;elem.old.visibility=elem.style.visibility;elem.old.position=elem.style.position;elem.style.position='absolute';elem.style.visibility='hidden';elem.style.display='block';}else{if(elem.old){elem.style.display=elem.old.display;elem.style.visibility=elem.old.visibility;elem.style.position=elem.old.position;elem.old=null;}}}});Jx.ContentLoader=Class.create();Jx.ContentLoader.prototype={bContentLoaded:false,contentLoaded:function(element,options,r){element.innerHTML=r.responseText;this.bContentLoaded=true;if(options.onContentLoaded){options.onContentLoaded();}},contentLoadFailed:function(options,r){this.bContentLoaded=false;if(options.onContentLoadFailed){options.onContentLoadFailed();}},loadContent:function(element,options){options=options||{};element=$(element);if(options.content){element.appendChild(options.content);this.bContentLoaded=true;}else if(options.contentID){var c=$(options.contentID);if(c){element.appendChild(c);this.bContentLoaded=true;}}else if(options.contentURL){this.bContentLoaded=false;var ts='';var a=new Ajax.Request(options.contentURL,Object.extend({method:'get',onSuccess:this.contentLoaded.bind(this,element,options),onFailure:this.contentLoadFailed.bind(this,options),requestHeaders:['If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT'],parameters:ts}));}else if(options.contentHTML){element.innerHTML=options.contentHTML;this.bContentLoaded=true;}else{this.bContentLoaded=true;}
-if(this.bContentLoaded&&options.onContentLoaded){options.onContentLoaded();}}};Jx.addStyleSheet('button/button.css');Jx.Button=Class.create();Object.extend(Jx.Button.prototype,Jx.Listener.prototype);Object.extend(Jx.Button.prototype,{al:null,domObj:null,enabled:null,initialize:function(action,options){options=options||{};this.al=[];this.action=action;var imgPath=(options.imgPath||options.image)||'';var tooltip=options.tooltip||'';var label=options.label||'';this.disabledClass=options.disabledClass||'jxDisabled';this.domA=document.createElement('a');this.domA.className='jxButton';this.domA.href='javascript:void(0)';this.domA.onclick=this.onclick.bindAsEventListener(this);this.domA.title=tooltip;this.domA.alt=tooltip;var span=document.createElement('span');span.className='jxButtonSpan';this.domA.appendChild(span);this.domLabel=document.createElement('span');this.domLabel.className='jxButtonContent';this.domLabel.innerHTML=label!=''?label:'&nbsp;';span.appendChild(this.domLabel);if(label!=''){Element.addClassName(this.domLabel,'jxButtonLabel');}
-if(imgPath!=''){Element.addClassName(this.domLabel,'jxButtonIcon');this.domLabel.style.backgroundImage="url("+imgPath+")";}
-if(this.action){this.action.bindTo(this);this.propertyChanged(this.action);}
-this.domObj=document.createElement('div');this.domObj.className='jxButtonContainer';this.domObj.appendChild(this.domA);if(options.halign&&options.halign=='left'){Element.addClassName(this.domObj,'jxButtonContentLeft');}
-if(options.valign&&options.valign=='top'){Element.addClassName(this.domObj,'jxButtonContentTop');}},onclick:function(){if(this.enabled){this.processEvent(this.al,'actionPerformed',this);}
-return false;},addActionListener:function(obj){this.addListener(this.al,obj);},removeActionListener:function(obj){this.removeListener(this.al,obj);},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj,this.disabledClass);}else{Element.addClassName(this.domObj,this.disabledClass);}},setImage:function(path){if(this.domImg){this.domImg.src=path;}},setLabel:function(label){if(this.domLabel){this.domLabel.innerHTML=label;}},setTooltip:function(tooltip){if(this.domImg){this.domImg.title=tooltip;this.domImg.alt=tooltip;}}});Jx.Button.Flyout=Class.create();Object.extend(Jx.Button.Flyout.prototype,Jx.Button.prototype);Object.extend(Jx.Button.Flyout.prototype,Jx.ContentLoader.prototype);Object.extend(Jx.Button.Flyout.prototype,{content:null,initialize:function(options){options=options||{};var a=new Jx.Action(this.show.bind(this));Jx.Button.prototype.initialize.apply(this,[a,options]);Element.addClassName(this.domA,'jxButtonFlyout');this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.content=document.createElement('div');Element.addClassName(this.content,'jxFlyout');this.loadContent(this.content,options);this.domObj.appendChild(this.content);this.content.style.display='none';this.keypressWatcher=this.keypressHandler.bindAsEventListener(this);this.hideWatcher=this.clickHandler.bindAsEventListener(this);},show:function(){if(!window.opera&&!this.iframe.parentNode){this.content.appendChild(this.iframe);}
-this.content.style.display='block';Event.observe(window,'keypress',this.keypressWatcher);Event.observe(document,'click',this.hideWatcher);},hide:function(){this.content.style.display='none';Event.stopObserving(window,'keypress',this.keypressWatcher);Event.stopObserving(document,'click',this.hideWatcher);},clickHandler:function(e){var elm=Event.element(e);if(!Element.descendantOf(elm,this.domObj.parentNode)){this.hide();}},keypressHandler:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.hide();}}});Jx.Button.Multi=Class.create();Jx.Button.Multi.prototype={activeButton:null,buttons:null,initialize:function(){this.buttons=[];this.content=document.createElement('div');this.tb=new Jx.Toolbar(this.content,'right');this.flyout=new Jx.Button.Flyout({content:this.content,label:'&nbsp;'});Element.addClassName(this.flyout.domObj.firstChild,'jxButtonMulti');this.domObj=document.createElement('div');this.buttonContainer=document.createElement('div');this.buttonContainer.className='jxButtonMultiContainer';this.domObj.appendChild(this.buttonContainer);this.domObj.appendChild(this.flyout.domObj);},add:function(){for(var i=0;i<arguments.length;i++){var theButton=arguments[i];var action=new Jx.Action(this.setButton.bind(this,theButton));var button=new Jx.Button(action,{});var click=button.domA.onclick;button.domObj=theButton.domObj.cloneNode(true);button.domObj.onclick=click;this.tb.add(button);if(!this.activeButton){this.buttonContainer.appendChild(theButton.domObj);this.activeButton=theButton;}}},setActiveButton:function(button){while(this.buttonContainer.childNodes.length>0){this.buttonContainer.removeChild(this.buttonContainer.firstChild);}
-this.buttonContainer.appendChild(button.domObj);},setButton:function(button){this.setActiveButton(button);button.onclick();this.flyout.hide();}};Jx.Button.Picker=Class.create();Object.extend(Jx.Button.Picker.prototype,Jx.Button.Flyout.prototype);Object.extend(Jx.Button.Picker.prototype,{ul:null,selectedItem:null,initialize:function(){Jx.Button.Flyout.prototype.initialize.apply(this,arguments);this.ul=document.createElement('ul');this.content.appendChild(this.ul);Element.removeClassName(this.domLabel,'jxButtonEmptyLabel');},add:function(){for(var i=0;i<arguments.length;i++){var thing=arguments[i];if(thing.domObj){thing=thing.domObj;}
-var li=document.createElement('li');var a=document.createElement('a');li.appendChild(a);if(typeof(thing)=='string'){a.innerHTML=thing;}else{a.appendChild(thing);}
-this.ul.appendChild(li);if(!this.selectedItem){this.updateButton(a);}}},clickHandler:function(e){var elm=Event.element(e);if(!Element.descendantOf(elm,this.domObj.parentNode)){this.hide();return;}
-var a=Event.findElement(e,'A');if(a&&Element.descendantOf(a,this.ul)){this.updateButton(a);this.hide();}},updateButton:function(a){while(this.domLabel.childNodes.length>0){this.domLabel.removeChild(this.domLabel.firstChild);}
-this.domLabel.appendChild(a.firstChild.cloneNode(true));this.selectedItem=a.firstChild;}});Jx.addStyleSheet('color/color.css');Jx.ColorPanel=Class.create();Jx.ColorPanel.prototype={domObj:null,color:null,alpha:null,ccl:null,hexColors:['00','33','66','99','CC','FF'],initialize:function(options){options=options||{};this.keypressWatcher=this.keypressHandler.bind(this);this.ccl=[];this.color=options.color||'#000000';this.alpha=options.alpha||1;this.domObj=document.createElement('div');this.domObj.className='jxColorPanel';var top=document.createElement('div');top.className='jxColorBar';var d=document.createElement('div');d.className='jxColorPreview';this.selectedSwatch=document.createElement('div');d.appendChild(this.selectedSwatch);top.appendChild(d);this.colorInputLabel=document.createElement('label');this.colorInputLabel.className='jxColorLabel';this.colorInputLabel.innerHTML='#';top.appendChild(this.colorInputLabel);this.colorInput=document.createElement('input');this.colorInput.className='jxHexInput';this.colorInput.type='text';this.colorInput.maxLength=6;Event.observe(this.colorInput,'keyup',this.colorChanged.bind(this));Event.observe(this.colorInput,'blur',this.colorChanged.bind(this));Event.observe(this.colorInput,'change',this.colorChanged.bind(this));top.appendChild(this.colorInput);this.alphaLabel=document.createElement('label');this.alphaLabel.className='jxAlphaLabel';this.alphaLabel.innerHTML='alpha (%)';top.appendChild(this.alphaLabel);this.alphaInput=document.createElement('input');this.alphaInput.className='jxAlphaInput';this.alphaInput.type='text';this.alphaInput.maxLength=3;Event.observe(this.alphaInput,'keyup',this.alphaChanged.bind(this));top.appendChild(this.alphaInput);this.domObj.appendChild(top);var a=document.createElement('a');a.href="javascript:void(0)";a.className='jxColorClose';a.alt='Close';a.title='Close';Event.observe(a,'click',this.hide.bind(this));img=document.createElement('img');img.className='png24';img.src=Jx.baseURL+'images/close.png';a.appendChild(img);this.domObj.appendChild(a);d=document.createElement('div');d.className='jxClearer';this.domObj.appendChild(d);var swatchClick=this.swatchClick.bindAsEventListener(this);var swatchOver=this.swatchOver.bindAsEventListener(this);var table=document.createElement('table');table.className='jxColorGrid';var tbody=document.createElement('tbody');table.appendChild(tbody);for(var i=0;i<12;i++){var tr=document.createElement('tr');for(var j=-3;j<18;j++){var bSkip=false;var r,g,b;if(j<0){if(j==-3||j==-1){r=g=b=0;bSkip=true;}else{if(i<6){r=g=b=i;}else{if(i==6){r=5;g=0;b=0;}else if(i==7){r=0;g=5;b=0;}else if(i==8){r=0;g=0;b=5;}else if(i==9){r=5;g=5;b=0;}else if(i==10){r=0;g=5;b=5;}else if(i==11){r=5;g=0;b=5;}}}}else{r=parseInt(i/6)*3+parseInt(j/6);g=j%6;b=i%6;}
-var bgColor='#'+this.hexColors[r]+this.hexColors[g]+this.hexColors[b];var td=document.createElement('td');if(!bSkip){td.style.backgroundColor=bgColor;var a=document.createElement('a');if((r>2&&g>2)||(r>2&&b>2)||(g>2&&b>2)){a.className='colorSwatch borderBlack';}else{a.className='colorSwatch borderWhite';}
-a.href='#';a.title=bgColor;a.alt=bgColor;a.swatchColor=bgColor;a.onmouseover=swatchOver;a.onclick=swatchClick;td.appendChild(a);}else{var span=document.createElement('span');td.className='emptyCell';td.appendChild(span);}
-tr.appendChild(td);}
-tbody.appendChild(tr);}
-this.domObj.appendChild(table);var d=document.createElement('div');d.className='jxColorPreview';this.previewSwatch=document.createElement('div');d.appendChild(this.previewSwatch);this.previewSwatch.style.backgroundColor=this.color;this.domObj.appendChild(d);this.previewLabel=document.createElement('label');this.previewLabel.className='jxColorLabel';this.previewLabel.innerHTML=this.color;this.domObj.appendChild(this.previewLabel);d=document.createElement('div');d.className='jxClearer';this.domObj.appendChild(d);this.updateSelected();},swatchOver:function(e){var a=Event.element(e);this.previewSwatch.style.backgroundColor=a.swatchColor;this.previewLabel.innerHTML=a.swatchColor;},swatchClick:function(e){var a=Event.element(e);this.color=a.swatchColor;this.updateSelected();this.hide();},colorChanged:function(){var color=this.colorInput.value;if(color.substring(0,1)=='#'){color=color.substring(1);}
-if(color.toLowerCase().match(/^[0-9a-f]{6}$/)){this.color='#'+color.toUpperCase();this.updateSelected();}},alphaChanged:function(){var alpha=this.alphaInput.value;if(alpha.match(/^[0-9]{1,3}$/)){this.alpha=parseFloat(alpha/100);this.updateSelected();}},setColor:function(color){this.colorInput.value=color;this.colorChanged();},setAlpha:function(alpha){this.alphaInput.value=alpha;this.alphaChanged();},updateSelected:function(){this.selectedSwatch.style.backgroundColor=this.color;this.colorInput.value=this.color.substring(1);this.alphaInput.value=parseInt(this.alpha*100);if(this.alpha<1){this.selectedSwatch.style.opacity=this.alpha;this.selectedSwatch.style.filter='Alpha(opacity='+(this.alpha*100)+')';}else{this.selectedSwatch.style.opacity='';this.selectedSwatch.style.filter='';}
-this.processEvent(this.ccl,'colorChanged',this);},show:function(){this.domObj.style.display='block';Event.observe(window,'keypress',this.keypressWatcher);},hide:function(){this.domObj.style.display='none';Event.stopObserving(window,'keypress',this.keypressWatcher);},keypressHandler:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.hide();}},addColorChangeListener:function(obj){this.addListener(this.ccl,obj);},removeColorChangeListener:function(obj){this.removeListener(this.ccl,obj);}};Object.extend(Jx.ColorPanel.prototype,Jx.Listener.prototype);Jx.Button.Color=Class.create();Object.extend(Jx.Button.Color.prototype,Jx.Button.Flyout.prototype);Object.extend(Jx.Button.Color.prototype,{colorPanel:[],swatch:null,color:null,alpha:null,ccl:null,initialize:function(options){options=options||{};options.label=options.label||'&nbsp;';this.color=options.color||'#000000';this.alpha=options.alpha||100;this.ccl=[];if(this.colorPanel.length==0){this.colorPanel[0]=new Jx.ColorPanel();}
-var d=document.createElement('div');d.className='jxColorButtonPreview';this.selectedSwatch=document.createElement('div');d.appendChild(this.selectedSwatch);Jx.Button.Flyout.prototype.initialize.apply(this,[options]);Element.addClassName(this.domObj.firstChild,'jxButtonColor');this.domObj.firstChild.firstChild.insertBefore(d,this.domObj.firstChild.firstChild.firstChild);this.updateSwatch();},show:function(){if(this.colorPanel[0].currentButton){this.colorPanel[0].currentButton.hide();}
-this.colorPanel[0].currentButton=this;this.colorPanel[0].addColorChangeListener(this);this.content.appendChild(this.colorPanel[0].domObj);this.colorPanel[0].domObj.style.display='block';Jx.Button.Flyout.prototype.show.apply(this,arguments);this.colorPanel[0].setColor(this.color);this.colorPanel[0].setAlpha(this.alpha);},hide:function(){this.colorPanel[0].removeColorChangeListener(this);Jx.Button.Flyout.prototype.hide.apply(this,arguments);this.colorPanel[0].currentButton=null;},setColor:function(color){this.color=color;this.updateSwatch();},setAlpha:function(alpha){this.alpha=alpha;this.updateSwatch();},colorChanged:function(panel){this.color=panel.color;this.alpha=panel.alpha*100;this.updateSwatch();this.processEvent(this.ccl,'colorChanged',this);},updateSwatch:function(){this.selectedSwatch.style.backgroundColor=this.color;if(this.alpha<100){this.selectedSwatch.style.opacity=this.alpha/100;this.selectedSwatch.style.filter='Alpha(opacity='+(this.alpha)+')';}else{this.selectedSwatch.style.opacity='';this.selectedSwatch.style.filter='';}},addColorChangeListener:function(obj){this.addListener(this.ccl,obj);},removeColorChangeListener:function(obj){this.removeListener(this.ccl,obj);}});Jx.addStyleSheet('dialog/dialog.css');Jx.Dialog=Class.create();Jx.Dialog.prototype={onClose:null,onOpen:null,onChange:null,title:null,content:null,action:null,values:null,actions:null,handler:null,bContentLoaded:null,zIndex:[101],stack:[],blanket:null,firstShow:true,modal:true,initialize:function(options){this.initUniqueId();this.values={};this.actions={};this.handler=options.handler?options.handler:null;if(options.onChange){this.onChange=options.onChange;}
-if(options.onClose){this.onClose=options.onClose;}
-if(options.onOpen){this.onOpen=options.onOpen;}
-if(options.onContentLoaded){this.onContentLoaded=options.onContentLoaded;}
-this.imageBaseUrl=options.imageBaseUrl||Jx.baseURL+"/images/";if(this.imageBaseUrl.slice(-1)!='/'){this.imageBaseUrl+='/';}
-this.modal=typeof options.modal=='undefined'?true:options.modal;var w=options.width||250;var h=options.height||250;var b=(typeof options.bottom!='undefined')?options.bottom:null;var r=(typeof options.right!='undefined')?options.right:null;var t=(typeof options.top!='undefined')?options.top:(b!=null?null:0);var l=(typeof options.left!='undefined')?options.left:(r!=null?null:0);this.blanket=document.createElement('div');this.blanket.className='jxDialogModal';this.blanket.style.display='none';if(!window.opera&&this.modal){var iframe=document.createElement('iframe');iframe.className='jxDialogShim';iframe.scrolling='no';iframe.frameborder=0;this.blanket.appendChild(iframe);if(options.parentObj){$(options.parentObj).appendChild(this.blanket);}else{document.body.appendChild(this.blanket);}}
-this.dragHandle=document.createElement('div');this.dragHandle.innerHTML=options.title||'&nbsp;';this.dragHandle.style.width='100%';var domObj=document.createElement('div');domObj.className='jxDialogContainer';this.domObj=domObj;if(options.id){domObj.id=options.id;}
-var dialogObj=document.createElement('div');dialogObj.className='jxDialog';this.innerDialogObj=dialogObj;var titleObj=document.createElement('div');titleObj.className='jxDialogTitle';this.title=titleObj;titleObj.appendChild(this.dragHandle);titleObj.style.visibility='hidden';document.getElementsByTagName('BODY')[0].appendChild(titleObj);this.titleHeight=Element.getBorderBoxSize(titleObj).height;document.getElementsByTagName('BODY')[0].removeChild(titleObj);titleObj.style.visibility='';var contentObj=document.createElement('div');contentObj.className='jxDialogContent';this.content=contentObj;domObj.appendChild(dialogObj);dialogObj.appendChild(titleObj);dialogObj.appendChild(contentObj);new Jx.Layout(dialogObj,{width:w,height:h});new Jx.Layout(titleObj,{top:0,left:0,right:0,bottom:null,height:this.titleHeight,width:null});this.actionHeight=0;if(options.buttons){var actionObj=document.createElement('div');actionObj.className='jxDialogAction';actionObj.style.visibility='hidden';document.getElementsByTagName('BODY')[0].appendChild(actionObj);this.actionHeight=parseInt(Element.getStyle(actionObj,'height'));document.getElementsByTagName('BODY')[0].removeChild(actionObj);actionObj.style.visibility='';dialogObj.appendChild(actionObj);new Jx.Layout(actionObj,{top:null,left:0,right:0,bottom:0,height:this.actionHeight,width:null});this.action=actionObj;this.setButtons(options.buttons);}
-new Jx.Layout(contentObj,{top:this.titleHeight,left:0,right:0,bottom:this.actionHeight});var atag=document.createElement('a');atag.href='javascript:void(0)';atag.className='jxDialogCloseButton';atag.onclick=this.close.bindAsEventListener(this);var close=document.createElement('img');if(options.closeImg){close.src=options.closeImg;}
-else{close.src=this.imageBaseUrl+'icon_close.png';}
-close.alt='Close Dialog';close.title='Close Dialog';atag.appendChild(close);titleObj.appendChild(atag);if(options.helpID||options.helpHTML||options.helpURL||options.help){var atag2=document.createElement('a');atag2.href='javascript:void(0)';atag2.className='jxDialogHelpButton';atag2.onclick=this.toggleHelp.bindAsEventListener(this);var help=document.createElement('img');help.src=this.imageBaseUrl+'icon_quickhelp.png';help.alt='Help';help.title='Help';atag2.appendChild(help);titleObj.appendChild(atag2);this.help=document.createElement('div');this.help.className='jxDialogHelp';this.help.style.display='none';this.help.isVisible=false;var helpOpts={};helpOpts.contentID=options.helpID;helpOpts.content=options.help;helpOpts.contentURL=options.helpURL;helpOpts.contentHTML=options.helpHTML;helpOpts.onContentLoaded=this.onHelpContentLoaded.bind(this);this.loadContent(this.help,helpOpts);dialogObj.appendChild(this.help);}
-var contentOpts={};contentOpts.contentID=options.contentID;contentOpts.content=options.content;contentOpts.contentURL=options.contentURL;contentOpts.contentHTML=options.contentHTML;contentOpts.onContentLoaded=this.onDialogContentLoaded.bind(this);this.loadContent(contentObj,contentOpts);dialogObj.style.visibility='hidden';document.body.appendChild(dialogObj);dialogObj.resize();this.dialogBoxSize=Element.getBorderBoxSize(dialogObj);this.dialogBoxMargins=Element.getMarginSize(dialogObj);var containerSize={width:this.dialogBoxSize.width,height:this.dialogBoxSize.height};containerSize.width+=this.dialogBoxMargins.left+this.dialogBoxMargins.right;containerSize.height+=this.dialogBoxMargins.top+this.dialogBoxMargins.bottom;document.body.removeChild(dialogObj);dialogObj.style.visibility='';domObj.appendChild(dialogObj);domObj.style.display="none";Element.setBorderBoxSize(domObj,{width:(containerSize.width),height:(containerSize.height)});domObj.style.position='absolute';if(t!=null){domObj.style.top=(t)+'px';}else{domObj.style.bottom=(b)+'px';}
-if(l!=null){domObj.style.left=(l)+'px';}else{domObj.style.right=(r)+'px';}
-if(options.parentObj){$(options.parentObj).appendChild(domObj);}else{document.body.appendChild(domObj);}
-this.DTOffset=0;this.DBOffset=0;this.DROffset=0;this.DLOffset=0;this.decorationOffsets={top:0,right:0,bottom:0,left:0};var imgContainer=document.createElement('div');imgContainer.className='jxDialogBgTL';var img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_tl.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.top+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.left+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgTR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_tr.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.top+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.right+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgBR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_br.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.bottom+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.right+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgBL';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_bl.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.bottom+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.left+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgT';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_t.png';img.className='png24';img.style.width=containerSize.width-this.decorationOffsets.top+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.topImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgB';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_b.png';img.className='png24';img.style.width=containerSize.width-this.decorationOffsets.bottom+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.bottomImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgL';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_l.png';img.className='png24';img.style.height=containerSize.height-this.decorationOffsets.left+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.leftImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_r.png';img.className='png24';img.style.height=containerSize.height-this.decorationOffsets.right+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.rightImg=img;Event.observe(domObj,'mousedown',this.mouseDown.bind(this));Event.observe(this.title,'mousedown',this.mouseDown.bind(this));if(options.resizeable){this.resizeHandle=document.createElement('div');this.resizeHandle.className='jxDialogResize';this.resizeHandle.style.position='absolute';this.domObj.appendChild(this.resizeHandle);this.resizeHandleSize={width:parseInt(Element.getStyle(this.resizeHandle,'width')),height:parseInt(Element.getStyle(this.resizeHandle,'height'))};this.resizeHandle.style.top=(containerSize.height-this.resizeHandleSize.height)+'px';this.resizeHandle.style.left=(containerSize.width-this.resizeHandleSize.width)+'px';new Draggable(this.resizeHandle,{starteffect:false,endeffect:false,change:this.ondrag.bind(this),zindex:0});}
-this.bOpen=false;},mouseDown:function(){for(var i=0;i<this.stack.length;i++){if(this.stack[i]==this){this.stack.splice(i,1);this.stack.push(this);}}
-for(var i=0;i<this.stack.length;i++){this.stack[i].domObj.style.zIndex=(101+i);}},ondrag:function(obj){this.mouseDown();var delta=obj.currentDelta();var deltaX=delta[0]+this.resizeHandleSize.width;var deltaY=delta[1]+this.resizeHandleSize.height;this.resize({width:deltaX,height:deltaY});},resize:function(newSize){this.innerDialogObj.resize(newSize);if(newSize.width){var outerWidth=newSize.width;Element.setBorderBoxSize(this.domObj,{width:outerWidth});Element.setBorderBoxSize(this.topImg,{width:outerWidth-this.decorationOffsets.top});Element.setBorderBoxSize(this.bottomImg,{width:outerWidth-this.decorationOffsets.bottom});}
-if(newSize.height){var outerHeight=newSize.height;Element.setBorderBoxSize(this.domObj,{height:outerHeight});Element.setBorderBoxSize(this.leftImg,{height:outerHeight-this.decorationOffsets.left});Element.setBorderBoxSize(this.rightImg,{height:outerHeight-this.decorationOffsets.right});if(this.help){Element.setBorderBoxSize(this.help,{height:newSize.height-this.titleHeight});}}},setTitle:function(title){this.title.childNodes[0].innerHTML=title;},setButtons:function(buttons){this.action.innerHTML='';for(var i=0;i<buttons.length;i++){var button=document.createElement('input');button.id=buttons[i];button.type='button';button.className='normalButton';button.name=buttons[i];button.value=buttons[i];button.onclick=this.buttonHandler.bind(this,button);this.action.appendChild(button);this.uniqueIdRefs[button.id]=button;}},processInputs:function(obj){for(var i=0;i<obj.childNodes.length;i++){var node=obj.childNodes[i];if(node.tagName=='INPUT'||node.tagName=='SELECT'||node.tagName=='TEXTAREA'){if(node.type=='button'){this.actions[node.id]=node;node.onclick=this.buttonHandler.bind(this,node);}else{this.values[node.id]=node;if(this.onChange){node.onchange=this.onChangeHandler.bind(this,node);}}}else{if(node.childNodes){this.processInputs(node);}}}},buttonHandler:function(input,event){if(this.handler){this.handler(input.value,this);}},onChangeHandler:function(input,event){if(this.onChange){this.onChange(input,this);}},getValue:function(name){var result='';var input=this.values[name];if(input){switch(input.tagName){case'INPUT':result=input.value;break;case'SELECT':result=input.options[input.selectedIndex].value;}}
-return result;},setValue:function(name,value){if(typeof this.values[name]!='undefined'){if(this.values[name].type=='text'||this.values[name].type=='hidden'){this.values[name].value=value;}}},show:function(){this.stack.push(this);if(this.modal){this.blanket.style.zIndex=this.zIndex[0]++;this.blanket.style.visibility='visible';this.blanket.style.display='block';}
-this.domObj.style.zIndex=this.zIndex[0]++;Effect.Appear(this.domObj,{duration:0.1});this.domObj.style.display='block';new Draggable(this.domObj,{handle:this.dragHandle,starteffect:false,endeffect:false});this.content.resize({forceResize:this.firstShow});this.firstShow=false;},hide:function(){for(var i=0;i<this.stack.length;i++){if(this.stack[i]==this){this.stack.splice(i,1);}}
-this.zIndex[0]--;Effect.Fade(this.domObj,{duration:0.3});if(this.modal){this.blanket.style.visibility='hidden';this.zIndex[0]--;}},open:function(){if(!this.bOpen){this.bOpen=true;}
-if(this.bContentLoaded){this.show();if(this.onOpen)this.onOpen();}},close:function(){this.bOpen=false;this.hide();if(this.onClose)this.onClose();},onDialogContentLoaded:function(){this.processInputs(this.content);if(this.onContentLoaded){this.onContentLoaded(this);}
-if(this.bOpen){this.open();this.bOpen=false;}},onHelpContentLoaded:function(){var img=document.createElement('img');img.className='jxDialogHelpCloseButton png24';img.src=this.imageBaseUrl+'help_close.png';img.onclick=this.toggleHelp.bind(this);img.alt='Close Help';img.title='Close Help';this.help.appendChild(img);},toggleHelp:function(){if(this.help.isVisible){Effect.Fade(this.help,{duration:0.3});}else{var actionSize=this.action?Element.getBorderBoxSize(this.action):{width:0,height:0};var contentSize=Element.getBorderBoxSize(this.content);Element.setBorderBoxSize(this.help,{height:contentSize.height+actionSize.height});Effect.Appear(this.help,{duration:0.3});}
-this.help.isVisible=!this.help.isVisible;}};Object.extend(Jx.Dialog.prototype,Jx.UniqueId.prototype);Object.extend(Jx.Dialog.prototype,Jx.ContentLoader.prototype);Jx.addStyleSheet('grid/grid.css');Jx.Grid=Class.create();Jx.Grid.prototype={domObj:null,model:null,initialize:function(domObj,options){this.domObj=$(domObj);if(!this.domObj.jxLayout){new Jx.Layout(this.domObj);}
-this.domObj.jxLayout.addSizeChangeListener(this);options=options||{};this.rowColObj=document.createElement('div');this.rowColObj.className='jxGridContainer';this.colObj=document.createElement('div');this.colObj.className='jxGridContainer';this.colTable=document.createElement('table');this.colTable.className='jxGridTable';this.colTableHead=document.createElement('thead');this.colTable.appendChild(this.colTableHead);this.colTableBody=document.createElement('tbody');this.colTable.appendChild(this.colTableBody);this.colObj.appendChild(this.colTable);this.rowObj=document.createElement('div');this.rowObj.className='jxGridContainer';this.rowTable=document.createElement('table');this.rowTable.className='jxGridTable';this.rowTableHead=document.createElement('thead');this.rowTable.appendChild(this.rowTableHead);this.rowObj.appendChild(this.rowTable);this.gridObj=document.createElement('div');this.gridObj.className='jxGridContainer';this.gridObj.style.overflow='scroll';this.gridTable=document.createElement('table');this.gridTable.className='jxGridTable';this.gridTableBody=document.createElement('tbody');this.gridTable.appendChild(this.gridTableBody);this.gridObj.appendChild(this.gridTable);this.domObj.appendChild(this.rowColObj);this.domObj.appendChild(this.rowObj);this.domObj.appendChild(this.colObj);this.domObj.appendChild(this.gridObj);this.bAlternateRowColors=options.alternateRowColors||false;this.showRowHeader=options.rowHeaders||false;this.showColumnHeader=options.columnHeaders||false;this.rowSelection=options.rowSelection||false;this.cellSelection=options.cellSelection||false;Event.observe(this.gridObj,'scroll',this.onScroll.bind(this));Event.observe(this.gridObj,'click',this.onClickGrid.bindAsEventListener(this));Event.observe(this.rowObj,'click',this.onClickRowHeader.bindAsEventListener(this));Event.observe(this.colObj,'click',this.onClickColumnHeader.bindAsEventListener(this));Event.observe(this.gridObj,'mousemove',this.onMouseMoveGrid.bindAsEventListener(this));Event.observe(this.rowObj,'mousemove',this.onMouseMoveRowHeader.bindAsEventListener(this));Event.observe(this.colObj,'mousemove',this.onMouseMoveColumnHeader.bindAsEventListener(this));},onScroll:function(){this.colObj.scrollLeft=this.gridObj.scrollLeft;this.rowObj.scrollTop=this.gridObj.scrollTop;},sizeChanged:function(){this.resize();},resize:function(){if(!this.model){return;}
-var colHeight=this.showColumnHeader?this.model.getColumnHeaderHeight():1;var rowWidth=this.showRowHeader?this.model.getRowHeaderWidth():1;var size=Element.getContentBoxSize(this.domObj);this.rowColObj.style.width=(rowWidth-1)+'px';this.rowColObj.style.height=(colHeight-1)+'px';this.rowObj.style.top=(colHeight)+'px';this.rowObj.style.left='0px';this.rowObj.style.width=(rowWidth-1)+'px';this.rowObj.style.height=(size.height-colHeight-1)+'px';this.colObj.style.top='0px';this.colObj.style.left=(rowWidth)+'px';this.colObj.style.width=(size.width-rowWidth-1)+'px';this.colObj.style.height=(colHeight-1)+'px';this.gridObj.style.top=(colHeight)+'px';this.gridObj.style.left=(rowWidth)+'px';this.gridObj.style.width=(size.width-rowWidth-1)+'px';this.gridObj.style.height=(size.height-colHeight-1)+'px';},setModel:function(model){if(this.model){this.model.removeGridListener(this);}
-this.model=model;if(this.model){this.domObj.jxLayout.resize();this.model.addGridListener(this);this.createGrid();this.resize();}else{this.destroyGrid();}},destroyGrid:function(){var n=this.colTableHead.cloneNode(false);this.colTable.replaceChild(n,this.colTableHead);this.colTableHead=n;n=this.colTableBody.cloneNode(false);this.colTable.replaceChild(n,this.colTableBody);this.colTableBody=n;n=this.rowTableHead.cloneNode(false);this.rowTable.replaceChild(n,this.rowTableHead);this.rowTableHead=n;n=this.gridTableBody.cloneNode(false);this.gridTable.replaceChild(n,this.gridTableBody);this.gridTableBody=n;},createGrid:function(){this.destroyGrid();if(this.model){var model=this.model;var nColumns=model.getColumnCount();var nRows=model.getRowCount();if(this.showColumnHeader){var colHeight=model.getColumnHeaderHeight();var trHead=document.createElement('tr');this.colTableHead.appendChild(trHead);var trBody=document.createElement('tr');this.colTableBody.appendChild(trBody);var th=document.createElement('th');th.style.width='0px';th.style.height='0px';trHead.appendChild(th);th=th.cloneNode(true);th.style.height=(colHeight)+'px';trBody.appendChild(th);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);th=document.createElement('th');th.className='jxGridColHeadHide';th.style.width=(colWidth)+'px';var p=document.createElement('p');p.style.height='0px';p.style.width=(colWidth)+'px';th.appendChild(p);trHead.appendChild(th);th=document.createElement('th');th.className='jxGridColHead';th.innerHTML=model.getColumnHeaderHTML(i);trBody.appendChild(th);}
-var th=document.createElement('th');th.style.width='1000px';th.style.height='0px';trHead.appendChild(th);th=th.cloneNode(true);th.style.height=(colHeight-1)+'px';th.className='jxGridColHead';trBody.appendChild(th);}
-if(this.showRowHeader){var rowWidth=model.getRowHeaderWidth();var tr=document.createElement('tr');var td=document.createElement('td');td.style.width='0px';td.style.height='0px';tr.appendChild(td);var th=document.createElement('th');th.style.width=(rowWidth)+'px';th.style.height='0px';tr.appendChild(th);this.rowTableHead.appendChild(tr);for(var i=0;i<nRows;i++){var rowHeight=model.getRowHeight(i);var tr=document.createElement('tr');var td=document.createElement('td');td.className='jxGridRowHeadHide';td.style.width='0px';td.style.height=(rowHeight)+'px';var p=document.createElement('p');p.style.width='0px';p.style.height=(rowHeight)+'px';td.appendChild(p);tr.appendChild(td);var th=document.createElement('th');th.className='jxGridRowHead';th.innerHTML=model.getRowHeaderHTML(i);tr.appendChild(th);this.rowTableHead.appendChild(tr);}
-var tr=document.createElement('tr');var td=document.createElement('td');td.style.width='0px';td.style.height='1000px';tr.appendChild(td);var th=document.createElement('th');th.style.width=(rowWidth)+'px';th.style.height='1000px';th.className='jxGridRowHead';tr.appendChild(th);this.rowTableHead.appendChild(tr);}
-var colHeight=model.getColumnHeaderHeight();var trBody=document.createElement('tr');this.gridTableBody.appendChild(trBody);var td=document.createElement('td');td.style.width='0px';td.style.height='0px';trBody.appendChild(td);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);td=document.createElement('td');td.className='jxGridColHeadHide';td.style.width=(colWidth)+'px';var p=document.createElement('p');p.style.height='0px';p.style.width=(colWidth)+'px';td.appendChild(p);trBody.appendChild(td);}
-for(var j=0;j<nRows;j++){var rowHeight=model.getRowHeight(j);var actualRowHeight=rowHeight;var tr=document.createElement('tr');this.gridTableBody.appendChild(tr);var td=document.createElement('td');td.className='jxGridRowHeadHide';td.style.width='0px';td.style.height=(rowHeight)+'px';var p=document.createElement('p');p.style.height=(rowHeight)+'px';td.appendChild(p);tr.appendChild(td);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);td=document.createElement('td');td.className='jxGridCell';td.innerHTML=model.getValueAt(j,i);tr.appendChild(td);var tdSize=Element.getDimensions(td);if(tdSize.height>actualRowHeight){actualRowHeight=tdSize.height;}}
-if(document.all){actualRowHeight-=1;}
-if(this.showRowHeader){this.setRowHeaderHeight(j,actualRowHeight);}
-if(this.bAlternateRowColors){tr.className=(j%2)?'jxGridRowOdd':'jxGridRowEven';}else{tr.className='jxGridRowAll';}}}},setRowHeaderHeight:function(row,height){this.rowTableHead.childNodes[row+1].childNodes[0].childNodes[0].style.height=(height)+'px';},gridChanged:function(model,row,col,value){if(this.model==model){this.gridObj.childNodes[row].childNodes[col].innerHTML=value;}},prelightRowHeader:function(row){var cell=(row>=0&&row<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[row+1].cells[1]:null;if(this.prelitRowHeader!=cell){if(this.prelitRowHeader){Element.removeClassName(this.prelitRowHeader,'jxGridRowHeaderPrelight');}
-this.prelitRowHeader=cell;if(this.prelitRowHeader){Element.addClassName(this.prelitRowHeader,'jxGridRowHeaderPrelight');}}},prelightColumnHeader:function(col){if(this.colTableBody.rows.length==0){return;}
-var cell=(col>=0&&col<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[col+1]:null;if(this.prelitColumnHeader!=cell){if(this.prelitColumnHeader){Element.removeClassName(this.prelitColumnHeader,'jxGridColumnHeaderPrelight');}
-this.prelitColumnHeader=cell;if(this.prelitColumnHeader){Element.addClassName(this.prelitColumnHeader,'jxGridColumnHeaderPrelight');}}},prelightRow:function(row){var tr=(row>=0&&row<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[row+1]:null;if(this.prelitRow!=row){if(this.prelitRow){Element.removeClassName(this.prelitRow,'jxGridRowPrelight');}
-this.prelitRow=tr;if(this.prelitRow&&!Element.hasClassName(this.prelitRow,'jxGridRowSelected')){this.prelightRowHeader(row);Element.addClassName(this.prelitRow,'jxGridRowPrelight');}}},prelightColumn:function(col){this.prelightColumnHeader(col);},prelightCell:function(row,col){var td=(row>=0&&col>=0&&row<this.gridTableBody.rows.length-1&&col<this.gridTableBody.rows[row+1].cells.length-1)?this.gridTableBody.rows[row+1].cells[col+1]:null;if(this.prelitCell!=td){if(this.prelitCell){Element.removeClassName(this.prelitCell,'jxGridCellPrelight');}
-this.prelitCell=td;if(this.prelitCell){Element.addClassName(this.prelitCell,'jxGridCellPrelight');this.prelightRow(row);this.prelightColumn(col);}}},selectCell:function(row,col){var td=(row>=0&&col>=0&&row<this.gridTableBody.rows.length-1&&col<this.gridTableBody.rows[row+1].cells.length-1)?this.gridTableBody.rows[row+1].cells[col+1]:null;if(!td){return;}
-if(this.selectedCell){Element.addClassName(this.selectedCell,'jxGridCellSelected');}else{Element.removeClassName(this.selectedCell,'jxGridCellSelected');}},selectRowHeader:function(row,selected){var cell=(row>=0&&row<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[row+1].cells[1]:null;if(!cell){return;}
-if(selected){Element.addClassName(cell,'jxGridRowHeaderSelected');}else{Element.removeClassName(cell,'jxGridRowHeaderSelected');}},selectRow:function(row,selected){var tr=(row>=0&&row<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[row+1]:null;if(tr){if(selected){Element.addClassName(tr,'jxGridRowSelected');}else{Element.removeClassName(tr,'jxGridRowSelected');}}
-this.selectRowHeader(row,selected);},selectColumnHeader:function(col,selected){if(this.colTableBody.rows.length==0){return;}
-var cell=(col>=0&&col<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[col+1]:null;if(cell==null){return;}
-if(selected){Element.addClassName(cell,'jxGridColumnHeaderSelected');}else{Element.removeClassName(cell,'jxGridColumnHeaderSelected');}},selectColumn:function(col,selected){if(col>=0&&col<this.gridTable.rows[0].cells.length){if(selected){for(var i=0;i<this.gridTable.rows.length;i++){Element.removeClassName(this.gridTable.rows[i].cells[this.selectedColumn+1],'jxGridColumnSelected');}}else{for(var i=0;i<this.gridTable.rows.length;i++){Element.addClassName(this.gridTable.rows[i].cells[col+1],'jxGridColumnSelected');}}}
-this.selectColumnHeader(col,selected);},onMouseMoveGrid:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightCell(rc.row,rc.column);},onMouseMoveRowHeader:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightRow(rc.row);},onMouseMoveColumnHeader:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightColumn(rc.column);},onClickGrid:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.cellSelected){this.model.cellSelected(this,rc.row,rc.column);}},onClickRowHeader:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.rowSelected){this.model.rowSelected(this,rc.row);}},onClickColumnHeader:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.columnSelected){this.model.columnSelected(this,rc.column);}},getRowColumnFromEvent:function(e){var td=Event.element(e);if(td.tagName!='TD'&&td.tagName!='TH'){return{row:-1,column:-1};}
-var tr=td.parentNode;var col=td.cellIndex-1;var row=tr.rowIndex-1;if(col==-1){for(var i=0;i<tr.childNodes.length;i++){if(tr.childNodes[i]==td){col=i-1;break;}}}
-return{row:row,column:col};}};Jx.Layout=Class.create();Jx.Layout.prototype={scl:null,initialize:function(domObj,options){options=options||{};this.options=new Jx.Constraint(options);this.domObj=$(domObj);this.domObj.resize=this.resize.bind(this);this.domObj.style.position=this.options.position;this.domObj.jxLayout=this;if(this.domObj.parentNode&&this.domObj.parentNode.tagName=='BODY'){Event.observe(window,'resize',this.windowResize.bind(this));}
-this.scl=[];},windowResize:function(){if(this.resizeTimer){window.clearTimeout(this.resizeTimer);this.resizeTimer=null;}
-this.resizeTimer=window.setTimeout(this.resize.bind(this),250);},resize:function(options){this.resizeTimer=null;var needsResize=false;if(options){for(var i in options){if(this.options[i]!=options[i]){needsResize=true;this.options[i]=options[i];}}
-if(options.forceResize){needsResize=true;}}
-var parentSize;if(this.domObj.parentNode.tagName=='BODY'){parentSize=Element.getPageDimensions();}else{parentSize=Element.getContentBoxSize(this.domObj.parentNode);}
-if(this.lastParentSize&&!needsResize){needsResize=(this.lastParentSize.width!=parentSize.width||this.lastParentSize.height!=parentSize.height);}else{needsResize=true;}
-this.lastParentSize=parentSize;if(!needsResize){return;}
-var l,t,w,h;if(this.options.left!=null){l=this.options.left;if(this.options.right==null){if(this.options.width==null){w=parentSize.width-l;if(w<this.options.minWidth){w=this.options.minWidth;}
-if(this.options.maxWidth>=0&&w>this.options.maxWidth){w=this.options.maxWidth;}}else{w=this.options.width;}}else{if(this.options.width==null){w=parentSize.width-l-this.options.right;if(w<this.options.minWidth){w=this.options.minWidth;}
-if(this.options.maxWidth>=0&&w>this.options.maxWidth){w=this.options.maxWidth;}}else{w=this.options.width;}}}else{if(this.options.right==null){if(this.options.width==null){l=0;w=parentSize.width;if(this.options.maxWidth>=0&&w>this.options.maxWidth){l=l+parseInt(w-this.options.maxWidth)/2;w=this.options.maxWidth;}}else{w=this.options.width;l=parseInt((parentSize.width-w)/2);if(l<0){l=0;}}}else{if(this.options.width!=null){w=this.options.width;l=parentSize.width-w-this.options.right;if(l<0){l=0;}}else{l=0;w=parentSize.width-this.options.right;if(w<this.options.minWidth){w=this.options.minWidth;}
-if(this.options.maxWidth>=0&&w>this.options.maxWidth){l=w-this.options.maxWidth-this.options.right;w=this.options.maxWidth;}}}}
-if(this.options.top!=null){t=this.options.top;if(this.options.bottom==null){if(this.options.height==null){h=parentSize.height-t;if(h<this.options.minHeight){h=this.options.minHeight;}
-if(this.options.maxHeight>=0&&h>this.options.maxHeight){h=this.options.maxHeight;}}else{h=this.options.height;if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=h-this.options.maxHeight;h=this.options.maxHeight;}}}else{if(this.options.height==null){h=parentSize.height-t-this.options.bottom;if(h<this.options.minHeight){h=this.options.minHeight;}
-if(this.options.maxHeight>=0&&h>this.options.maxHeight){h=this.options.maxHeight;}}else{h=this.options.height;}}}else{if(this.options.bottom==null){if(this.options.height==null){t=0;h=parentSize.height;if(h<this.options.minHeight){h=this.options.minHeight;}
-if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=parseInt((parentSize.height-this.options.maxHeight)/2);h=this.options.maxHeight;}}else{h=this.options.height;t=parseInt((parentSize.height-h)/2);if(t<0){t=0;}}}else{if(this.options.height!=null){h=this.options.height;t=parentSize.height-h-this.options.bottom;if(t<0){t=0;}}else{t=0;h=parentSize.height-this.options.bottom;if(h<this.options.minHeight){h=this.options.minHeight;}
-if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=parentSize.height-this.options.maxHeight-this.options.bottom;h=this.options.maxHeight;}}}}
-this.domObj.style.position=this.options.position;if(this.options.position=='absolute'){var padding=Element.getPaddingSize(this.domObj.parentNode);this.domObj.style.left=(l+padding.left)+'px';this.domObj.style.top=(t+padding.top)+'px';Element.setBorderBoxSize(this.domObj,{width:w,height:h});}else{var sizeOpts={width:w};if(this.options.height){sizeOpts.height=this.options.height;}
-Element.setBorderBoxSize(this.domObj,sizeOpts);}
-var o={forceResize:options?options.forceResize:false};for(var i=0;i<this.domObj.childNodes.length;i++){var c=this.domObj.childNodes[i];if(c.resize){c.resize(o);}}
-this.processEvent(this.scl,'sizeChanged',this);},addSizeChangeListener:function(obj){this.addListener(this.scl,obj);},removeSizeChangeListener:function(o){this.removeListener(this.scl,o);}};Object.extend(Jx.Layout.prototype,Jx.Listener.prototype);Jx.Constraint=Class.create();Jx.Constraint.prototype={position:'absolute',left:0,right:0,top:0,bottom:0,width:null,height:null,minWidth:0,minHeight:0,maxWidth:-1,maxHeight:-1,initialize:function(o){for(var i in o){this[i]=o[i];}}};Jx.addStyleSheet('menu/menu.css');Jx.addStyleSheet('button/button.css');Jx.MenuItem=Class.create();Object.extend(Jx.MenuItem.prototype,Jx.Listener.prototype);Object.extend(Jx.MenuItem.prototype,{al:null,domObj:null,parent:null,enabled:false,button:null,initialize:function(action,options){this.initializeItem(options);action.bindTo(this);this.propertyChanged(action);},initializeItem:function(options){if(!options.image){options.image=Jx.baseURL+'images/a_pixel.png';}
-if(!options.label){options.label='&nbsp;';}
-this.label=options.label||'&nbsp;';this.image=options.image||null;this.al=[];this.domObj=document.createElement('li');this.domObj.className='jxMenuItem';var action=new Jx.Action(this.processActionEvent.bindAsEventListener(this))
-this.button=new Jx.Button(action,options);Event.observe(this.button.domObj,'mouseover',this.onmouseover.bindAsEventListener(this),true);this.domObj.appendChild(this.button.domObj);},setParent:function(obj){this.parent=obj;},hide:function(){},show:function(){},addActionListener:function(obj){this.addListener(this.al,obj);},removeActionListener:function(obj){this.removeListener(this.al,obj);},processActionEvent:function(e){if(this.enabled){this.processEvent(this.al,'actionPerformed',this);if(this.parent&&this.parent.deactivate){this.parent.deactivate(e);}}},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj.childNodes[0].childNodes[0],'jxDisabled');}else{Element.addClassName(this.domObj.childNodes[0].childNodes[0],'jxDisabled');}},onmouseover:function(e){var target=Event.element(e);if(this.parent&&this.parent.setVisibleItem){this.parent.setVisibleItem(this);}
-this.show();}});Jx.MenuSeparator=Class.create();Object.extend(Jx.MenuSeparator.prototype,{domObj:null,parent:null,initialize:function(){this.domObj=document.createElement('li');this.domObj.className='jxMenuItem';var span=document.createElement('span');span.className='jxMenuSeparator';span.innerHTML='&nbsp;';this.domObj.appendChild(span);},setParent:function(obj){this.parent=obj;},hide:function(){},show:function(){}});Jx.SubMenu=Class.create();Object.extend(Jx.SubMenu.prototype,Jx.MenuItem.prototype);Object.extend(Jx.SubMenu.prototype,{subDomObj:null,parent:null,visibleItem:null,items:null,initialize:function(options){this.open=false;this.items=[];this.initializeItem(options);Element.addClassName(this.domObj.childNodes[0].childNodes[0],'jxButtonSubMenu');this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.subDomObj=document.createElement('ul');this.subDomObj.className='jxSubMenu';this.subDomObj.style.display='none';this.domObj.appendChild(this.subDomObj);},setParent:function(obj){this.parent=obj;},show:function(){if(this.open||this.items.length==0){return;}
-this.open=true;this.subDomObj.style.display='block';if(!window.opera){this.subDomObj.childNodes[0].appendChild(this.iframe);var size=Element.getBorderBoxSize(this.subDomObj);this.iframe.style.width=size.width+"px";this.iframe.style.height=size.height+"px";}
-this.setActive(true);},hide:function(){if(!this.open){return;}
-this.open=false;for(var i=0;i<this.items.length;i++){this.items[i].hide();}
-this.subDomObj.style.display='none';if(!window.opera&&this.iframe.parentNode){this.subDomObj.childNodes[0].removeChild(this.iframe);}
-this.visibleItem=null;},add:function(){for(var i=0;i<arguments.length;i++){var item=arguments[i];this.items.push(item);item.setParent(this);this.subDomObj.appendChild(item.domObj);}},insertBefore:function(newItem,targetItem){var bInserted=false;for(var i=0;i<this.items.length;i++){if(this.items[i]==targetItem){this.items.splice(i,0,newItem);this.subDomObj.insertBefore(newItem.domObj,targetItem.domObj);bInserted=true;break;}}
-if(!bInserted){this.add(newItem);}},remove:function(item){for(var i=0;i<this.items.length;i++){if(this.items[i]==item){this.items.splice(i,1);this.subDomObj.removeChild(item.domObj);break;}}},processActionEvent:function(e){if(this.open){this.hide();}else{this.show();}
-return Event.stop(e);},deactivate:function(e){if(this.parent){this.parent.deactivate(e);}},isActive:function(){if(this.parent){return this.parent.isActive();}else{return false;}},setActive:function(isActive){if(this.parent&&this.parent.setActive){this.parent.setActive(isActive);}},setVisibleItem:function(obj){if(this.visibleItem!=obj){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide();}
-this.visibleItem=obj;this.visibleItem.show();}}});Jx.Menu=Class.create();Jx.Menu.prototype={domObj:null,buttonObj:null,subDomObj:null,items:null,menus:[],initialize:function(options){this.items=[];this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.subDomObj=document.createElement('ul');this.subDomObj.className='jxMenu';this.subDomObj.style.display='none';if(options){this.domObj=document.createElement('li');var action=new Jx.Action(this.show.bind(this));this.button=new Jx.Button(action,options);Element.addClassName(this.button.domObj.firstChild,'jxButtonMenu');this.domObj.appendChild(this.button.domObj);Event.observe(this.domObj,'mouseover',this.onMouseOver.bindAsEventListener(this));this.domObj.appendChild(this.subDomObj);}
-this.hideWatcher=this.hide.bindAsEventListener(this);},add:function(){for(var i=0;i<arguments.length;i++){var item=arguments[i];this.items.push(item);item.setParent(this);this.subDomObj.appendChild(item.domObj);}},deactivate:function(){this.hide();},actionPerformed:function(){this.hide();},onMouseOver:function(e){if(this.menus[0]&&this.menus[0]!=this){this.show(e);}},hide:function(e){if(e){var root=Event.findElement(e,'LI');if(root==this.domObj){return;}}
-if(this.menus[0]&&this.menus[0]==this){this.menus[0]=null;}
-for(var i=0;i<this.items.length;i++){this.items[i].hide(e);}
-Event.stopObserving(document,'click',this.hideWatcher,true);this.subDomObj.style.display='none';},show:function(e){if(this.menus[0]&&this.menus[0]!=this){this.menus[0].hide(e);}
-if(this.items.length==0){return;}
-this.menus[0]=this;this.subDomObj.style.display='block';this.subDomObj.style.visibility='visible';if(!window.opera){this.subDomObj.childNodes[0].appendChild(this.iframe);var size=Element.getContentBoxSize(this.subDomObj);this.iframe.style.width=size.width+"px";this.iframe.style.height=size.height+"px";}
-Event.stop(e);Event.observe(document,'click',this.hideWatcher,true);},setVisibleItem:function(obj){if(this.visibleItem!=obj){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide();}
-this.visibleItem=obj;this.visibleItem.show();}}};Jx.ContextMenu=Class.create();Object.extend(Jx.ContextMenu.prototype,Jx.Menu.prototype);Object.extend(Jx.ContextMenu.prototype,{initialize:function(id){Jx.Menu.prototype.initialize.apply(this,[]);document.getElementsByTagName('BODY')[0].appendChild(this.subDomObj);if($(id)){$(id).oncontextmenu=this.show.bindAsEventListener(this);;}},show:function(e){this.subDomObj.style.left=Event.pointerX(e)+"px";this.subDomObj.style.top=Event.pointerY(e)+"px";Jx.Menu.prototype.show.apply(this,[e]);}});Jx.addStyleSheet('panel/panel.css');Jx.PanelManager=Class.create();Jx.PanelManager.prototype={panels:null,height:null,firstLayout:true,initialize:function(domObj,panels){this.domObj=$(domObj);this.panels=panels;var d=document.createElement('div');d.style.position='absolute';new Jx.Layout(d,{minHeight:0,maxHeight:0,height:0});var elements=[d];for(var i=0;i<this.panels.length;i++){elements.push(this.panels[i].domObj);}
-this.splitter=new Jx.Splitter(this.domObj,{splitInto:panels.length+1,layout:'vertical',elements:elements});this.splitter.sizeChanged=this.sizeChanged.bind(this);for(var i=0;i<this.panels.length;i++){var panel=this.panels[i];this.splitter.bars[i].appendChild(panel.title);this.splitter.bars[i].style.height=Element.getBorderBoxSize(panel.title).height+'px';Element.removeClassName(this.splitter.bars[i],'jxSplitterBar');Element.addClassName(this.splitter.bars[i],'jxPanelBar');panel.manager=this;}},sizeChanged:function(){if(this.firstLayout){if(Element.getBorderBoxSize(this.panels[0].title).height!=0){for(var i=0;i<this.splitter.bars.length;i++){var panel=this.panels[i];this.splitter.bars[i].style.height=Element.getBorderBoxSize(panel.title).height+'px';this.splitter.bars[i].size=null;}
-this.firstLayout=false;Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[]);}}else{Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[]);}},maximizePanel:function(panel){var h=Element.getContentBoxSize(this.domObj).height;var t=0;for(var i=1;i<this.splitter.elements.length;i++){var p=this.splitter.elements[i];t+=Element.getBorderBoxSize(p.leftBar).height;if(p!==panel.domObj){p.jxLayout.resize({top:t,height:p.jxLayout.options.minHeight,bottom:null});t+=p.jxLayout.options.minHeight;p.rightBar.style.top=t+'px';}else{break;}}
-b=h;for(var i=this.splitter.elements.length-1;i>0;i--){p=this.splitter.elements[i];if(p!==panel.domObj){b-=p.jxLayout.options.minHeight;p.jxLayout.resize({top:b,height:p.jxLayout.options.minHeight,bottom:null});b-=Element.getBorderBoxSize(p.leftBar).height;p.leftBar.style.top=b+'px';}else{break;}}
-panel.domObj.jxLayout.resize({top:t,height:b-t,bottom:null});}};Jx.Panel=Class.create();Jx.Panel.prototype={labelObj:null,state:'open',busyCount:null,bContentReady:null,onContentReady:null,initialize:function(options){this.initUniqueId();this.title=document.createElement('div');this.title.className="jxPanelTitle";this.title.style.height='22px';this.labelObj=document.createElement('span');this.labelObj.className='jxPanelLabel';this.labelObj.innerHTML=options.label?options.label:'empty';this.imageBaseUrl=options.imageBaseUrl||Jx.baseURL+'images/';var a,img;if(options.helpCallback){a=document.createElement('a');a.className='jxPanelHelp';a.href='javascript:void(0)';Event.observe(a,'click',options.helpCallback);img=document.createElement('img');img.src=this.imageBaseUrl+"help.png";img.alt='Help on this panel';img.title='Help on this panel';a.appendChild(img);this.title.appendChild(a);}
-a=document.createElement('a');a.className='jxPanelMaximize';a.href='javascript:void(0)';Event.observe(a,'click',this.maximize.bindAsEventListener(this));img=document.createElement('img');img.src=this.imageBaseUrl+"maximize.png";img.alt='Maximize Panel';img.title='Maximize Panel';a.appendChild(img);this.title.appendChild(a);a=document.createElement('a');a.className='jxPanelLoading';a.href='javascript:void(0)';img=document.createElement('img');img.src=this.imageBaseUrl+"loading.gif";img.alt='Loading Panel';img.title='Loading Panel';a.appendChild(img);this.loadingObj={};this.loadingObj.link=a;this.loadingObj.img=img;this.title.appendChild(this.loadingObj.link);this.title.appendChild(this.labelObj);Event.observe(this.title,'dblclick',this.maximize.bindAsEventListener(this));this.domObj=document.createElement('div');this.domObj.className='jxPanel';this.jxLayout=new Jx.Layout(this.domObj,options.constraint||{});this.jxLayout.addSizeChangeListener(this);var top=0;var bottom=0;if(options.menubar){this.menubar=options.menubar;this.domObj.appendChild(options.menubar);var h=Element.getBorderBoxSize(options.menubar).height;new Jx.Layout(this.menubar,{top:top,height:h});top+=h;}
-if(options.toolbar){this.toolbar=options.toolbar;this.domObj.appendChild(options.toolbar);var h=Element.getBorderBoxSize(options.toolbar).height;new Jx.Layout(this.toolbar,{top:top,height:h});}
-if(options.statusbar){this.statusbar=options.statusbar;this.domObj.appendChild(options.statusbar);var h=Element.getBorderBoxSize(options.statusbar).height;new Jx.Layout(this.statusbar,{bottom:bottom,height:h,top:null});bottom+=h;}
-this.content=document.createElement('div');Element.addClassName(this.content,'jxPanelContent');new Jx.Layout(this.content,{top:top,bottom:bottom});this.domObj.appendChild(this.content);this.loadContent(this.content,options);this.busyCount=0;this.bContentReady=false;},setLabel:function(s){this.labelObj.innerHTML=s;},getLabel:function(){return this.labelObj.innerHTML;},finalize:function(){this.domObj=null;this.deregisterIds();},maximize:function(){if(this.manager){this.manager.maximizePanel(this);}},setContent:function(html){this.content.innerHTML=html;this.bContentReady=true;},setContentURL:function(url){this.bContentReady=false;this.setBusy(true);if(arguments[1]){this.onContentReady=arguments[1];}
-if(url.indexOf('?')==-1){url=url+'?';}
-var opts={method:'get',onComplete:this.panelContentLoaded.bind(this),requestHeaders:['If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT']};var a=new Ajax.Request(url,opts);},panelContentLoaded:function(r){this.content.innerHTML=r.responseText;this.bContentReady=true;this.setBusy(false);if(this.onContentReady){window.setTimeout(this.onContentReady.bind(this),1);}},setBusy:function(isBusy){this.busyCount+=isBusy?1:-1;this.loadingObj.img.style.visibility=(this.busyCount>0)?'visible':'hidden';},sizeChanged:function(){var top=0;var bottom=0;if(this.menubar){this.menubar.style.height='';var size=Element.getBorderBoxSize(this.menubar);this.menubar.resize({height:size.height});top+=size.height;}
-if(this.toolbar){this.toolbar.style.height='';var size=Element.getBorderBoxSize(this.toolbar);this.toolbar.resize({height:size.height});top+=size.height;}
-if(this.statusbar){this.statusbar.style.height='';var size=Element.getBorderBoxSize(this.statusbar);this.statusbar.resize({height:size.height});bottom+=size.height;}
-if(top||bottom){this.content.resize({bottom:bottom,top:top});}}};Object.extend(Jx.Panel.prototype,Jx.UniqueId.prototype);Object.extend(Jx.Panel.prototype,Jx.ContentLoader.prototype);Jx.addStyleSheet('picker/picker.css');Jx.Picker=Class.create();Jx.Picker.prototype={sl:null,domObj:null,ul:null,currentSelection:null,isEditable:false,initialize:function(options){options=options||{};this.domObj=document.createElement('div');this.domObj.className='jxPicker';this.isEditable=options.editable||false;if(this.isEditable){this.domInput=document.createElement('input');this.domInput.type='text';Event.observe(this.domInput,'change',this.valueChanged.bind(this));Event.observe(this.domInput,'keydown',this.onKeyPress.bind(this));}else{this.domInput=document.createElement('span');}
-this.domInput.className='jxPickerInput';this.domObj.appendChild(this.domInput);this.domA=document.createElement('a');this.domA.href='javascript:void(0)';this.domA.className='jxPickerDiscloser';Event.observe(this.domA,'click',this.toggle.bind(this));this.domButton=document.createElement('img');this.domButton.src=Jx.baseURL+'images/disclose2.png';Element.addClassName(this.domButton,'png24');this.domA.appendChild(this.domButton);this.domObj.appendChild(this.domA);if(!window.opera){var iframe=document.createElement('iframe');iframe.className='jxDialogShim';iframe.scrolling='no';iframe.frameborder=0;this.domObj.appendChild(iframe);}
-this.domListDiv=document.createElement('div');this.domListDiv.className='jxPickerOptions';this.domListDiv.style.display='none';this.domObj.appendChild(this.domListDiv);this.domList=document.createElement('ul');this.domListDiv.appendChild(this.domList);this.sl=[];},onKeyPress:function(e){var charCode=(e.charCode)?e.charCode:((e.keyCode)?e.keyCode:e.which);if(charCode==Event.KEY_RETURN){this.valueChanged();}},valueChanged:function(){this.processEvent(this.sl,'selectionChanged',this);},add:function(domObj,idx){var li=document.createElement('li');var a=document.createElement('a');a.href="javascript:void(0)";if(typeof(domObj)=='string'){a.innerHTML=domObj;}else{a.appendChild(domObj);}
-Event.observe(a,'click',this.pick.bindAsEventListener(this));li.appendChild(a);if(arguments.length>1&&this.domList.childNodes.length>idx){this.domList.insertBefore(li,this.domList.childNodes[idx]);}else{this.domList.appendChild(li);}
-if(this.getValue()==''){this.setValue(a.childNodes[0]);}},remove:function(idx){if(idx>0&&idx<this.domList.childNodes.length){this.domList.removeChild(this.domList.childNodes[idx]);}},pick:function(e){var target=Event.element(e);if(target.tagName=='A'){this.currentSelection=target;this.setValue(this.currentSelection.childNodes[0]);this.valueChanged();}
-this.close();},setValue:function(value){if(this.isEditable){if(typeof(value)=='string'){this.domInput.value=value;}else if(value.nodeType&&value.nodeType==3){this.domInput.value=value.nodeValue;}else{this.domInput.value=value.innerHTML;}}else if(!this.isEditable){if(typeof(value)=='string'){this.domInput.innerHTML=value;}else if(value.nodeType&&value.nodeType==3){this.domInput.innerHTML=value.nodeValue;}else{this.domInput.appendChild(value);}}},getValue:function(){value='';if(this.isEditable){value=this.domInput.value;}else if(this.domInput.childNodes.length>0){if(this.domInput.childNodes[0].nodeType==3){value=this.domInput.innerHTML;}else{value=this.domInput.childNodes[0];}}
-return value;},toggle:function(){if(this.domListDiv.style.display=='block'){this.close();}else{this.open();}},open:function(){if(!this.keypressListener){this.keypressListener=this.keypress.bindAsEventListener(this);}
-this.domListDiv.style.display='block';Event.observe(document,'keypress',this.keypressListener);},keypress:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.close();}},close:function(){this.domListDiv.style.display='none';Event.stopObserving(document,'keypress',this.keypressListener);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);},getSelection:function(){return this.currentSelection?this.currentSelection.name:'';}};Object.extend(Jx.Picker.prototype,Jx.Listener.prototype);Jx.Splitter=Class.create();Jx.Splitter.prototype={domObj:null,elements:null,bars:null,firstUpdate:true,initialize:function(domObj,options){options=options||{};this.domObj=$(domObj);this.domObj.style.overflow='hidden';if(this.domObj.jxLayout){this.domObj.jxLayout.addSizeChangeListener(this);}
-this.elements=[];this.bars=[];var nSplits=options.splitInto||(options.elements?options.elements.length:2);var aContainerOpts=options.containerOptions||[];for(var i=0;i<nSplits;i++){this.elements[i]=options.elements?options.elements[i]:this.prepareElement();this.domObj.appendChild(this.elements[i]);if(!this.elements[i].jxLayout){new Jx.Layout(this.elements[i],aContainerOpts[i]);}}
-for(var i=1;i<nSplits;i++){this.bars[i-1]=this.prepareBar();this.bars[i-1].leftSide=this.elements[i-1];this.bars[i-1].rightSide=this.elements[i];this.elements[i-1].rightBar=this.bars[i-1];this.elements[i].leftBar=this.bars[i-1];this.domObj.appendChild(this.bars[i-1]);}
-this.layout=options.layout||'horizontal';this.establishConstraints();if(options.snappers){for(var i=0;i<options.snappers.length;i++){if(options.snappers[i]){new Jx.Splitter.Snapper(options.snappers[i],this.elements[i],this);}}}},prepareElement:function(){var o=document.createElement('div');o.style.position='absolute';o.leftBar=null;o.rightBar=null;return o;},prepareBar:function(){var o=document.createElement('div');o.className='jxSplitterBar';o.style.position='absolute';o.title='drag this bar to resize';o.style.lineHeight='1px';o.splitterObj=this;return o;},establishConstraints:function(){if(this.layout=='horizontal'){for(var i=0;i<this.bars.length;i++){this.bars[i].style.top='0px';this.bars[i].style.height='100%';new Draggable(this.bars[i],{constraint:'horizontal',starteffect:function(element){element.style.backgroundColor='#eee';},endeffect:function(element){element.style.backgroundColor='';}});}}else{for(var i=0;i<this.bars.length;i++){this.bars[i].style.left='0px';this.bars[i].style.width='100%';new Draggable(this.bars[i],{constraint:'vertical',starteffect:function(element){element.style.backgroundColor='#eee';},endeffect:function(element){element.style.backgroundColor='';}});}}
-Draggables.addObserver(this);},onEnd:function(eventName,obj,event){if(obj.element.splitterObj!=this){return;}
-if(this.layout=='horizontal'){this.dragHorizontal(eventName,obj,event);}else{this.dragVertical(eventName,obj,event);}},dragHorizontal:function(eventName,obj,event){var leftEdge=parseInt(obj.element.style.left);var leftSide=obj.element.leftSide;var rightSide=obj.element.rightSide;var rsLeft,rsWidth,rsRight;if(!obj.element.size){obj.element.size=Element.getBorderBoxSize(obj.element);}
-var barSize=obj.element.size;rsLeft=leftEdge+barSize.width;var parentSize=Element.getContentBoxSize(this.domObj);if(rightSide.jxLayout.options.width!=null){rsWidth=rightSide.jxLayout.options.width+rightSide.jxLayout.options.left-rsLeft;rsRight=parentSize.width-rsLeft-rsWidth;}else{rsWidth=parentSize.width-rightSide.jxLayout.options.right-rsLeft;rsRight=rightSide.jxLayout.options.right;}
-if(rsWidth<0){rsWidth=0;}
-if(rsWidth<rightSide.jxLayout.options.minWidth){rsWidth=rightSide.jxLayout.options.minWidth;}
-if(rightSide.jxLayout.options.maxWidth>=0&&rsWidth>rightSide.jxLayout.options.maxWidth){rsWidth=rightSide.jxLayout.options.maxWidth;}
-rsLeft=parentSize.width-rsRight-rsWidth;leftEdge=rsLeft-barSize.width;var lsLeft,lsWidth;lsLeft=leftSide.jxLayout.options.left;lsWidth=leftEdge-lsLeft;if(lsWidth<0){lsWidth=0;}
-if(lsWidth<leftSide.jxLayout.options.minWidth){lsWidth=leftSide.jxLayout.options.minWidth;}
-if(leftSide.jxLayout.options.maxWidth>=0&&lsWidth>leftSide.jxLayout.options.maxWidth){lsWidth=leftSide.jxLayout.options.maxWidth;}
-if(lsLeft+lsWidth!=leftEdge){leftEdge=lsLeft+lsWidth;var delta=leftEdge+barSize.width-rsLeft;rsLeft+=delta;rsWidth-=delta;}
-obj.element.style.left=leftEdge+'px';if(leftSide.jxLayout.options.width==null){var parentSize=Element.getContentBoxSize(this.domObj);leftSide.jxLayout.resize({right:parentSize.width-lsLeft-lsWidth});}else{leftSide.jxLayout.resize({width:lsWidth});}
-if(rightSide.jxLayout.options.width==null){rightSide.jxLayout.resize({left:rsLeft});}else{rightSide.jxLayout.resize({left:rsLeft,width:rsWidth});}},dragVertical:function(eventName,obj,event){var topEdge=parseInt(obj.element.style.top);var topSide=obj.element.leftSide;var bottomSide=obj.element.rightSide;if(!obj.element.size){obj.element.size=Element.getBorderBoxSize(obj.element);}
-var barSize=obj.element.size;var parentSize=Element.getContentBoxSize(this.domObj);var bsTop,bsHeight,bsBottom;bsTop=topEdge+barSize.height;if(bottomSide.jxLayout.options.height!=null){bsHeight=bottomSide.jxLayout.options.height+bottomSide.jxLayout.options.top-bsTop;bsBottom=parentSize.height-bsTop-bsHeight;}else{bsHeight=parentSize.height-bottomSide.jxLayout.options.bottom-bsTop;bsBottom=bottomSide.jxLayout.options.bottom;}
-if(bsHeight<0){bsHeight=0;}
-if(bsHeight<bottomSide.jxLayout.options.minHeight){bsHeight=bottomSide.jxLayout.options.minHeight;}
-if(bottomSide.jxLayout.options.maxHeight>=0&&bsHeight>bottomSide.jxLayout.options.maxHeight){bsHeight=bottomSide.jxLayout.options.maxHeight;}
-bsTop=parentSize.height-bsBottom-bsHeight;topEdge=bsTop-barSize.height;var tsTop,tsHeight;tsTop=topSide.jxLayout.options.top;tsHeight=topEdge-tsTop;if(tsHeight<0){tsHeight=0;}
-if(tsHeight<topSide.jxLayout.options.minHeight){tsHeight=topSide.jxLayout.options.minHeight;}
-if(topSide.jxLayout.options.maxHeight>=0&&tsHeight>topSide.jxLayout.options.maxHeight){tsHeight=topSide.jxLayout.options.maxHeight;}
-if(tsTop+tsHeight!=topEdge){topEdge=tsTop+tsHeight;var delta=topEdge+barSize.height-bsTop;bsTop+=delta;bsHeight-=delta;}
-obj.element.style.top=topEdge+'px';if(topSide.jxLayout.options.height==null){topSide.jxLayout.resize({bottom:parentSize.height-tsTop-tsHeight});}else{topSide.jxLayout.resize({height:tsHeight});}
-if(bottomSide.jxLayout.options.height==null){bottomSide.jxLayout.resize({top:bsTop});}else{bottomSide.jxLayout.resize({top:bsTop,height:bsHeight});}},sizeChanged:function(){if(this.layout=='horizontal'){this.horizontalResize();}else{this.verticalResize();}},horizontalResize:function(){var availableSpace=Element.getContentBoxSize(this.domObj).width;var overallWidth=availableSpace;for(var i=0;i<this.bars.length;i++){var bar=this.bars[i];if(!bar.size){bar.size=Element.getBorderBoxSize(bar);}
-availableSpace-=bar.size.width;}
-var nVariable=0;var jxo;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];jxo=e.jxLayout.options;if(jxo.width!=null){availableSpace-=parseInt(jxo.width);}else{var w=0;if(jxo.right!=0||jxo.left!=0){w=Element.getBorderBoxSize(e).width;}
-availableSpace-=w;nVariable++;}}
-if(nVariable==0){availableSpace+=jxo.width;jxo.width=null;nVariable=1;}
-var amount=parseInt(availableSpace/nVariable);var remainder=availableSpace%nVariable;var currentPosition=0;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];var jxl=e.jxLayout;var jxo=jxl.options;if(jxo.width!=null){jxl.resize({left:currentPosition});currentPosition+=jxo.width;}else{var a=amount;if(nVariable==1){a+=remainder;}
-nVariable--;var w=0;if(jxo.right!=0||jxo.left!=0){w=Element.getBorderBoxSize(e).width+a;}else{w=a;}
-if(w<0){if(nVariable>0){amount=amount+w/nVariable;}
-w=0;}
-if(w<jxo.minWidth){if(nVariable>0){amount=amount+(w-jxo.minWidth)/nVariable;}
-w=jxo.minWidth;}
-if(jxo.maxWidth>=0&&w>jxo.maxWidth){if(nVariable>0){amount=amount+(w-jxo.maxWidth)/nVariable;}
-w=e.options.maxWidth;}
-var r=overallWidth-currentPosition-w;jxl.resize({left:currentPosition,right:r});currentPosition+=w;}
-if(e.rightBar){e.rightBar.style.left=currentPosition+'px';currentPosition+=e.rightBar.size.width;}}},verticalResize:function(){var availableSpace=Element.getContentBoxSize(this.domObj).height;var overallHeight=availableSpace;for(var i=0;i<this.bars.length;i++){var bar=this.bars[i];if(!bar.size){bar.size=Element.getBorderBoxSize(bar);}
-availableSpace-=bar.size.height;}
-var nVariable=0;var jxo;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];jxo=e.jxLayout.options;if(jxo.height!=null){availableSpace-=parseInt(jxo.height);}else{var h=0;if(jxo.bottom!=0||jxo.top!=0){h=Element.getBorderBoxSize(e).height;}
-availableSpace-=h;nVariable++;}}
-if(nVariable==0){availableSpace+=jxo.height;jxo.height=null;nVariable=1;}
-var amount=parseInt(availableSpace/nVariable);var remainder=availableSpace%nVariable;var currentPosition=0;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];var jxl=e.jxLayout;var jxo=jxl.options;if(jxo.height!=null){jxl.resize({top:currentPosition});currentPosition+=jxo.height;}else{var a=amount;if(nVariable==1){a+=remainder;}
-nVariable--;var h=0;if(jxo.bottom!=0||jxo.top!=0){h=Element.getBorderBoxSize(e).height+a;}else{h=a;}
-if(h<0){if(nVariable>0){amount=amount+h/nVariable;}
-h=0;}
-if(h<jxo.minHeight){if(nVariable>0){amount=amount+(h-jxo.minHeight)/nVariable;}
-h=jxo.minHeight;}
-if(jxo.maxHeight>=0&&h>jxo.maxHeight){if(nVariable>0){amount=amount+(h-jxo.maxHeight)/nVariable;}
-h=jxo.maxHeight;}
-var r=overallHeight-currentPosition-h;jxl.resize({top:currentPosition,bottom:r});currentPosition+=h;}
-if(e.rightBar){e.rightBar.style.top=currentPosition+'px';currentPosition+=e.rightBar.size.height;}}}};Jx.Splitter.Snapper=Class.create();Jx.Splitter.Snapper.prototype={snapper:null,element:null,splitter:null,layout:'vertical',initialize:function(snapper,element,splitter){this.snapper=snapper;this.element=element;element.jxLayout.addSizeChangeListener(this);this.splitter=splitter;this.layout=splitter.layout;var jxo=this.element.jxLayout.options;var size=Element.getBorderBoxSize(this.element);if(this.layout=='vertical'){this.originalSize=size.height;this.minimumSize=jxo.minHeight?jxo.minHeight:0;}else{this.originalSize=size.width;this.minimumSize=jxo.minWidth?jxo.minWidth:0;}
-Event.observe(snapper,'click',this.toggleElement.bind(this));},toggleElement:function(){var size=Element.getBorderBoxSize(this.element);var newSize={};if(this.layout=='vertical'){if(size.height==this.minimumSize){newSize.height=this.originalSize;}else{this.originalSize=size.height;newSize.height=this.minimumSize;}}else{if(size.width==this.minimumSize){newSize.width=this.originalSize;}else{this.originalSize=size.width;newSize.width=this.minimumSize;}}
-this.element.jxLayout.resize(newSize);this.splitter.sizeChanged();},sizeChanged:function(){var size=Element.getBorderBoxSize(this.element);if(this.layout=='vertical'){if(size.height==this.minimumSize){Element.addClassName(this.snapper,'jxSnapClosed');Element.removeClassName(this.snapper,'jxSnapOpened');}else{Element.addClassName(this.snapper,'jxSnapOpened');Element.removeClassName(this.snapper,'jxSnapClosed');}}else{if(size.width==this.minimumSize){Element.addClassName(this.snapper,'jxSnapClosed');Element.removeClassName(this.snapper,'jxSnapOpened');}else{Element.addClassName(this.snapper,'jxSnapOpened');Element.removeClassName(this.snapper,'jxSnapClosed');}}}};Jx.addStyleSheet('tab/tabs.css');Jx.addStyleSheet('tabs/tabs_ie.css',true);Jx.TabSet=Class.create();Jx.TabSet.prototype={domObj:null,sl:null,initialize:function(domObj){this.domObj=$(domObj);if(!Element.hasClassName(this.domObj,'jxTabSetContainer')){Element.addClassName(this.domObj,'jxTabSetContainer');}
-this.sl=[];},sizeChanged:function(){this.resizeTabBox();},resizeTabBox:function(){var parentSize=Element.getContentBoxSize(this.domObj.parentNode);Element.setBorderBoxSize(this.domObj,{width:parentSize.width,height:parentSize.height});for(var i=0;i<this.domObj.childNodes.length;i++){if(this.domObj.childNodes[i].nodeType==3){continue;}
-Element.setBorderBoxSize(this.domObj.childNodes[i],{height:parentSize.height});if(this.domObj.childNodes[i].resize){this.domObj.childNodes[i].resize({forceResize:true});}}},add:function(){for(var i=0;i<arguments.length;i++){var tab=arguments[i];tab.addSelectionListener(this);this.domObj.appendChild(tab.content);if(!this.activeTab){this.setActiveTab(tab);}}},remove:function(tab){},setActiveTab:function(tab){if(this.activeTab){Element.removeClassName(this.activeTab.domObj,'tabActive');Element.removeClassName(this.activeTab.content,'tabContentActive');}
-this.activeTab=tab;Element.addClassName(this.activeTab.domObj,'tabActive');Element.addClassName(this.activeTab.content,'tabContentActive');if(this.activeTab.content.resize){this.activeTab.content.resize({forceResize:true});}},selectionChanged:function(tab){this.setActiveTab(tab);this.processEvent(this.sl,'selectionChanged',tab);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);}};Object.extend(Jx.TabSet.prototype,Jx.Listener.prototype);Jx.Tab=Class.create();Jx.Tab.prototype={domObj:null,content:null,name:null,sl:null,initialize:function(name,options){this.sl=[];options=options||{};this.name=name;this.content=document.createElement('div');this.content.className='tabContent';this.loadContent(this.content,options);var a=new Jx.Action(this.clicked.bind(this));var b=new Jx.Button(a,{label:name});this.domObj=b.domA;Element.addClassName(this.domObj,'jxTab');new Jx.Layout(this.content,options);},clicked:function(){this.processEvent(this.sl,'selectionChanged',this);this.domObj.childNodes[0].blur();},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);}};Object.extend(Jx.Tab.prototype,Jx.Listener.prototype);Object.extend(Jx.Tab.prototype,Jx.ContentLoader.prototype);Jx.TabBox=Class.create();Jx.TabBox.prototype={tabBar:null,tabSet:null,initialize:function(domObj,position){var parent=$(domObj);position=position||'top';var tabBarDiv=document.createElement('div');parent.appendChild(tabBarDiv);this.tabBar=new Jx.Toolbar(tabBarDiv,position);this.tabSet=new Jx.TabSet(parent);switch(position){case'top':Element.addClassName(parent,'jxTabBoxTop');break;case'bottom':Element.addClassName(parent,'jxTabBoxBottom');break;case'left':Element.addClassName(parent,'jxTabBoxLeft');Element.addClassName(tabBarDiv,'verticalToolbar');break;case'right':Element.addClassName(parent,'jxTabBoxRight');Element.addClassName(tabBarDiv,'verticalToolbar');break;}
-this.sl=[];},sizeChanged:function(){this.tabSet.sizeChanged();},add:function(){this.tabBar.add.apply(this.tabBar,arguments);this.tabSet.add.apply(this.tabSet,arguments);},remove:function(tab){}};Object.extend(Jx.TabBox.prototype,Jx.Listener.prototype);Jx.addStyleSheet('toolbar/toolbar.css');Jx.addStyleSheet('button/button.css');Jx.Toolbar=Class.create();Jx.Toolbar.prototype={items:null,domObj:null,isActive:false,initialize:function(domObj,position){var parent=$(domObj);this.domObj=document.createElement('ul');Element.addClassName(this.domObj,'jxToolbar');if(!Element.hasClassName(parent,'jxToolbarContainer')){Element.addClassName(parent,'jxToolbarContainer');parent.appendChild(this.domObj);var clearer=document.createElement('div');clearer.className='jxClearer';parent.appendChild(clearer);}else{parent.insertBefore(this.domObj,parent.lastChild);}
-switch(position){case'top':Element.addClassName(parent,'jxBarTop');break;case'right':Element.addClassName(parent,'jxBarRight');break;case'bottom':Element.addClassName(parent,'jxBarBottom');break;case'left':Element.addClassName(parent,'jxBarLeft');break;default:Element.addClassName(parent,'jxBarTop');}
-this.deactivateWatcher=this.deactivate.bindAsEventListener(this);},add:function(){for(var i=0;i<arguments.length;i++){var thing=arguments[i];thing.toolbar=this;if(thing.domObj){thing=thing.domObj;}
-if(thing.tagName=='LI'){if(!Element.hasClassName(thing,'jxToolItem')){Element.addClassName(thing,'jxToolItem');}
-this.domObj.appendChild(thing);}else{var item=new Jx.ToolbarItem(thing);this.domObj.appendChild(item.domObj);}}},deactivate:function(){for(var i=0;i<this.items.length;i++){this.items[i].hide();}
-this.setActive(false);},isActive:function(){return this.isActive;},setActive:function(b){this.isActive=b;if(this.isActive){Event.observe(document,'click',this.deactivateWatcher);}else{Event.stopObserving(document,'click',this.deactivateWatcher);}},setVisibleItem:function(obj){if(this.visibleItem&&this.visibleItem.hide&&this.visibleItem!=obj){this.visibleItem.hide();}
-this.visibleItem=obj;if(this.isActive()){this.visibleItem.show();}}};Jx.ToolbarItem=Class.create();Jx.ToolbarItem.prototype={domObj:null,initialize:function(jxThing){this.al=[];this.domObj=document.createElement('li');this.domObj.className='jxToolItem';if(jxThing){if(jxThing.domObj){this.domObj.appendChild(jxThing.domObj);if(jxThing instanceof Jx.Tab){Element.addClassName(this.domObj,'jxTabItem');}}else{this.domObj.appendChild(jxThing);if(Element.hasClassName(jxThing,'jxTab')){Element.addClassName(this.domObj,'jxTabItem');}}}}};Jx.ToolbarSeparator=Class.create();Jx.ToolbarSeparator.prototype={domObj:null,initialize:function(){this.domObj=document.createElement('li');this.domObj.className='jxToolItem';this.domSpan=document.createElement('span');this.domSpan.className='separator';this.domObj.appendChild(this.domSpan);}};Jx.addStyleSheet('tree/tree.css');Jx.addStyleSheet('tree/tree_ie.css',true);Jx.TreeItem=Class.create();Jx.TreeItem.prototype={data:null,domObj:null,parent:null,currentClassName:null,onClick:null,sl:null,enabled:null,contextMenu:null,initialize:function(options){this.initializeItem(options);},initializeItem:function(options){options=options||{};this.sl=[];var label=options.label||'new node';this.data=options.data||null;this.contextMenu=options.contextMenu||null;this.imgNode=options.imgNode||Jx.baseURL+'images/tree_none.png';this.imgIcon=options.imgIcon||Jx.baseURL+'images/tree_page.png';this.domObj=document.createElement('li');this.domObj.className='jxTreeNode';this.currentClassName='jxTreeNode';var elm=document.createElement('img');elm.className='jxTreeNodeImage';Jx.addToImgQueue({domElement:elm,src:this.imgNode});this.domObj.appendChild(elm);elm=document.createElement('img');elm.className='jxTreeNodeIcon';Jx.addToImgQueue({domElement:elm,src:this.imgIcon});this.domObj.appendChild(elm);elm=document.createElement('a');elm.href='javascript:void(0)';elm.onclick=this.selected.bindAsEventListener(this);elm.ondblclick=this.selected.bindAsEventListener(this);elm.oncontextmenu=this.showMenu.bindAsEventListener(this);elm.innerHTML=label;this.domObj.appendChild(elm);this.domObj.jxTreeItem=this;this.domObj.childNodes[2].jxTreeItem=this;this.onClick=options.onClick||null;this.enabled=typeof options.enabled!='undefined'?options.enabled:true;if(this.enabled){Element.removeClassName(this.domObj,'jxDisabled');}else{Element.addClassName(this.domObj,'jxDisabled');}
-var clearer=document.createElement('span');clearer.className='jxClearer';this.domObj.appendChild(clearer);},finalize:function(){this.finalizeItem();},finalizeItem:function(){if(!this.domObj){return;}
-this.domObj.childNodes[2].onclick=null;this.domObj.childNodes[2].ondblclick=null;this.domObj.childNodes[2].oncontextmenu=null;this.contextMenu=null;this.onClick=null;for(var i=this.sl.length;i>=0;i--){this.removeSelectionListener(this.sl[i]);}
-this.parent=null;this.domObj.jxTreeItem=null;this.domObj=null;},clone:function(){var options={label:this.domObj.childNodes[2].innerHTML,data:this.data,onClick:this.onClick,imgNode:this.imgNode,imgIcon:this.imgIcon};var item=new Jx.TreeItem(options);return item;},update:function(shouldDescend){var isLast=(arguments.length>1)?arguments[1]:(this.parent&&this.parent.isLastNode(this));if(isLast){Element.removeClassName(this.domObj,'jxTreeNode');Element.addClassName(this.domObj,'jxTreeNodeLast');}else{Element.removeClassName(this.domObj,'jxTreeNodeLast');Element.addClassName(this.domObj,'jxTreeNode');}},selected:function(e){this.lastEvent=e?e:event;this.processEvent(this.sl,'selectionChanged',this);},showMenu:function(e){this.lastEvent=e?e:event;this.processEvent(this.sl,'selectionChanged',this);if(this.contextMenu){this.contextMenu.show(this.lastEvent);}
-Event.stop(e);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);},getName:function(){return this.domObj.childNodes[2].innerHTML;},setName:function(name){this.domObj.childNodes[2].innerHTML=name;},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj,'jxDisabled');}else{Element.addClassName(this.domObj,'jxDisabled');}}};Object.extend(Jx.TreeItem.prototype,Jx.Listener.prototype);Jx.TreeFolder=Class.create();Object.extend(Jx.TreeFolder.prototype,Jx.TreeItem.prototype);Object.extend(Jx.TreeFolder.prototype,{subDomObj:null,nodes:null,isOpen:false,dl:null,initialize:function(options){this.initializeFolder(options);},initializeFolder:function(options){options=options||{};this.initializeItem(options);this.imgTreePlus=options.imgTreePlus||Jx.baseURL+'images/tree_plus.png';this.imgTreeMinus=options.imgTreeMinus||Jx.baseURL+'images/tree_minus.png';this.imgTreeFolder=options.imgTreeFolder||Jx.baseURL+'images/tree_folder.png';this.imgTreeFolderOpen=options.imgTreeFolderOpen||Jx.baseURL+'images/tree_folder_open.png';Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreePlus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolder});this.domObj.childNodes[0].onclick=this.clicked.bindAsEventListener(this);this.nodes=[];this.subDomObj=document.createElement('ul');this.domObj.appendChild(this.subDomObj);this.subDomObj.className='jxTree';this.isOpen=options.isOpen||false;this.dl=[];if(this.isOpen){this.expand();}else{this.collapse();}},finalize:function(){this.finalizeFolder();this.finalizeItem();this.subDomObj=null;},finalizeFolder:function(){this.domObj.childNodes[0].onclick=null;for(var i=this.nodes.length-1;i>=0;i--){this.nodes[i].finalize();if(this.nodes[i].domObj)this.subDomObj.removeChild(this.nodes[i].domObj);this.nodes.pop();}
-for(var i=this.dl.length-1;i>=0;i--){this.removeDisclosureListener(this.dl[i]);}},clone:function(){var options={label:this.domObj.childNodes[2].innerHTML,data:this.data,onClick:this.onClick,imgTreePlus:this.imgTreePlus,imgTreeMinus:this.imgTreeMinus,imgTreeFolder:this.imgTreeFolder,imgTreeFolderOpen:this.imgTreeFolderOpen};var node=new Jx.TreeFolder(options);for(var i=0;i<this.nodes.length;i++){node.append(this.nodes[i].clone());}
-return node;},isLastNode:function(node){if(this.nodes.length==0){return false;}else{return this.nodes[this.nodes.length-1]==node;}},update:function(bDescend){if(!this.parent)return;var bLast=false;if(arguments.length>1){bLast=arguments[1];}else{bLast=(this.parent&&this.parent.isLastNode(this));}
-if(bLast){this.domObj.className='jxTreeNodeLast';this.subDomObj.className='jxTree';}else{this.domObj.className='jxTreeNode';this.subDomObj.className='jxTree jxTreeNest';}
-if(this.isOpen){Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreeMinus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolderOpen});}else{Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreePlus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolder});}
-if(this.nodes&&bDescend){for(var i=0;i<this.nodes.length;i++){this.nodes[i].update(false,i==this.nodes.length-1);}}},append:function(node){node.parent=this;this.nodes.push(node);this.subDomObj.appendChild(node.domObj);this.update(true);},insert:function(node,refNode){node.parent=this;if(!refNode){this.nodes.unshift(node);if(this.subDomObj.childNodes.length==0){this.subDomObj.appendChild(node.domObj);}else{this.subDomObj.insertBefore(node.domObj,this.subDomObj.childNodes[0]);}}else{var b=false;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==refNode){i=i+1;if(i<this.nodes.length){this.nodes.splice(i,0,node);this.subDomObj.insertBefore(node.domObj,this.subDomObj.childNodes[i]);b=true;break;}}}
-if(!b){this.nodes.push(node);this.subDomObj.appendChild(node.domObj);}}
-this.update(true);},remove:function(node){node.parent=null;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==node){this.nodes.splice(i,1);this.subDomObj.removeChild(this.subDomObj.childNodes[i]);break;}}
-this.update(true);},replace:function(newNode,refNode){var b=false;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==refNode){if(i<this.nodes.length){newNode.parent=this;this.nodes.splice(i,1,newNode);this.subDomObj.replaceChild(newNode.domObj,refNode.domObj);return true;}}}
-return false;},clicked:function(e){e=e?e:event;if(this.isOpen){this.collapse();}else{this.expand();}},expand:function(){this.isOpen=true;this.subDomObj.style.display='block';this.update(true);this.processEvent(this.dl,'disclosed',this);},collapse:function(){this.isOpen=false;this.subDomObj.style.display='none';this.update(true);this.processEvent(this.dl,'disclosed',this);},addDisclosureListener:function(obj){this.addListener(this.dl,obj);},removeDisclosureListener:function(obj){this.removeListener(this.dl,obj);},findChild:function(path){if(path.length==0)
-return this;if(path.length==1)
-{for(var i=0;i<this.nodes.length;i++)
-{if(this.nodes[i].getName()==path[0])
-return this.nodes[i];}
-return null;}
-var childName=path.shift();for(var i=0;i<this.nodes.length;i++)
-{if(this.nodes[i].getName()==childName&&this.nodes[i].findChild)
-return this.nodes[i].findChild(path);}
-return null;}});Jx.Tree=Class.create();Object.extend(Jx.Tree.prototype,Jx.TreeFolder.prototype);Object.extend(Jx.Tree.prototype,{initialize:function(id){this.subDomObj=document.createElement('ul');this.subDomObj.className='jxTreeRoot';$(id).appendChild(this.subDomObj);this.nodes=[];this.dl=[];this.isOpen=true;},finalize:function(){this.clear();this.subDomObj.parentNode.removeChild(this.subDomObj);},clear:function(){for(var i=this.nodes.length-1;i>=0;i--){this.subDomObj.removeChild(this.nodes[i].domObj);this.nodes[i].finalize();this.nodes.pop();}},update:function(shouldDescend){var bLast=true;if(this.subDomObj)
-{if(bLast){Element.removeClassName(this.subDomObj,'jxTreeNest');}else{Element.addClassName(this.subDomObj,'jxTreeNest');}}
-if(this.nodes&&shouldDescend){this.nodes.each(function(n){n.update(false);});}},append:function(node){node.parent=this;this.nodes.push(node);this.subDomObj.appendChild(node.domObj);this.update(true);}});if(Jx.COMBINED_CSS){document.write('<link type="text/css" rel="stylesheet" href="'+Jx.baseURL+'lib/jx_combined.css" />\n');}else{for(var styleSheet in Jx.importRules){var url=Jx.baseURL+styleSheet;document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');}
-document.write('<!--[if IE]>');for(var styleSheet in Jx.importRulesIE){var url=Jx.baseURL+styleSheet;document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');}
-document.write('<![endif]-->\n');}
\ No newline at end of file

Copied: sandbox/aboudreault/jx/lib/jx_compressed.js (from rev 1352, trunk/jx/lib/jx_compressed.js)
===================================================================
--- sandbox/aboudreault/jx/lib/jx_compressed.js	                        (rev 0)
+++ sandbox/aboudreault/jx/lib/jx_compressed.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,639 @@
+
+var Prototype={Version:'1.5.0',BrowserFeatures:{XPath:!!document.evaluate},ScriptFragment:'(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',emptyFunction:function(){},K:function(x){return x}}
+var Class={create:function(){return function(){this.initialize.apply(this,arguments);}}}
+var Abstract=new Object();Object.extend=function(destination,source){for(var property in source){destination[property]=source[property];}
+return destination;}
+Object.extend(Object,{inspect:function(object){try{if(object===undefined)return'undefined';if(object===null)return'null';return object.inspect?object.inspect():object.toString();}catch(e){if(e instanceof RangeError)return'...';throw e;}},keys:function(object){var keys=[];for(var property in object)
+keys.push(property);return keys;},values:function(object){var values=[];for(var property in object)
+values.push(object[property]);return values;},clone:function(object){return Object.extend({},object);}});Function.prototype.bind=function(){var __method=this,args=$A(arguments),object=args.shift();return function(){return __method.apply(object,args.concat($A(arguments)));}}
+Function.prototype.bindAsEventListener=function(object){var __method=this,args=$A(arguments),object=args.shift();return function(event){return __method.apply(object,[(event||window.event)].concat(args).concat($A(arguments)));}}
+Object.extend(Number.prototype,{toColorPart:function(){var digits=this.toString(16);if(this<16)return'0'+digits;return digits;},succ:function(){return this+1;},times:function(iterator){$R(0,this,true).each(iterator);return this;}});var Try={these:function(){var returnValue;for(var i=0,length=arguments.length;i<length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
+return returnValue;}}
+var PeriodicalExecuter=Class.create();PeriodicalExecuter.prototype={initialize:function(callback,frequency){this.callback=callback;this.frequency=frequency;this.currentlyExecuting=false;this.registerCallback();},registerCallback:function(){this.timer=setInterval(this.onTimerEvent.bind(this),this.frequency*1000);},stop:function(){if(!this.timer)return;clearInterval(this.timer);this.timer=null;},onTimerEvent:function(){if(!this.currentlyExecuting){try{this.currentlyExecuting=true;this.callback(this);}finally{this.currentlyExecuting=false;}}}}
+String.interpret=function(value){return value==null?'':String(value);}
+Object.extend(String.prototype,{gsub:function(pattern,replacement){var result='',source=this,match;replacement=arguments.callee.prepareReplacement(replacement);while(source.length>0){if(match=source.match(pattern)){result+=source.slice(0,match.index);result+=String.interpret(replacement(match));source=source.slice(match.index+match[0].length);}else{result+=source,source='';}}
+return result;},sub:function(pattern,replacement,count){replacement=this.gsub.prepareReplacement(replacement);count=count===undefined?1:count;return this.gsub(pattern,function(match){if(--count<0)return match[0];return replacement(match);});},scan:function(pattern,iterator){this.gsub(pattern,iterator);return this;},truncate:function(length,truncation){length=length||30;truncation=truncation===undefined?'...':truncation;return this.length>length?this.slice(0,length-truncation.length)+truncation:this;},strip:function(){return this.replace(/^\s+/,'').replace(/\s+$/,'');},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,'');},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,'img'),'');},extractScripts:function(){var matchAll=new RegExp(Prototype.ScriptFragment,'img');var matchOne=new RegExp(Prototype.ScriptFragment,'im');return(this.match(matchAll)||[]).map(function(scriptTag){return(scriptTag.match(matchOne)||['',''])[1];});},evalScripts:function(){return this.extractScripts().map(function(script){return eval(script)});},escapeHTML:function(){var div=document.createElement('div');var text=document.createTextNode(this);div.appendChild(text);return div.innerHTML;},unescapeHTML:function(){var div=document.createElement('div');div.innerHTML=this.stripTags();return div.childNodes[0]?(div.childNodes.length>1?$A(div.childNodes).inject('',function(memo,node){return memo+node.nodeValue}):div.childNodes[0].nodeValue):'';},toQueryParams:function(separator){var match=this.strip().match(/([^?#]*)(#.*)?$/);if(!match)return{};return match[1].split(separator||'&').inject({},function(hash,pair){if((pair=pair.split('='))[0]){var name=decodeURIComponent(pair[0]);var value=pair[1]?decodeURIComponent(pair[1]):undefined;if(hash[name]!==undefined){if(hash[name].constructor!=Array)
+hash[name]=[hash[name]];if(value)hash[name].push(value);}
+else hash[name]=value;}
+return hash;});},toArray:function(){return this.split('');},succ:function(){return this.slice(0,this.length-1)+
+String.fromCharCode(this.charCodeAt(this.length-1)+1);},camelize:function(){var parts=this.split('-'),len=parts.length;if(len==1)return parts[0];var camelized=this.charAt(0)=='-'?parts[0].charAt(0).toUpperCase()+parts[0].substring(1):parts[0];for(var i=1;i<len;i++)
+camelized+=parts[i].charAt(0).toUpperCase()+parts[i].substring(1);return camelized;},capitalize:function(){return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase();},underscore:function(){return this.gsub(/::/,'/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();},dasherize:function(){return this.gsub(/_/,'-');},inspect:function(useDoubleQuotes){var escapedString=this.replace(/\\/g,'\\\\');if(useDoubleQuotes)
+return'"'+escapedString.replace(/"/g,'\\"')+'"';else
+return"'"+escapedString.replace(/'/g,'\\\'')+"'";}});String.prototype.gsub.prepareReplacement=function(replacement){if(typeof replacement=='function')return replacement;var template=new Template(replacement);return function(match){return template.evaluate(match)};}
+String.prototype.parseQuery=String.prototype.toQueryParams;var Template=Class.create();Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;Template.prototype={initialize:function(template,pattern){this.template=template.toString();this.pattern=pattern||Template.Pattern;},evaluate:function(object){return this.template.gsub(this.pattern,function(match){var before=match[1];if(before=='\\')return match[2];return before+String.interpret(object[match[3]]);});}}
+var $break=new Object();var $continue=new Object();var Enumerable={each:function(iterator){var index=0;try{this._each(function(value){try{iterator(value,index++);}catch(e){if(e!=$continue)throw e;}});}catch(e){if(e!=$break)throw e;}
+return this;},eachSlice:function(number,iterator){var index=-number,slices=[],array=this.toArray();while((index+=number)<array.length)
+slices.push(array.slice(index,index+number));return slices.map(iterator);},all:function(iterator){var result=true;this.each(function(value,index){result=result&&!!(iterator||Prototype.K)(value,index);if(!result)throw $break;});return result;},any:function(iterator){var result=false;this.each(function(value,index){if(result=!!(iterator||Prototype.K)(value,index))
+throw $break;});return result;},collect:function(iterator){var results=[];this.each(function(value,index){results.push((iterator||Prototype.K)(value,index));});return results;},detect:function(iterator){var result;this.each(function(value,index){if(iterator(value,index)){result=value;throw $break;}});return result;},findAll:function(iterator){var results=[];this.each(function(value,index){if(iterator(value,index))
+results.push(value);});return results;},grep:function(pattern,iterator){var results=[];this.each(function(value,index){var stringValue=value.toString();if(stringValue.match(pattern))
+results.push((iterator||Prototype.K)(value,index));})
+return results;},include:function(object){var found=false;this.each(function(value){if(value==object){found=true;throw $break;}});return found;},inGroupsOf:function(number,fillWith){fillWith=fillWith===undefined?null:fillWith;return this.eachSlice(number,function(slice){while(slice.length<number)slice.push(fillWith);return slice;});},inject:function(memo,iterator){this.each(function(value,index){memo=iterator(memo,value,index);});return memo;},invoke:function(method){var args=$A(arguments).slice(1);return this.map(function(value){return value[method].apply(value,args);});},max:function(iterator){var result;this.each(function(value,index){value=(iterator||Prototype.K)(value,index);if(result==undefined||value>=result)
+result=value;});return result;},min:function(iterator){var result;this.each(function(value,index){value=(iterator||Prototype.K)(value,index);if(result==undefined||value<result)
+result=value;});return result;},partition:function(iterator){var trues=[],falses=[];this.each(function(value,index){((iterator||Prototype.K)(value,index)?trues:falses).push(value);});return[trues,falses];},pluck:function(property){var results=[];this.each(function(value,index){results.push(value[property]);});return results;},reject:function(iterator){var results=[];this.each(function(value,index){if(!iterator(value,index))
+results.push(value);});return results;},sortBy:function(iterator){return this.map(function(value,index){return{value:value,criteria:iterator(value,index)};}).sort(function(left,right){var a=left.criteria,b=right.criteria;return a<b?-1:a>b?1:0;}).pluck('value');},toArray:function(){return this.map();},zip:function(){var iterator=Prototype.K,args=$A(arguments);if(typeof args.last()=='function')
+iterator=args.pop();var collections=[this].concat(args).map($A);return this.map(function(value,index){return iterator(collections.pluck(index));});},size:function(){return this.toArray().length;},inspect:function(){return'#<Enumerable:'+this.toArray().inspect()+'>';}}
+Object.extend(Enumerable,{map:Enumerable.collect,find:Enumerable.detect,select:Enumerable.findAll,member:Enumerable.include,entries:Enumerable.toArray});var $A=Array.from=function(iterable){if(!iterable)return[];if(iterable.toArray){return iterable.toArray();}else{var results=[];for(var i=0,length=iterable.length;i<length;i++)
+results.push(iterable[i]);return results;}}
+Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse)
+Array.prototype._reverse=Array.prototype.reverse;Object.extend(Array.prototype,{_each:function(iterator){for(var i=0,length=this.length;i<length;i++)
+iterator(this[i]);},clear:function(){this.length=0;return this;},first:function(){return this[0];},last:function(){return this[this.length-1];},compact:function(){return this.select(function(value){return value!=null;});},flatten:function(){return this.inject([],function(array,value){return array.concat(value&&value.constructor==Array?value.flatten():[value]);});},without:function(){var values=$A(arguments);return this.select(function(value){return!values.include(value);});},indexOf:function(object){for(var i=0,length=this.length;i<length;i++)
+if(this[i]==object)return i;return-1;},reverse:function(inline){return(inline!==false?this:this.toArray())._reverse();},reduce:function(){return this.length>1?this:this[0];},uniq:function(){return this.inject([],function(array,value){return array.include(value)?array:array.concat([value]);});},clone:function(){return[].concat(this);},size:function(){return this.length;},inspect:function(){return'['+this.map(Object.inspect).join(', ')+']';}});Array.prototype.toArray=Array.prototype.clone;function $w(string){string=string.strip();return string?string.split(/\s+/):[];}
+if(window.opera){Array.prototype.concat=function(){var array=[];for(var i=0,length=this.length;i<length;i++)array.push(this[i]);for(var i=0,length=arguments.length;i<length;i++){if(arguments[i].constructor==Array){for(var j=0,arrayLength=arguments[i].length;j<arrayLength;j++)
+array.push(arguments[i][j]);}else{array.push(arguments[i]);}}
+return array;}}
+var Hash=function(obj){Object.extend(this,obj||{});};Object.extend(Hash,{toQueryString:function(obj){var parts=[];this.prototype._each.call(obj,function(pair){if(!pair.key)return;if(pair.value&&pair.value.constructor==Array){var values=pair.value.compact();if(values.length<2)pair.value=values.reduce();else{key=encodeURIComponent(pair.key);values.each(function(value){value=value!=undefined?encodeURIComponent(value):'';parts.push(key+'='+encodeURIComponent(value));});return;}}
+if(pair.value==undefined)pair[1]='';parts.push(pair.map(encodeURIComponent).join('='));});return parts.join('&');}});Object.extend(Hash.prototype,Enumerable);Object.extend(Hash.prototype,{_each:function(iterator){for(var key in this){var value=this[key];if(value&&value==Hash.prototype[key])continue;var pair=[key,value];pair.key=key;pair.value=value;iterator(pair);}},keys:function(){return this.pluck('key');},values:function(){return this.pluck('value');},merge:function(hash){return $H(hash).inject(this,function(mergedHash,pair){mergedHash[pair.key]=pair.value;return mergedHash;});},remove:function(){var result;for(var i=0,length=arguments.length;i<length;i++){var value=this[arguments[i]];if(value!==undefined){if(result===undefined)result=value;else{if(result.constructor!=Array)result=[result];result.push(value)}}
+delete this[arguments[i]];}
+return result;},toQueryString:function(){return Hash.toQueryString(this);},inspect:function(){return'#<Hash:{'+this.map(function(pair){return pair.map(Object.inspect).join(': ');}).join(', ')+'}>';}});function $H(object){if(object&&object.constructor==Hash)return object;return new Hash(object);};ObjectRange=Class.create();Object.extend(ObjectRange.prototype,Enumerable);Object.extend(ObjectRange.prototype,{initialize:function(start,end,exclusive){this.start=start;this.end=end;this.exclusive=exclusive;},_each:function(iterator){var value=this.start;while(this.include(value)){iterator(value);value=value.succ();}},include:function(value){if(value<this.start)
+return false;if(this.exclusive)
+return value<this.end;return value<=this.end;}});var $R=function(start,end,exclusive){return new ObjectRange(start,end,exclusive);}
+var Ajax={getTransport:function(){return Try.these(function(){return new XMLHttpRequest()},function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')})||false;},activeRequestCount:0}
+Ajax.Responders={responders:[],_each:function(iterator){this.responders._each(iterator);},register:function(responder){if(!this.include(responder))
+this.responders.push(responder);},unregister:function(responder){this.responders=this.responders.without(responder);},dispatch:function(callback,request,transport,json){this.each(function(responder){if(typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}});}};Object.extend(Ajax.Responders,Enumerable);Ajax.Responders.register({onCreate:function(){Ajax.activeRequestCount++;},onComplete:function(){Ajax.activeRequestCount--;}});Ajax.Base=function(){};Ajax.Base.prototype={setOptions:function(options){this.options={method:'post',asynchronous:true,contentType:'application/x-www-form-urlencoded',encoding:'UTF-8',parameters:''}
+Object.extend(this.options,options||{});this.options.method=this.options.method.toLowerCase();if(typeof this.options.parameters=='string')
+this.options.parameters=this.options.parameters.toQueryParams();}}
+Ajax.Request=Class.create();Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];Ajax.Request.prototype=Object.extend(new Ajax.Base(),{_complete:false,initialize:function(url,options){this.transport=Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){this.url=url;this.method=this.options.method;var params=this.options.parameters;if(!['get','post'].include(this.method)){params['_method']=this.method;this.method='post';}
+params=Hash.toQueryString(params);if(params&&/Konqueror|Safari|KHTML/.test(navigator.userAgent))params+='&_='
+if(this.method=='get'&&params)
+this.url+=(this.url.indexOf('?')>-1?'&':'?')+params;try{Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous)
+setTimeout(function(){this.respondToReadyState(1)}.bind(this),10);this.transport.onreadystatechange=this.onStateChange.bind(this);this.setRequestHeaders();var body=this.method=='post'?(this.options.postBody||params):null;this.transport.send(body);if(!this.options.asynchronous&&this.transport.overrideMimeType)
+this.onStateChange();}
+catch(e){this.dispatchException(e);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState>1&&!((readyState==4)&&this._complete))
+this.respondToReadyState(this.transport.readyState);},setRequestHeaders:function(){var headers={'X-Requested-With':'XMLHttpRequest','X-Prototype-Version':Prototype.Version,'Accept':'text/javascript, text/html, application/xml, text/xml, */*'};if(this.method=='post'){headers['Content-type']=this.options.contentType+
+(this.options.encoding?'; charset='+this.options.encoding:'');if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005)
+headers['Connection']='close';}
+if(typeof this.options.requestHeaders=='object'){var extras=this.options.requestHeaders;if(typeof extras.push=='function')
+for(var i=0,length=extras.length;i<length;i+=2)
+headers[extras[i]]=extras[i+1];else
+$H(extras).each(function(pair){headers[pair.key]=pair.value});}
+for(var name in headers)
+this.transport.setRequestHeader(name,headers[name]);},success:function(){return!this.transport.status||(this.transport.status>=200&&this.transport.status<300);},respondToReadyState:function(readyState){var state=Ajax.Request.Events[readyState];var transport=this.transport,json=this.evalJSON();if(state=='Complete'){try{this._complete=true;(this.options['on'+this.transport.status]||this.options['on'+(this.success()?'Success':'Failure')]||Prototype.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);}
+if((this.getHeader('Content-type')||'text/javascript').strip().match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+this.evalResponse();}
+try{(this.options['on'+state]||Prototype.emptyFunction)(transport,json);Ajax.Responders.dispatch('on'+state,this,transport,json);}catch(e){this.dispatchException(e);}
+if(state=='Complete'){this.transport.onreadystatechange=Prototype.emptyFunction;}},getHeader:function(name){try{return this.transport.getResponseHeader(name);}catch(e){return null}},evalJSON:function(){try{var json=this.getHeader('X-JSON');return json?eval('('+json+')'):null;}catch(e){return null}},evalResponse:function(){try{return eval(this.transport.responseText);}catch(e){this.dispatchException(e);}},dispatchException:function(exception){(this.options.onException||Prototype.emptyFunction)(this,exception);Ajax.Responders.dispatch('onException',this,exception);}});Ajax.Updater=Class.create();Object.extend(Object.extend(Ajax.Updater.prototype,Ajax.Request.prototype),{initialize:function(container,url,options){this.container={success:(container.success||container),failure:(container.failure||(container.success?null:container))}
+this.transport=Ajax.getTransport();this.setOptions(options);var onComplete=this.options.onComplete||Prototype.emptyFunction;this.options.onComplete=(function(transport,param){this.updateContent();onComplete(transport,param);}).bind(this);this.request(url);},updateContent:function(){var receiver=this.container[this.success()?'success':'failure'];var response=this.transport.responseText;if(!this.options.evalScripts)response=response.stripScripts();if(receiver=$(receiver)){if(this.options.insertion)
+new this.options.insertion(receiver,response);else
+receiver.update(response);}
+if(this.success()){if(this.onComplete)
+setTimeout(this.onComplete.bind(this),10);}}});Ajax.PeriodicalUpdater=Class.create();Ajax.PeriodicalUpdater.prototype=Object.extend(new Ajax.Base(),{initialize:function(container,url,options){this.setOptions(options);this.onComplete=this.options.onComplete;this.frequency=(this.options.frequency||2);this.decay=(this.options.decay||1);this.updater={};this.container=container;this.url=url;this.start();},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent();},stop:function(){this.updater.options.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,arguments);},updateComplete:function(request){if(this.options.decay){this.decay=(request.responseText==this.lastText?this.decay*this.options.decay:1);this.lastText=request.responseText;}
+this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1000);},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options);}});function $(element){if(arguments.length>1){for(var i=0,elements=[],length=arguments.length;i<length;i++)
+elements.push($(arguments[i]));return elements;}
+if(typeof element=='string')
+element=document.getElementById(element);return Element.extend(element);}
+if(Prototype.BrowserFeatures.XPath){document._getElementsByXPath=function(expression,parentElement){var results=[];var query=document.evaluate(expression,$(parentElement)||document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);for(var i=0,length=query.snapshotLength;i<length;i++)
+results.push(query.snapshotItem(i));return results;};}
+document.getElementsByClassName=function(className,parentElement){if(Prototype.BrowserFeatures.XPath){var q=".//*[contains(concat(' ', @class, ' '), ' "+className+" ')]";return document._getElementsByXPath(q,parentElement);}else{var children=($(parentElement)||document.body).getElementsByTagName('*');var elements=[],child;for(var i=0,length=children.length;i<length;i++){child=children[i];if(Element.hasClassName(child,className))
+elements.push(Element.extend(child));}
+return elements;}};if(!window.Element)
+var Element=new Object();Element.extend=function(element){if(!element||_nativeExtensions||element.nodeType==3)return element;if(!element._extended&&element.tagName&&element!=window){var methods=Object.clone(Element.Methods),cache=Element.extend.cache;if(element.tagName=='FORM')
+Object.extend(methods,Form.Methods);if(['INPUT','TEXTAREA','SELECT'].include(element.tagName))
+Object.extend(methods,Form.Element.Methods);Object.extend(methods,Element.Methods.Simulated);for(var property in methods){var value=methods[property];if(typeof value=='function'&&!(property in element))
+element[property]=cache.findOrStore(value);}}
+element._extended=true;return element;};Element.extend.cache={findOrStore:function(value){return this[value]=this[value]||function(){return value.apply(null,[this].concat($A(arguments)));}}};Element.Methods={visible:function(element){return $(element).style.display!='none';},toggle:function(element){element=$(element);Element[Element.visible(element)?'hide':'show'](element);return element;},hide:function(element){$(element).style.display='none';return element;},show:function(element){$(element).style.display='';return element;},remove:function(element){element=$(element);element.parentNode.removeChild(element);return element;},update:function(element,html){html=typeof html=='undefined'?'':html.toString();$(element).innerHTML=html.stripScripts();setTimeout(function(){html.evalScripts()},10);return element;},replace:function(element,html){element=$(element);html=typeof html=='undefined'?'':html.toString();if(element.outerHTML){element.outerHTML=html.stripScripts();}else{var range=element.ownerDocument.createRange();range.selectNodeContents(element);element.parentNode.replaceChild(range.createContextualFragment(html.stripScripts()),element);}
+setTimeout(function(){html.evalScripts()},10);return element;},inspect:function(element){element=$(element);var result='<'+element.tagName.toLowerCase();$H({'id':'id','className':'class'}).each(function(pair){var property=pair.first(),attribute=pair.last();var value=(element[property]||'').toString();if(value)result+=' '+attribute+'='+value.inspect(true);});return result+'>';},recursivelyCollect:function(element,property){element=$(element);var elements=[];while(element=element[property])
+if(element.nodeType==1)
+elements.push(Element.extend(element));return elements;},ancestors:function(element){return $(element).recursivelyCollect('parentNode');},descendants:function(element){return $A($(element).getElementsByTagName('*'));},immediateDescendants:function(element){if(!(element=$(element).firstChild))return[];while(element&&element.nodeType!=1)element=element.nextSibling;if(element)return[element].concat($(element).nextSiblings());return[];},previousSiblings:function(element){return $(element).recursivelyCollect('previousSibling');},nextSiblings:function(element){return $(element).recursivelyCollect('nextSibling');},siblings:function(element){element=$(element);return element.previousSiblings().reverse().concat(element.nextSiblings());},match:function(element,selector){if(typeof selector=='string')
+selector=new Selector(selector);return selector.match($(element));},up:function(element,expression,index){return Selector.findElement($(element).ancestors(),expression,index);},down:function(element,expression,index){return Selector.findElement($(element).descendants(),expression,index);},previous:function(element,expression,index){return Selector.findElement($(element).previousSiblings(),expression,index);},next:function(element,expression,index){return Selector.findElement($(element).nextSiblings(),expression,index);},getElementsBySelector:function(){var args=$A(arguments),element=$(args.shift());return Selector.findChildElements(element,args);},getElementsByClassName:function(element,className){return document.getElementsByClassName(className,element);},readAttribute:function(element,name){element=$(element);if(document.all&&!window.opera){var t=Element._attributeTranslations;if(t.values[name])return t.values[name](element,name);if(t.names[name])name=t.names[name];var attribute=element.attributes[name];if(attribute)return attribute.nodeValue;}
+return element.getAttribute(name);},getHeight:function(element){return $(element).getDimensions().height;},getWidth:function(element){return $(element).getDimensions().width;},classNames:function(element){return new Element.ClassNames(element);},hasClassName:function(element,className){if(!(element=$(element)))return;var elementClassName=element.className;if(elementClassName.length==0)return false;if(elementClassName==className||elementClassName.match(new RegExp("(^|\\s)"+className+"(\\s|$)")))
+return true;return false;},addClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element).add(className);return element;},removeClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element).remove(className);return element;},toggleClassName:function(element,className){if(!(element=$(element)))return;Element.classNames(element)[element.hasClassName(className)?'remove':'add'](className);return element;},observe:function(){Event.observe.apply(Event,arguments);return $A(arguments).first();},stopObserving:function(){Event.stopObserving.apply(Event,arguments);return $A(arguments).first();},cleanWhitespace:function(element){element=$(element);var node=element.firstChild;while(node){var nextNode=node.nextSibling;if(node.nodeType==3&&!/\S/.test(node.nodeValue))
+element.removeChild(node);node=nextNode;}
+return element;},empty:function(element){return $(element).innerHTML.match(/^\s*$/);},descendantOf:function(element,ancestor){element=$(element),ancestor=$(ancestor);while(element=element.parentNode)
+if(element==ancestor)return true;return false;},scrollTo:function(element){element=$(element);var pos=Position.cumulativeOffset(element);window.scrollTo(pos[0],pos[1]);return element;},getStyle:function(element,style){element=$(element);if(['float','cssFloat'].include(style))
+style=(typeof element.style.styleFloat!='undefined'?'styleFloat':'cssFloat');style=style.camelize();var value=element.style[style];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css[style]:null;}else if(element.currentStyle){value=element.currentStyle[style];}}
+if((value=='auto')&&['width','height'].include(style)&&(element.getStyle('display')!='none'))
+value=element['offset'+style.capitalize()]+'px';if(window.opera&&['left','top','right','bottom'].include(style))
+if(Element.getStyle(element,'position')=='static')value='auto';if(style=='opacity'){if(value)return parseFloat(value);if(value=(element.getStyle('filter')||'').match(/alpha\(opacity=(.*)\)/))
+if(value[1])return parseFloat(value[1])/100;return 1.0;}
+return value=='auto'?null:value;},setStyle:function(element,style){element=$(element);for(var name in style){var value=style[name];if(name=='opacity'){if(value==1){value=(/Gecko/.test(navigator.userAgent)&&!/Konqueror|Safari|KHTML/.test(navigator.userAgent))?0.999999:1.0;if(/MSIE/.test(navigator.userAgent)&&!window.opera)
+element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');}else if(value===''){if(/MSIE/.test(navigator.userAgent)&&!window.opera)
+element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');}else{if(value<0.00001)value=0;if(/MSIE/.test(navigator.userAgent)&&!window.opera)
+element.style.filter=element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'')+'alpha(opacity='+value*100+')';}}else if(['float','cssFloat'].include(name))name=(typeof element.style.styleFloat!='undefined')?'styleFloat':'cssFloat';element.style[name.camelize()]=value;}
+return element;},getDimensions:function(element){element=$(element);var display=$(element).getStyle('display');if(display!='none'&&display!=null)
+return{width:element.offsetWidth,height:element.offsetHeight};var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;var originalDisplay=els.display;els.visibility='hidden';els.position='absolute';els.display='block';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display=originalDisplay;els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},makePositioned:function(element){element=$(element);var pos=Element.getStyle(element,'position');if(pos=='static'||!pos){element._madePositioned=true;element.style.position='relative';if(window.opera){element.style.top=0;element.style.left=0;}}
+return element;},undoPositioned:function(element){element=$(element);if(element._madePositioned){element._madePositioned=undefined;element.style.position=element.style.top=element.style.left=element.style.bottom=element.style.right='';}
+return element;},makeClipping:function(element){element=$(element);if(element._overflow)return element;element._overflow=element.style.overflow||'auto';if((Element.getStyle(element,'overflow')||'visible')!='hidden')
+element.style.overflow='hidden';return element;},undoClipping:function(element){element=$(element);if(!element._overflow)return element;element.style.overflow=element._overflow=='auto'?'':element._overflow;element._overflow=null;return element;}};Object.extend(Element.Methods,{childOf:Element.Methods.descendantOf});Element._attributeTranslations={};Element._attributeTranslations.names={colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",datetime:"dateTime",accesskey:"accessKey",tabindex:"tabIndex",enctype:"encType",maxlength:"maxLength",readonly:"readOnly",longdesc:"longDesc"};Element._attributeTranslations.values={_getAttr:function(element,attribute){return element.getAttribute(attribute,2);},_flag:function(element,attribute){return $(element).hasAttribute(attribute)?attribute:null;},style:function(element){return element.style.cssText.toLowerCase();},title:function(element){var node=element.getAttributeNode('title');return node.specified?node.nodeValue:null;}};Object.extend(Element._attributeTranslations.values,{href:Element._attributeTranslations.values._getAttr,src:Element._attributeTranslations.values._getAttr,disabled:Element._attributeTranslations.values._flag,checked:Element._attributeTranslations.values._flag,readonly:Element._attributeTranslations.values._flag,multiple:Element._attributeTranslations.values._flag});Element.Methods.Simulated={hasAttribute:function(element,attribute){var t=Element._attributeTranslations;attribute=t.names[attribute]||attribute;return $(element).getAttributeNode(attribute).specified;}};if(document.all&&!window.opera){Element.Methods.update=function(element,html){element=$(element);html=typeof html=='undefined'?'':html.toString();var tagName=element.tagName.toUpperCase();if(['THEAD','TBODY','TR','TD'].include(tagName)){var div=document.createElement('div');switch(tagName){case'THEAD':case'TBODY':div.innerHTML='<table><tbody>'+html.stripScripts()+'</tbody></table>';depth=2;break;case'TR':div.innerHTML='<table><tbody><tr>'+html.stripScripts()+'</tr></tbody></table>';depth=3;break;case'TD':div.innerHTML='<table><tbody><tr><td>'+html.stripScripts()+'</td></tr></tbody></table>';depth=4;}
+$A(element.childNodes).each(function(node){element.removeChild(node)});depth.times(function(){div=div.firstChild});$A(div.childNodes).each(function(node){element.appendChild(node)});}else{element.innerHTML=html.stripScripts();}
+setTimeout(function(){html.evalScripts()},10);return element;}};Object.extend(Element,Element.Methods);var _nativeExtensions=false;if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+['','Form','Input','TextArea','Select'].each(function(tag){var className='HTML'+tag+'Element';if(window[className])return;var klass=window[className]={};klass.prototype=document.createElement(tag?tag.toLowerCase():'div').__proto__;});Element.addMethods=function(methods){Object.extend(Element.Methods,methods||{});function copy(methods,destination,onlyIfAbsent){onlyIfAbsent=onlyIfAbsent||false;var cache=Element.extend.cache;for(var property in methods){var value=methods[property];if(!onlyIfAbsent||!(property in destination))
+destination[property]=cache.findOrStore(value);}}
+if(typeof HTMLElement!='undefined'){copy(Element.Methods,HTMLElement.prototype);copy(Element.Methods.Simulated,HTMLElement.prototype,true);copy(Form.Methods,HTMLFormElement.prototype);[HTMLInputElement,HTMLTextAreaElement,HTMLSelectElement].each(function(klass){copy(Form.Element.Methods,klass.prototype);});_nativeExtensions=true;}}
+var Toggle=new Object();Toggle.display=Element.toggle;Abstract.Insertion=function(adjacency){this.adjacency=adjacency;}
+Abstract.Insertion.prototype={initialize:function(element,content){this.element=$(element);this.content=content.stripScripts();if(this.adjacency&&this.element.insertAdjacentHTML){try{this.element.insertAdjacentHTML(this.adjacency,this.content);}catch(e){var tagName=this.element.tagName.toUpperCase();if(['TBODY','TR'].include(tagName)){this.insertContent(this.contentFromAnonymousTable());}else{throw e;}}}else{this.range=this.element.ownerDocument.createRange();if(this.initializeRange)this.initializeRange();this.insertContent([this.range.createContextualFragment(this.content)]);}
+setTimeout(function(){content.evalScripts()},10);},contentFromAnonymousTable:function(){var div=document.createElement('div');div.innerHTML='<table><tbody>'+this.content+'</tbody></table>';return $A(div.childNodes[0].childNodes[0].childNodes);}}
+var Insertion=new Object();Insertion.Before=Class.create();Insertion.Before.prototype=Object.extend(new Abstract.Insertion('beforeBegin'),{initializeRange:function(){this.range.setStartBefore(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.parentNode.insertBefore(fragment,this.element);}).bind(this));}});Insertion.Top=Class.create();Insertion.Top.prototype=Object.extend(new Abstract.Insertion('afterBegin'),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(true);},insertContent:function(fragments){fragments.reverse(false).each((function(fragment){this.element.insertBefore(fragment,this.element.firstChild);}).bind(this));}});Insertion.Bottom=Class.create();Insertion.Bottom.prototype=Object.extend(new Abstract.Insertion('beforeEnd'),{initializeRange:function(){this.range.selectNodeContents(this.element);this.range.collapse(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.appendChild(fragment);}).bind(this));}});Insertion.After=Class.create();Insertion.After.prototype=Object.extend(new Abstract.Insertion('afterEnd'),{initializeRange:function(){this.range.setStartAfter(this.element);},insertContent:function(fragments){fragments.each((function(fragment){this.element.parentNode.insertBefore(fragment,this.element.nextSibling);}).bind(this));}});Element.ClassNames=Class.create();Element.ClassNames.prototype={initialize:function(element){this.element=$(element);},_each:function(iterator){this.element.className.split(/\s+/).select(function(name){return name.length>0;})._each(iterator);},set:function(className){this.element.className=className;},add:function(classNameToAdd){if(this.include(classNameToAdd))return;this.set($A(this).concat(classNameToAdd).join(' '));},remove:function(classNameToRemove){if(!this.include(classNameToRemove))return;this.set($A(this).without(classNameToRemove).join(' '));},toString:function(){return $A(this).join(' ');}};Object.extend(Element.ClassNames.prototype,Enumerable);var Selector=Class.create();Selector.prototype={initialize:function(expression){this.params={classNames:[]};this.expression=expression.toString().strip();this.parseExpression();this.compileMatcher();},parseExpression:function(){function abort(message){throw'Parse error in selector: '+message;}
+if(this.expression=='')abort('empty expression');var params=this.params,expr=this.expression,match,modifier,clause,rest;while(match=expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)){params.attributes=params.attributes||[];params.attributes.push({name:match[2],operator:match[3],value:match[4]||match[5]||''});expr=match[1];}
+if(expr=='*')return this.params.wildcard=true;while(match=expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)){modifier=match[1],clause=match[2],rest=match[3];switch(modifier){case'#':params.id=clause;break;case'.':params.classNames.push(clause);break;case'':case undefined:params.tagName=clause.toUpperCase();break;default:abort(expr.inspect());}
+expr=rest;}
+if(expr.length>0)abort(expr.inspect());},buildMatchExpression:function(){var params=this.params,conditions=[],clause;if(params.wildcard)
+conditions.push('true');if(clause=params.id)
+conditions.push('element.readAttribute("id") == '+clause.inspect());if(clause=params.tagName)
+conditions.push('element.tagName.toUpperCase() == '+clause.inspect());if((clause=params.classNames).length>0)
+for(var i=0,length=clause.length;i<length;i++)
+conditions.push('element.hasClassName('+clause[i].inspect()+')');if(clause=params.attributes){clause.each(function(attribute){var value='element.readAttribute('+attribute.name.inspect()+')';var splitValueBy=function(delimiter){return value+' && '+value+'.split('+delimiter.inspect()+')';}
+switch(attribute.operator){case'=':conditions.push(value+' == '+attribute.value.inspect());break;case'~=':conditions.push(splitValueBy(' ')+'.include('+attribute.value.inspect()+')');break;case'|=':conditions.push(splitValueBy('-')+'.first().toUpperCase() == '+attribute.value.toUpperCase().inspect());break;case'!=':conditions.push(value+' != '+attribute.value.inspect());break;case'':case undefined:conditions.push('element.hasAttribute('+attribute.name.inspect()+')');break;default:throw'Unknown operator '+attribute.operator+' in selector';}});}
+return conditions.join(' && ');},compileMatcher:function(){this.match=new Function('element','if (!element.tagName) return false; element = $(element); return '+this.buildMatchExpression());},findElements:function(scope){var element;if(element=$(this.params.id))
+if(this.match(element))
+if(!scope||Element.childOf(element,scope))
+return[element];scope=(scope||document).getElementsByTagName(this.params.tagName||'*');var results=[];for(var i=0,length=scope.length;i<length;i++)
+if(this.match(element=scope[i]))
+results.push(Element.extend(element));return results;},toString:function(){return this.expression;}}
+Object.extend(Selector,{matchElements:function(elements,expression){var selector=new Selector(expression);return elements.select(selector.match.bind(selector)).map(Element.extend);},findElement:function(elements,expression,index){if(typeof expression=='number')index=expression,expression=false;return Selector.matchElements(elements,expression||'*')[index||0];},findChildElements:function(element,expressions){return expressions.map(function(expression){return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null],function(results,expr){var selector=new Selector(expr);return results.inject([],function(elements,result){return elements.concat(selector.findElements(result||element));});});}).flatten();}});function $$(){return Selector.findChildElements(document,$A(arguments));}
+var Form={reset:function(form){$(form).reset();return form;},serializeElements:function(elements,getHash){var data=elements.inject({},function(result,element){if(!element.disabled&&element.name){var key=element.name,value=$(element).getValue();if(value!=undefined){if(result[key]){if(result[key].constructor!=Array)result[key]=[result[key]];result[key].push(value);}
+else result[key]=value;}}
+return result;});return getHash?data:Hash.toQueryString(data);}};Form.Methods={serialize:function(form,getHash){return Form.serializeElements(Form.getElements(form),getHash);},getElements:function(form){return $A($(form).getElementsByTagName('*')).inject([],function(elements,child){if(Form.Element.Serializers[child.tagName.toLowerCase()])
+elements.push(Element.extend(child));return elements;});},getInputs:function(form,typeName,name){form=$(form);var inputs=form.getElementsByTagName('input');if(!typeName&&!name)return $A(inputs).map(Element.extend);for(var i=0,matchingInputs=[],length=inputs.length;i<length;i++){var input=inputs[i];if((typeName&&input.type!=typeName)||(name&&input.name!=name))
+continue;matchingInputs.push(Element.extend(input));}
+return matchingInputs;},disable:function(form){form=$(form);form.getElements().each(function(element){element.blur();element.disabled='true';});return form;},enable:function(form){form=$(form);form.getElements().each(function(element){element.disabled='';});return form;},findFirstElement:function(form){return $(form).getElements().find(function(element){return element.type!='hidden'&&!element.disabled&&['input','select','textarea'].include(element.tagName.toLowerCase());});},focusFirstElement:function(form){form=$(form);form.findFirstElement().activate();return form;}}
+Object.extend(Form,Form.Methods);Form.Element={focus:function(element){$(element).focus();return element;},select:function(element){$(element).select();return element;}}
+Form.Element.Methods={serialize:function(element){element=$(element);if(!element.disabled&&element.name){var value=element.getValue();if(value!=undefined){var pair={};pair[element.name]=value;return Hash.toQueryString(pair);}}
+return'';},getValue:function(element){element=$(element);var method=element.tagName.toLowerCase();return Form.Element.Serializers[method](element);},clear:function(element){$(element).value='';return element;},present:function(element){return $(element).value!='';},activate:function(element){element=$(element);element.focus();if(element.select&&(element.tagName.toLowerCase()!='input'||!['button','reset','submit'].include(element.type)))
+element.select();return element;},disable:function(element){element=$(element);element.disabled=true;return element;},enable:function(element){element=$(element);element.blur();element.disabled=false;return element;}}
+Object.extend(Form.Element,Form.Element.Methods);var Field=Form.Element;var $F=Form.Element.getValue;Form.Element.Serializers={input:function(element){switch(element.type.toLowerCase()){case'checkbox':case'radio':return Form.Element.Serializers.inputSelector(element);default:return Form.Element.Serializers.textarea(element);}},inputSelector:function(element){return element.checked?element.value:null;},textarea:function(element){return element.value;},select:function(element){return this[element.type=='select-one'?'selectOne':'selectMany'](element);},selectOne:function(element){var index=element.selectedIndex;return index>=0?this.optionValue(element.options[index]):null;},selectMany:function(element){var values,length=element.length;if(!length)return null;for(var i=0,values=[];i<length;i++){var opt=element.options[i];if(opt.selected)values.push(this.optionValue(opt));}
+return values;},optionValue:function(opt){return Element.extend(opt).hasAttribute('value')?opt.value:opt.text;}}
+Abstract.TimedObserver=function(){}
+Abstract.TimedObserver.prototype={initialize:function(element,frequency,callback){this.frequency=frequency;this.element=$(element);this.callback=callback;this.lastValue=this.getValue();this.registerCallback();},registerCallback:function(){setInterval(this.onTimerEvent.bind(this),this.frequency*1000);},onTimerEvent:function(){var value=this.getValue();var changed=('string'==typeof this.lastValue&&'string'==typeof value?this.lastValue!=value:String(this.lastValue)!=String(value));if(changed){this.callback(this.element,value);this.lastValue=value;}}}
+Form.Element.Observer=Class.create();Form.Element.Observer.prototype=Object.extend(new Abstract.TimedObserver(),{getValue:function(){return Form.Element.getValue(this.element);}});Form.Observer=Class.create();Form.Observer.prototype=Object.extend(new Abstract.TimedObserver(),{getValue:function(){return Form.serialize(this.element);}});Abstract.EventObserver=function(){}
+Abstract.EventObserver.prototype={initialize:function(element,callback){this.element=$(element);this.callback=callback;this.lastValue=this.getValue();if(this.element.tagName.toLowerCase()=='form')
+this.registerFormCallbacks();else
+this.registerCallback(this.element);},onElementEvent:function(){var value=this.getValue();if(this.lastValue!=value){this.callback(this.element,value);this.lastValue=value;}},registerFormCallbacks:function(){Form.getElements(this.element).each(this.registerCallback.bind(this));},registerCallback:function(element){if(element.type){switch(element.type.toLowerCase()){case'checkbox':case'radio':Event.observe(element,'click',this.onElementEvent.bind(this));break;default:Event.observe(element,'change',this.onElementEvent.bind(this));break;}}}}
+Form.Element.EventObserver=Class.create();Form.Element.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.Element.getValue(this.element);}});Form.EventObserver=Class.create();Form.EventObserver.prototype=Object.extend(new Abstract.EventObserver(),{getValue:function(){return Form.serialize(this.element);}});if(!window.Event){var Event=new Object();}
+Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_HOME:36,KEY_END:35,KEY_PAGEUP:33,KEY_PAGEDOWN:34,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},pointerX:function(event){return event.pageX||(event.clientX+
+(document.documentElement.scrollLeft||document.body.scrollLeft));},pointerY:function(event){return event.pageY||(event.clientY+
+(document.documentElement.scrollTop||document.body.scrollTop));},stop:function(event){if(event.preventDefault){event.preventDefault();event.stopPropagation();}else{event.returnValue=false;event.cancelBubble=true;}},findElement:function(event,tagName){var element=Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
+element=element.parentNode;return element;},observers:false,_observeAndCache:function(element,name,observer,useCapture){if(!this.observers)this.observers=[];if(element.addEventListener){this.observers.push([element,name,observer,useCapture]);element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){this.observers.push([element,name,observer,useCapture]);element.attachEvent('on'+name,observer);}},unloadCache:function(){if(!Event.observers)return;for(var i=0,length=Event.observers.length;i<length;i++){Event.stopObserving.apply(this,Event.observers[i]);Event.observers[i][0]=null;}
+Event.observers=false;},observe:function(element,name,observer,useCapture){element=$(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent))
+name='keydown';Event._observeAndCache(element,name,observer,useCapture);},stopObserving:function(element,name,observer,useCapture){element=$(element);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent))
+name='keydown';if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element.detachEvent){try{element.detachEvent('on'+name,observer);}catch(e){}}}});if(navigator.appVersion.match(/\bMSIE\b/))
+Event.observe(window,'unload',Event.unloadCache,false);var Position={includeScrollOffsets:false,prepare:function(){this.deltaX=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;this.deltaY=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;},realOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.scrollTop||0;valueL+=element.scrollLeft||0;element=element.parentNode;}while(element);return[valueL,valueT];},cumulativeOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;element=element.offsetParent;}while(element);return[valueL,valueT];},positionedOffset:function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;element=element.offsetParent;if(element){if(element.tagName=='BODY')break;var p=Element.getStyle(element,'position');if(p=='relative'||p=='absolute')break;}}while(element);return[valueL,valueT];},offsetParent:function(element){if(element.offsetParent)return element.offsetParent;if(element==document.body)return element;while((element=element.parentNode)&&element!=document.body)
+if(Element.getStyle(element,'position')!='static')
+return element;return document.body;},within:function(element,x,y){if(this.includeScrollOffsets)
+return this.withinIncludingScrolloffsets(element,x,y);this.xcomp=x;this.ycomp=y;this.offset=this.cumulativeOffset(element);return(y>=this.offset[1]&&y<this.offset[1]+element.offsetHeight&&x>=this.offset[0]&&x<this.offset[0]+element.offsetWidth);},withinIncludingScrolloffsets:function(element,x,y){var offsetcache=this.realOffset(element);this.xcomp=x+offsetcache[0]-this.deltaX;this.ycomp=y+offsetcache[1]-this.deltaY;this.offset=this.cumulativeOffset(element);return(this.ycomp>=this.offset[1]&&this.ycomp<this.offset[1]+element.offsetHeight&&this.xcomp>=this.offset[0]&&this.xcomp<this.offset[0]+element.offsetWidth);},overlap:function(mode,element){if(!mode)return 0;if(mode=='vertical')
+return((this.offset[1]+element.offsetHeight)-this.ycomp)/element.offsetHeight;if(mode=='horizontal')
+return((this.offset[0]+element.offsetWidth)-this.xcomp)/element.offsetWidth;},page:function(forElement){var valueT=0,valueL=0;var element=forElement;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;if(element.offsetParent==document.body)
+if(Element.getStyle(element,'position')=='absolute')break;}while(element=element.offsetParent);element=forElement;do{if(!window.opera||element.tagName=='BODY'){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;}}while(element=element.parentNode);return[valueL,valueT];},clone:function(source,target){var options=Object.extend({setLeft:true,setTop:true,setWidth:true,setHeight:true,offsetTop:0,offsetLeft:0},arguments[2]||{})
+source=$(source);var p=Position.page(source);target=$(target);var delta=[0,0];var parent=null;if(Element.getStyle(target,'position')=='absolute'){parent=Position.offsetParent(target);delta=Position.page(parent);}
+if(parent==document.body){delta[0]-=document.body.offsetLeft;delta[1]-=document.body.offsetTop;}
+if(options.setLeft)target.style.left=(p[0]-delta[0]+options.offsetLeft)+'px';if(options.setTop)target.style.top=(p[1]-delta[1]+options.offsetTop)+'px';if(options.setWidth)target.style.width=source.offsetWidth+'px';if(options.setHeight)target.style.height=source.offsetHeight+'px';},absolutize:function(element){element=$(element);if(element.style.position=='absolute')return;Position.prepare();var offsets=Position.positionedOffset(element);var top=offsets[1];var left=offsets[0];var width=element.clientWidth;var height=element.clientHeight;element._originalLeft=left-parseFloat(element.style.left||0);element._originalTop=top-parseFloat(element.style.top||0);element._originalWidth=element.style.width;element._originalHeight=element.style.height;element.style.position='absolute';element.style.top=top+'px';element.style.left=left+'px';element.style.width=width+'px';element.style.height=height+'px';},relativize:function(element){element=$(element);if(element.style.position=='relative')return;Position.prepare();element.style.position='relative';var top=parseFloat(element.style.top||0)-(element._originalTop||0);var left=parseFloat(element.style.left||0)-(element._originalLeft||0);element.style.top=top+'px';element.style.left=left+'px';element.style.height=element._originalHeight;element.style.width=element._originalWidth;}}
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){Position.cumulativeOffset=function(element){var valueT=0,valueL=0;do{valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;if(element.offsetParent==document.body)
+if(Element.getStyle(element,'position')=='absolute')break;element=element.offsetParent;}while(element);return[valueL,valueT];}}
+Element.addMethods();var Builder={NODEMAP:{AREA:'map',CAPTION:'table',COL:'table',COLGROUP:'table',LEGEND:'fieldset',OPTGROUP:'select',OPTION:'select',PARAM:'object',TBODY:'table',TD:'table',TFOOT:'table',TH:'table',THEAD:'table',TR:'table'},node:function(elementName){elementName=elementName.toUpperCase();var parentTag=this.NODEMAP[elementName]||'div';var parentElement=document.createElement(parentTag);try{parentElement.innerHTML="<"+elementName+"></"+elementName+">";}catch(e){}
+var element=parentElement.firstChild||null;if(element&&(element.tagName.toUpperCase()!=elementName))
+element=element.getElementsByTagName(elementName)[0];if(!element)element=document.createElement(elementName);if(!element)return;if(arguments[1])
+if(this._isStringOrNumber(arguments[1])||(arguments[1]instanceof Array)){this._children(element,arguments[1]);}else{var attrs=this._attributes(arguments[1]);if(attrs.length){try{parentElement.innerHTML="<"+elementName+" "+
+attrs+"></"+elementName+">";}catch(e){}
+element=parentElement.firstChild||null;if(!element){element=document.createElement(elementName);for(attr in arguments[1])
+element[attr=='class'?'className':attr]=arguments[1][attr];}
+if(element.tagName.toUpperCase()!=elementName)
+element=parentElement.getElementsByTagName(elementName)[0];}}
+if(arguments[2])
+this._children(element,arguments[2]);return element;},_text:function(text){return document.createTextNode(text);},ATTR_MAP:{'className':'class','htmlFor':'for'},_attributes:function(attributes){var attrs=[];for(attribute in attributes)
+attrs.push((attribute in this.ATTR_MAP?this.ATTR_MAP[attribute]:attribute)+'="'+attributes[attribute].toString().escapeHTML()+'"');return attrs.join(" ");},_children:function(element,children){if(typeof children=='object'){children.flatten().each(function(e){if(typeof e=='object')
+element.appendChild(e)
+else
+if(Builder._isStringOrNumber(e))
+element.appendChild(Builder._text(e));});}else
+if(Builder._isStringOrNumber(children))
+element.appendChild(Builder._text(children));},_isStringOrNumber:function(param){return(typeof param=='string'||typeof param=='number');},build:function(html){var element=this.node('div');$(element).update(html.strip());return element.down();},dump:function(scope){if(typeof scope!='object'&&typeof scope!='function')scope=window;var tags=("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY "+"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET "+"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);tags.each(function(tag){scope[tag]=function(){return Builder.node.apply(Builder,[tag].concat($A(arguments)));}});}}
+String.prototype.parseColor=function(){var color='#';if(this.slice(0,4)=='rgb('){var cols=this.slice(4,this.length-1).split(',');var i=0;do{color+=parseInt(cols[i]).toColorPart()}while(++i<3);}else{if(this.slice(0,1)=='#'){if(this.length==4)for(var i=1;i<4;i++)color+=(this.charAt(i)+this.charAt(i)).toLowerCase();if(this.length==7)color=this.toLowerCase();}}
+return(color.length==7?color:(arguments[0]||this));}
+Element.collectTextNodes=function(element){return $A($(element).childNodes).collect(function(node){return(node.nodeType==3?node.nodeValue:(node.hasChildNodes()?Element.collectTextNodes(node):''));}).flatten().join('');}
+Element.collectTextNodesIgnoreClass=function(element,className){return $A($(element).childNodes).collect(function(node){return(node.nodeType==3?node.nodeValue:((node.hasChildNodes()&&!Element.hasClassName(node,className))?Element.collectTextNodesIgnoreClass(node,className):''));}).flatten().join('');}
+Element.setContentZoom=function(element,percent){element=$(element);element.setStyle({fontSize:(percent/100)+'em'});if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);return element;}
+Element.getOpacity=function(element){return $(element).getStyle('opacity');}
+Element.setOpacity=function(element,value){return $(element).setStyle({opacity:value});}
+Element.getInlineOpacity=function(element){return $(element).style.opacity||'';}
+Element.forceRerendering=function(element){try{element=$(element);var n=document.createTextNode(' ');element.appendChild(n);element.removeChild(n);}catch(e){}};Array.prototype.call=function(){var args=arguments;this.each(function(f){f.apply(this,args)});}
+var Effect={_elementDoesNotExistError:{name:'ElementDoesNotExistError',message:'The specified DOM element does not exist, but is required for this effect to operate'},tagifyText:function(element){if(typeof Builder=='undefined')
+throw("Effect.tagifyText requires including script.aculo.us' builder.js library");var tagifyStyle='position:relative';if(/MSIE/.test(navigator.userAgent)&&!window.opera)tagifyStyle+=';zoom:1';element=$(element);$A(element.childNodes).each(function(child){if(child.nodeType==3){child.nodeValue.toArray().each(function(character){element.insertBefore(Builder.node('span',{style:tagifyStyle},character==' '?String.fromCharCode(160):character),child);});Element.remove(child);}});},multiple:function(element,effect){var elements;if(((typeof element=='object')||(typeof element=='function'))&&(element.length))
+elements=element;else
+elements=$(element).childNodes;var options=Object.extend({speed:0.1,delay:0.0},arguments[2]||{});var masterDelay=options.delay;$A(elements).each(function(element,index){new effect(element,Object.extend(options,{delay:index*options.speed+masterDelay}));});},PAIRS:{'slide':['SlideDown','SlideUp'],'blind':['BlindDown','BlindUp'],'appear':['Appear','Fade']},toggle:function(element,effect){element=$(element);effect=(effect||'appear').toLowerCase();var options=Object.extend({queue:{position:'end',scope:(element.id||'global'),limit:1}},arguments[2]||{});Effect[element.visible()?Effect.PAIRS[effect][1]:Effect.PAIRS[effect][0]](element,options);}};var Effect2=Effect;Effect.Transitions={linear:Prototype.K,sinoidal:function(pos){return(-Math.cos(pos*Math.PI)/2)+0.5;},reverse:function(pos){return 1-pos;},flicker:function(pos){return((-Math.cos(pos*Math.PI)/4)+0.75)+Math.random()/4;},wobble:function(pos){return(-Math.cos(pos*Math.PI*(9*pos))/2)+0.5;},pulse:function(pos,pulses){pulses=pulses||5;return(Math.round((pos%(1/pulses))*pulses)==0?((pos*pulses*2)-Math.floor(pos*pulses*2)):1-((pos*pulses*2)-Math.floor(pos*pulses*2)));},none:function(pos){return 0;},full:function(pos){return 1;}};Effect.ScopedQueue=Class.create();Object.extend(Object.extend(Effect.ScopedQueue.prototype,Enumerable),{initialize:function(){this.effects=[];this.interval=null;},_each:function(iterator){this.effects._each(iterator);},add:function(effect){var timestamp=new Date().getTime();var position=(typeof effect.options.queue=='string')?effect.options.queue:effect.options.queue.position;switch(position){case'front':this.effects.findAll(function(e){return e.state=='idle'}).each(function(e){e.startOn+=effect.finishOn;e.finishOn+=effect.finishOn;});break;case'with-last':timestamp=this.effects.pluck('startOn').max()||timestamp;break;case'end':timestamp=this.effects.pluck('finishOn').max()||timestamp;break;}
+effect.startOn+=timestamp;effect.finishOn+=timestamp;if(!effect.options.queue.limit||(this.effects.length<effect.options.queue.limit))
+this.effects.push(effect);if(!this.interval)
+this.interval=setInterval(this.loop.bind(this),15);},remove:function(effect){this.effects=this.effects.reject(function(e){return e==effect});if(this.effects.length==0){clearInterval(this.interval);this.interval=null;}},loop:function(){var timePos=new Date().getTime();for(var i=0,len=this.effects.length;i<len;i++)
+if(this.effects[i])this.effects[i].loop(timePos);}});Effect.Queues={instances:$H(),get:function(queueName){if(typeof queueName!='string')return queueName;if(!this.instances[queueName])
+this.instances[queueName]=new Effect.ScopedQueue();return this.instances[queueName];}}
+Effect.Queue=Effect.Queues.get('global');Effect.DefaultOptions={transition:Effect.Transitions.sinoidal,duration:1.0,fps:60.0,sync:false,from:0.0,to:1.0,delay:0.0,queue:'parallel'}
+Effect.Base=function(){};Effect.Base.prototype={position:null,start:function(options){this.options=Object.extend(Object.extend({},Effect.DefaultOptions),options||{});this.currentFrame=0;this.state='idle';this.startOn=this.options.delay*1000;this.finishOn=this.startOn+(this.options.duration*1000);this.event('beforeStart');if(!this.options.sync)
+Effect.Queues.get(typeof this.options.queue=='string'?'global':this.options.queue.scope).add(this);},loop:function(timePos){if(timePos>=this.startOn){if(timePos>=this.finishOn){this.render(1.0);this.cancel();this.event('beforeFinish');if(this.finish)this.finish();this.event('afterFinish');return;}
+var pos=(timePos-this.startOn)/(this.finishOn-this.startOn);var frame=Math.round(pos*this.options.fps*this.options.duration);if(frame>this.currentFrame){this.render(pos);this.currentFrame=frame;}}},render:function(pos){if(this.state=='idle'){this.state='running';this.event('beforeSetup');if(this.setup)this.setup();this.event('afterSetup');}
+if(this.state=='running'){if(this.options.transition)pos=this.options.transition(pos);pos*=(this.options.to-this.options.from);pos+=this.options.from;this.position=pos;this.event('beforeUpdate');if(this.update)this.update(pos);this.event('afterUpdate');}},cancel:function(){if(!this.options.sync)
+Effect.Queues.get(typeof this.options.queue=='string'?'global':this.options.queue.scope).remove(this);this.state='finished';},event:function(eventName){if(this.options[eventName+'Internal'])this.options[eventName+'Internal'](this);if(this.options[eventName])this.options[eventName](this);},inspect:function(){var data=$H();for(property in this)
+if(typeof this[property]!='function')data[property]=this[property];return'#<Effect:'+data.inspect()+',options:'+$H(this.options).inspect()+'>';}}
+Effect.Parallel=Class.create();Object.extend(Object.extend(Effect.Parallel.prototype,Effect.Base.prototype),{initialize:function(effects){this.effects=effects||[];this.start(arguments[1]);},update:function(position){this.effects.invoke('render',position);},finish:function(position){this.effects.each(function(effect){effect.render(1.0);effect.cancel();effect.event('beforeFinish');if(effect.finish)effect.finish(position);effect.event('afterFinish');});}});Effect.Event=Class.create();Object.extend(Object.extend(Effect.Event.prototype,Effect.Base.prototype),{initialize:function(){var options=Object.extend({duration:0},arguments[0]||{});this.start(options);},update:Prototype.emptyFunction});Effect.Opacity=Class.create();Object.extend(Object.extend(Effect.Opacity.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);if(/MSIE/.test(navigator.userAgent)&&!window.opera&&(!this.element.currentStyle.hasLayout))
+this.element.setStyle({zoom:1});var options=Object.extend({from:this.element.getOpacity()||0.0,to:1.0},arguments[1]||{});this.start(options);},update:function(position){this.element.setOpacity(position);}});Effect.Move=Class.create();Object.extend(Object.extend(Effect.Move.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({x:0,y:0,mode:'relative'},arguments[1]||{});this.start(options);},setup:function(){this.element.makePositioned();this.originalLeft=parseFloat(this.element.getStyle('left')||'0');this.originalTop=parseFloat(this.element.getStyle('top')||'0');if(this.options.mode=='absolute'){this.options.x=this.options.x-this.originalLeft;this.options.y=this.options.y-this.originalTop;}},update:function(position){this.element.setStyle({left:Math.round(this.options.x*position+this.originalLeft)+'px',top:Math.round(this.options.y*position+this.originalTop)+'px'});}});Effect.MoveBy=function(element,toTop,toLeft){return new Effect.Move(element,Object.extend({x:toLeft,y:toTop},arguments[3]||{}));};Effect.Scale=Class.create();Object.extend(Object.extend(Effect.Scale.prototype,Effect.Base.prototype),{initialize:function(element,percent){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({scaleX:true,scaleY:true,scaleContent:true,scaleFromCenter:false,scaleMode:'box',scaleFrom:100.0,scaleTo:percent},arguments[2]||{});this.start(options);},setup:function(){this.restoreAfterFinish=this.options.restoreAfterFinish||false;this.elementPositioning=this.element.getStyle('position');this.originalStyle={};['top','left','width','height','fontSize'].each(function(k){this.originalStyle[k]=this.element.style[k];}.bind(this));this.originalTop=this.element.offsetTop;this.originalLeft=this.element.offsetLeft;var fontSize=this.element.getStyle('font-size')||'100%';['em','px','%','pt'].each(function(fontSizeType){if(fontSize.indexOf(fontSizeType)>0){this.fontSize=parseFloat(fontSize);this.fontSizeType=fontSizeType;}}.bind(this));this.factor=(this.options.scaleTo-this.options.scaleFrom)/100;this.dims=null;if(this.options.scaleMode=='box')
+this.dims=[this.element.offsetHeight,this.element.offsetWidth];if(/^content/.test(this.options.scaleMode))
+this.dims=[this.element.scrollHeight,this.element.scrollWidth];if(!this.dims)
+this.dims=[this.options.scaleMode.originalHeight,this.options.scaleMode.originalWidth];},update:function(position){var currentScale=(this.options.scaleFrom/100.0)+(this.factor*position);if(this.options.scaleContent&&this.fontSize)
+this.element.setStyle({fontSize:this.fontSize*currentScale+this.fontSizeType});this.setDimensions(this.dims[0]*currentScale,this.dims[1]*currentScale);},finish:function(position){if(this.restoreAfterFinish)this.element.setStyle(this.originalStyle);},setDimensions:function(height,width){var d={};if(this.options.scaleX)d.width=Math.round(width)+'px';if(this.options.scaleY)d.height=Math.round(height)+'px';if(this.options.scaleFromCenter){var topd=(height-this.dims[0])/2;var leftd=(width-this.dims[1])/2;if(this.elementPositioning=='absolute'){if(this.options.scaleY)d.top=this.originalTop-topd+'px';if(this.options.scaleX)d.left=this.originalLeft-leftd+'px';}else{if(this.options.scaleY)d.top=-topd+'px';if(this.options.scaleX)d.left=-leftd+'px';}}
+this.element.setStyle(d);}});Effect.Highlight=Class.create();Object.extend(Object.extend(Effect.Highlight.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({startcolor:'#ffff99'},arguments[1]||{});this.start(options);},setup:function(){if(this.element.getStyle('display')=='none'){this.cancel();return;}
+this.oldStyle={};if(!this.options.keepBackgroundImage){this.oldStyle.backgroundImage=this.element.getStyle('background-image');this.element.setStyle({backgroundImage:'none'});}
+if(!this.options.endcolor)
+this.options.endcolor=this.element.getStyle('background-color').parseColor('#ffffff');if(!this.options.restorecolor)
+this.options.restorecolor=this.element.getStyle('background-color');this._base=$R(0,2).map(function(i){return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16)}.bind(this));this._delta=$R(0,2).map(function(i){return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i]}.bind(this));},update:function(position){this.element.setStyle({backgroundColor:$R(0,2).inject('#',function(m,v,i){return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart());}.bind(this))});},finish:function(){this.element.setStyle(Object.extend(this.oldStyle,{backgroundColor:this.options.restorecolor}));}});Effect.ScrollTo=Class.create();Object.extend(Object.extend(Effect.ScrollTo.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);this.start(arguments[1]||{});},setup:function(){Position.prepare();var offsets=Position.cumulativeOffset(this.element);if(this.options.offset)offsets[1]+=this.options.offset;var max=window.innerHeight?window.height-window.innerHeight:document.body.scrollHeight-
+(document.documentElement.clientHeight?document.documentElement.clientHeight:document.body.clientHeight);this.scrollStart=Position.deltaY;this.delta=(offsets[1]>max?max:offsets[1])-this.scrollStart;},update:function(position){Position.prepare();window.scrollTo(Position.deltaX,this.scrollStart+(position*this.delta));}});Effect.Fade=function(element){element=$(element);var oldOpacity=element.getInlineOpacity();var options=Object.extend({from:element.getOpacity()||1.0,to:0.0,afterFinishInternal:function(effect){if(effect.options.to!=0)return;effect.element.hide().setStyle({opacity:oldOpacity});}},arguments[1]||{});return new Effect.Opacity(element,options);}
+Effect.Appear=function(element){element=$(element);var options=Object.extend({from:(element.getStyle('display')=='none'?0.0:element.getOpacity()||0.0),to:1.0,afterFinishInternal:function(effect){effect.element.forceRerendering();},beforeSetup:function(effect){effect.element.setOpacity(effect.options.from).show();}},arguments[1]||{});return new Effect.Opacity(element,options);}
+Effect.Puff=function(element){element=$(element);var oldStyle={opacity:element.getInlineOpacity(),position:element.getStyle('position'),top:element.style.top,left:element.style.left,width:element.style.width,height:element.style.height};return new Effect.Parallel([new Effect.Scale(element,200,{sync:true,scaleFromCenter:true,scaleContent:true,restoreAfterFinish:true}),new Effect.Opacity(element,{sync:true,to:0.0})],Object.extend({duration:1.0,beforeSetupInternal:function(effect){Position.absolutize(effect.effects[0].element)},afterFinishInternal:function(effect){effect.effects[0].element.hide().setStyle(oldStyle);}},arguments[1]||{}));}
+Effect.BlindUp=function(element){element=$(element);element.makeClipping();return new Effect.Scale(element,0,Object.extend({scaleContent:false,scaleX:false,restoreAfterFinish:true,afterFinishInternal:function(effect){effect.element.hide().undoClipping();}},arguments[1]||{}));}
+Effect.BlindDown=function(element){element=$(element);var elementDimensions=element.getDimensions();return new Effect.Scale(element,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:0,scaleMode:{originalHeight:elementDimensions.height,originalWidth:elementDimensions.width},restoreAfterFinish:true,afterSetup:function(effect){effect.element.makeClipping().setStyle({height:'0px'}).show();},afterFinishInternal:function(effect){effect.element.undoClipping();}},arguments[1]||{}));}
+Effect.SwitchOff=function(element){element=$(element);var oldOpacity=element.getInlineOpacity();return new Effect.Appear(element,Object.extend({duration:0.4,from:0,transition:Effect.Transitions.flicker,afterFinishInternal:function(effect){new Effect.Scale(effect.element,1,{duration:0.3,scaleFromCenter:true,scaleX:false,scaleContent:false,restoreAfterFinish:true,beforeSetup:function(effect){effect.element.makePositioned().makeClipping();},afterFinishInternal:function(effect){effect.element.hide().undoClipping().undoPositioned().setStyle({opacity:oldOpacity});}})}},arguments[1]||{}));}
+Effect.DropOut=function(element){element=$(element);var oldStyle={top:element.getStyle('top'),left:element.getStyle('left'),opacity:element.getInlineOpacity()};return new Effect.Parallel([new Effect.Move(element,{x:0,y:100,sync:true}),new Effect.Opacity(element,{sync:true,to:0.0})],Object.extend({duration:0.5,beforeSetup:function(effect){effect.effects[0].element.makePositioned();},afterFinishInternal:function(effect){effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);}},arguments[1]||{}));}
+Effect.Shake=function(element){element=$(element);var oldStyle={top:element.getStyle('top'),left:element.getStyle('left')};return new Effect.Move(element,{x:20,y:0,duration:0.05,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:40,y:0,duration:0.1,afterFinishInternal:function(effect){new Effect.Move(effect.element,{x:-20,y:0,duration:0.05,afterFinishInternal:function(effect){effect.element.undoPositioned().setStyle(oldStyle);}})}})}})}})}})}});}
+Effect.SlideDown=function(element){element=$(element).cleanWhitespace();var oldInnerBottom=element.down().getStyle('bottom');var elementDimensions=element.getDimensions();return new Effect.Scale(element,100,Object.extend({scaleContent:false,scaleX:false,scaleFrom:window.opera?0:1,scaleMode:{originalHeight:elementDimensions.height,originalWidth:elementDimensions.width},restoreAfterFinish:true,afterSetup:function(effect){effect.element.makePositioned();effect.element.down().makePositioned();if(window.opera)effect.element.setStyle({top:''});effect.element.makeClipping().setStyle({height:'0px'}).show();},afterUpdateInternal:function(effect){effect.element.down().setStyle({bottom:(effect.dims[0]-effect.element.clientHeight)+'px'});},afterFinishInternal:function(effect){effect.element.undoClipping().undoPositioned();effect.element.down().undoPositioned().setStyle({bottom:oldInnerBottom});}},arguments[1]||{}));}
+Effect.SlideUp=function(element){element=$(element).cleanWhitespace();var oldInnerBottom=element.down().getStyle('bottom');return new Effect.Scale(element,window.opera?0:1,Object.extend({scaleContent:false,scaleX:false,scaleMode:'box',scaleFrom:100,restoreAfterFinish:true,beforeStartInternal:function(effect){effect.element.makePositioned();effect.element.down().makePositioned();if(window.opera)effect.element.setStyle({top:''});effect.element.makeClipping().show();},afterUpdateInternal:function(effect){effect.element.down().setStyle({bottom:(effect.dims[0]-effect.element.clientHeight)+'px'});},afterFinishInternal:function(effect){effect.element.hide().undoClipping().undoPositioned().setStyle({bottom:oldInnerBottom});effect.element.down().undoPositioned();}},arguments[1]||{}));}
+Effect.Squish=function(element){return new Effect.Scale(element,window.opera?1:0,{restoreAfterFinish:true,beforeSetup:function(effect){effect.element.makeClipping();},afterFinishInternal:function(effect){effect.element.hide().undoClipping();}});}
+Effect.Grow=function(element){element=$(element);var options=Object.extend({direction:'center',moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.full},arguments[1]||{});var oldStyle={top:element.style.top,left:element.style.left,height:element.style.height,width:element.style.width,opacity:element.getInlineOpacity()};var dims=element.getDimensions();var initialMoveX,initialMoveY;var moveX,moveY;switch(options.direction){case'top-left':initialMoveX=initialMoveY=moveX=moveY=0;break;case'top-right':initialMoveX=dims.width;initialMoveY=moveY=0;moveX=-dims.width;break;case'bottom-left':initialMoveX=moveX=0;initialMoveY=dims.height;moveY=-dims.height;break;case'bottom-right':initialMoveX=dims.width;initialMoveY=dims.height;moveX=-dims.width;moveY=-dims.height;break;case'center':initialMoveX=dims.width/2;initialMoveY=dims.height/2;moveX=-dims.width/2;moveY=-dims.height/2;break;}
+return new Effect.Move(element,{x:initialMoveX,y:initialMoveY,duration:0.01,beforeSetup:function(effect){effect.element.hide().makeClipping().makePositioned();},afterFinishInternal:function(effect){new Effect.Parallel([new Effect.Opacity(effect.element,{sync:true,to:1.0,from:0.0,transition:options.opacityTransition}),new Effect.Move(effect.element,{x:moveX,y:moveY,sync:true,transition:options.moveTransition}),new Effect.Scale(effect.element,100,{scaleMode:{originalHeight:dims.height,originalWidth:dims.width},sync:true,scaleFrom:window.opera?1:0,transition:options.scaleTransition,restoreAfterFinish:true})],Object.extend({beforeSetup:function(effect){effect.effects[0].element.setStyle({height:'0px'}).show();},afterFinishInternal:function(effect){effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);}},options))}});}
+Effect.Shrink=function(element){element=$(element);var options=Object.extend({direction:'center',moveTransition:Effect.Transitions.sinoidal,scaleTransition:Effect.Transitions.sinoidal,opacityTransition:Effect.Transitions.none},arguments[1]||{});var oldStyle={top:element.style.top,left:element.style.left,height:element.style.height,width:element.style.width,opacity:element.getInlineOpacity()};var dims=element.getDimensions();var moveX,moveY;switch(options.direction){case'top-left':moveX=moveY=0;break;case'top-right':moveX=dims.width;moveY=0;break;case'bottom-left':moveX=0;moveY=dims.height;break;case'bottom-right':moveX=dims.width;moveY=dims.height;break;case'center':moveX=dims.width/2;moveY=dims.height/2;break;}
+return new Effect.Parallel([new Effect.Opacity(element,{sync:true,to:0.0,from:1.0,transition:options.opacityTransition}),new Effect.Scale(element,window.opera?1:0,{sync:true,transition:options.scaleTransition,restoreAfterFinish:true}),new Effect.Move(element,{x:moveX,y:moveY,sync:true,transition:options.moveTransition})],Object.extend({beforeStartInternal:function(effect){effect.effects[0].element.makePositioned().makeClipping();},afterFinishInternal:function(effect){effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle);}},options));}
+Effect.Pulsate=function(element){element=$(element);var options=arguments[1]||{};var oldOpacity=element.getInlineOpacity();var transition=options.transition||Effect.Transitions.sinoidal;var reverser=function(pos){return transition(1-Effect.Transitions.pulse(pos,options.pulses))};reverser.bind(transition);return new Effect.Opacity(element,Object.extend(Object.extend({duration:2.0,from:0,afterFinishInternal:function(effect){effect.element.setStyle({opacity:oldOpacity});}},options),{transition:reverser}));}
+Effect.Fold=function(element){element=$(element);var oldStyle={top:element.style.top,left:element.style.left,width:element.style.width,height:element.style.height};element.makeClipping();return new Effect.Scale(element,5,Object.extend({scaleContent:false,scaleX:false,afterFinishInternal:function(effect){new Effect.Scale(element,1,{scaleContent:false,scaleY:false,afterFinishInternal:function(effect){effect.element.hide().undoClipping().setStyle(oldStyle);}});}},arguments[1]||{}));};Effect.Morph=Class.create();Object.extend(Object.extend(Effect.Morph.prototype,Effect.Base.prototype),{initialize:function(element){this.element=$(element);if(!this.element)throw(Effect._elementDoesNotExistError);var options=Object.extend({style:{}},arguments[1]||{});if(typeof options.style=='string'){if(options.style.indexOf(':')==-1){var cssText='',selector='.'+options.style;$A(document.styleSheets).reverse().each(function(styleSheet){if(styleSheet.cssRules)cssRules=styleSheet.cssRules;else if(styleSheet.rules)cssRules=styleSheet.rules;$A(cssRules).reverse().each(function(rule){if(selector==rule.selectorText){cssText=rule.style.cssText;throw $break;}});if(cssText)throw $break;});this.style=cssText.parseStyle();options.afterFinishInternal=function(effect){effect.element.addClassName(effect.options.style);effect.transforms.each(function(transform){if(transform.style!='opacity')
+effect.element.style[transform.style.camelize()]='';});}}else this.style=options.style.parseStyle();}else this.style=$H(options.style)
+this.start(options);},setup:function(){function parseColor(color){if(!color||['rgba(0, 0, 0, 0)','transparent'].include(color))color='#ffffff';color=color.parseColor();return $R(0,2).map(function(i){return parseInt(color.slice(i*2+1,i*2+3),16)});}
+this.transforms=this.style.map(function(pair){var property=pair[0].underscore().dasherize(),value=pair[1],unit=null;if(value.parseColor('#zzzzzz')!='#zzzzzz'){value=value.parseColor();unit='color';}else if(property=='opacity'){value=parseFloat(value);if(/MSIE/.test(navigator.userAgent)&&!window.opera&&(!this.element.currentStyle.hasLayout))
+this.element.setStyle({zoom:1});}else if(Element.CSS_LENGTH.test(value))
+var components=value.match(/^([\+\-]?[0-9\.]+)(.*)$/),value=parseFloat(components[1]),unit=(components.length==3)?components[2]:null;var originalValue=this.element.getStyle(property);return $H({style:property,originalValue:unit=='color'?parseColor(originalValue):parseFloat(originalValue||0),targetValue:unit=='color'?parseColor(value):value,unit:unit});}.bind(this)).reject(function(transform){return((transform.originalValue==transform.targetValue)||(transform.unit!='color'&&(isNaN(transform.originalValue)||isNaN(transform.targetValue))))});},update:function(position){var style=$H(),value=null;this.transforms.each(function(transform){value=transform.unit=='color'?$R(0,2).inject('#',function(m,v,i){return m+(Math.round(transform.originalValue[i]+
+(transform.targetValue[i]-transform.originalValue[i])*position)).toColorPart()}):transform.originalValue+Math.round(((transform.targetValue-transform.originalValue)*position)*1000)/1000+transform.unit;style[transform.style]=value;});this.element.setStyle(style);}});Effect.Transform=Class.create();Object.extend(Effect.Transform.prototype,{initialize:function(tracks){this.tracks=[];this.options=arguments[1]||{};this.addTracks(tracks);},addTracks:function(tracks){tracks.each(function(track){var data=$H(track).values().first();this.tracks.push($H({ids:$H(track).keys().first(),effect:Effect.Morph,options:{style:data}}));}.bind(this));return this;},play:function(){return new Effect.Parallel(this.tracks.map(function(track){var elements=[$(track.ids)||$$(track.ids)].flatten();return elements.map(function(e){return new track.effect(e,Object.extend({sync:true},track.options))});}).flatten(),this.options);}});Element.CSS_PROPERTIES=$w('backgroundColor backgroundPosition borderBottomColor borderBottomStyle '+'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth '+'borderRightColor borderRightStyle borderRightWidth borderSpacing '+'borderTopColor borderTopStyle borderTopWidth bottom clip color '+'fontSize fontWeight height left letterSpacing lineHeight '+'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+'maxWidth minHeight minWidth opacity outlineColor outlineOffset '+'outlineWidth paddingBottom paddingLeft paddingRight paddingTop '+'right textIndent top width wordSpacing zIndex');Element.CSS_LENGTH=/^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;String.prototype.parseStyle=function(){var element=Element.extend(document.createElement('div'));element.innerHTML='<div style="'+this+'"></div>';var style=element.down().style,styleRules=$H();Element.CSS_PROPERTIES.each(function(property){if(style[property])styleRules[property]=style[property];});if(/MSIE/.test(navigator.userAgent)&&!window.opera&&this.indexOf('opacity')>-1){styleRules.opacity=this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];}
+return styleRules;};Element.morph=function(element,style){new Effect.Morph(element,Object.extend({style:style},arguments[2]||{}));return element;};['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom','collectTextNodes','collectTextNodesIgnoreClass','morph'].each(function(f){Element.Methods[f]=Element[f];});Element.Methods.visualEffect=function(element,effect,options){s=effect.gsub(/_/,'-').camelize();effect_class=s.charAt(0).toUpperCase()+s.substring(1);new Effect[effect_class](element,options);return $(element);};Element.addMethods();if(typeof Effect=='undefined')
+throw("dragdrop.js requires including script.aculo.us' effects.js library");var Droppables={drops:[],remove:function(element){this.drops=this.drops.reject(function(d){return d.element==$(element)});},add:function(element){element=$(element);var options=Object.extend({greedy:true,hoverclass:null,tree:false},arguments[1]||{});if(options.containment){options._containers=[];var containment=options.containment;if((typeof containment=='object')&&(containment.constructor==Array)){containment.each(function(c){options._containers.push($(c))});}else{options._containers.push($(containment));}}
+if(options.accept)options.accept=[options.accept].flatten();Element.makePositioned(element);options.element=element;this.drops.push(options);},findDeepestChild:function(drops){deepest=drops[0];for(i=1;i<drops.length;++i)
+if(Element.isParent(drops[i].element,deepest.element))
+deepest=drops[i];return deepest;},isContained:function(element,drop){var containmentNode;if(drop.tree){containmentNode=element.treeNode;}else{containmentNode=element.parentNode;}
+return drop._containers.detect(function(c){return containmentNode==c});},isAffected:function(point,element,drop){return((drop.element!=element)&&((!drop._containers)||this.isContained(element,drop))&&((!drop.accept)||(Element.classNames(element).detect(function(v){return drop.accept.include(v)})))&&Position.within(drop.element,point[0],point[1]));},deactivate:function(drop){if(drop.hoverclass)
+Element.removeClassName(drop.element,drop.hoverclass);this.last_active=null;},activate:function(drop){if(drop.hoverclass)
+Element.addClassName(drop.element,drop.hoverclass);this.last_active=drop;},show:function(point,element){if(!this.drops.length)return;var affected=[];if(this.last_active)this.deactivate(this.last_active);this.drops.each(function(drop){if(Droppables.isAffected(point,element,drop))
+affected.push(drop);});if(affected.length>0){drop=Droppables.findDeepestChild(affected);Position.within(drop.element,point[0],point[1]);if(drop.onHover)
+drop.onHover(element,drop.element,Position.overlap(drop.overlap,drop.element));Droppables.activate(drop);}},fire:function(event,element){if(!this.last_active)return;Position.prepare();if(this.isAffected([Event.pointerX(event),Event.pointerY(event)],element,this.last_active))
+if(this.last_active.onDrop)
+this.last_active.onDrop(element,this.last_active.element,event);},reset:function(){if(this.last_active)
+this.deactivate(this.last_active);}}
+var Draggables={drags:[],observers:[],register:function(draggable){if(this.drags.length==0){this.eventMouseUp=this.endDrag.bindAsEventListener(this);this.eventMouseMove=this.updateDrag.bindAsEventListener(this);this.eventKeypress=this.keyPress.bindAsEventListener(this);Event.observe(document,"mouseup",this.eventMouseUp);Event.observe(document,"mousemove",this.eventMouseMove);Event.observe(document,"keypress",this.eventKeypress);}
+this.drags.push(draggable);},unregister:function(draggable){this.drags=this.drags.reject(function(d){return d==draggable});if(this.drags.length==0){Event.stopObserving(document,"mouseup",this.eventMouseUp);Event.stopObserving(document,"mousemove",this.eventMouseMove);Event.stopObserving(document,"keypress",this.eventKeypress);}},activate:function(draggable){if(draggable.options.delay){this._timeout=setTimeout(function(){Draggables._timeout=null;window.focus();Draggables.activeDraggable=draggable;}.bind(this),draggable.options.delay);}else{window.focus();this.activeDraggable=draggable;}},deactivate:function(){this.activeDraggable=null;},updateDrag:function(event){if(!this.activeDraggable)return;var pointer=[Event.pointerX(event),Event.pointerY(event)];if(this._lastPointer&&(this._lastPointer.inspect()==pointer.inspect()))return;this._lastPointer=pointer;this.activeDraggable.updateDrag(event,pointer);},endDrag:function(event){if(this._timeout){clearTimeout(this._timeout);this._timeout=null;}
+if(!this.activeDraggable)return;this._lastPointer=null;this.activeDraggable.endDrag(event);this.activeDraggable=null;},keyPress:function(event){if(this.activeDraggable)
+this.activeDraggable.keyPress(event);},addObserver:function(observer){this.observers.push(observer);this._cacheObserverCallbacks();},removeObserver:function(element){this.observers=this.observers.reject(function(o){return o.element==element});this._cacheObserverCallbacks();},notify:function(eventName,draggable,event){if(this[eventName+'Count']>0)
+this.observers.each(function(o){if(o[eventName])o[eventName](eventName,draggable,event);});if(draggable.options[eventName])draggable.options[eventName](draggable,event);},_cacheObserverCallbacks:function(){['onStart','onEnd','onDrag'].each(function(eventName){Draggables[eventName+'Count']=Draggables.observers.select(function(o){return o[eventName];}).length;});}}
+var Draggable=Class.create();Draggable._dragging={};Draggable.prototype={initialize:function(element){var defaults={handle:false,reverteffect:function(element,top_offset,left_offset){var dur=Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;new Effect.Move(element,{x:-left_offset,y:-top_offset,duration:dur,queue:{scope:'_draggable',position:'end'}});},endeffect:function(element){var toOpacity=typeof element._opacity=='number'?element._opacity:1.0;new Effect.Opacity(element,{duration:0.2,from:0.7,to:toOpacity,queue:{scope:'_draggable',position:'end'},afterFinish:function(){Draggable._dragging[element]=false}});},zindex:1000,revert:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,snap:false,delay:0};if(!arguments[1]||typeof arguments[1].endeffect=='undefined')
+Object.extend(defaults,{starteffect:function(element){element._opacity=Element.getOpacity(element);Draggable._dragging[element]=true;new Effect.Opacity(element,{duration:0.2,from:element._opacity,to:0.7});}});var options=Object.extend(defaults,arguments[1]||{});this.element=$(element);if(options.handle&&(typeof options.handle=='string'))
+this.handle=this.element.down('.'+options.handle,0);if(!this.handle)this.handle=$(options.handle);if(!this.handle)this.handle=this.element;if(options.scroll&&!options.scroll.scrollTo&&!options.scroll.outerHTML){options.scroll=$(options.scroll);this._isScrollChild=Element.childOf(this.element,options.scroll);}
+Element.makePositioned(this.element);this.delta=this.currentDelta();this.options=options;this.dragging=false;this.eventMouseDown=this.initDrag.bindAsEventListener(this);Event.observe(this.handle,"mousedown",this.eventMouseDown);Draggables.register(this);},destroy:function(){Event.stopObserving(this.handle,"mousedown",this.eventMouseDown);Draggables.unregister(this);},currentDelta:function(){return([parseInt(Element.getStyle(this.element,'left')||'0'),parseInt(Element.getStyle(this.element,'top')||'0')]);},initDrag:function(event){if(typeof Draggable._dragging[this.element]!='undefined'&&Draggable._dragging[this.element])return;if(Event.isLeftClick(event)){var src=Event.element(event);if((tag_name=src.tagName.toUpperCase())&&(tag_name=='INPUT'||tag_name=='SELECT'||tag_name=='OPTION'||tag_name=='BUTTON'||tag_name=='TEXTAREA'))return;var pointer=[Event.pointerX(event),Event.pointerY(event)];var pos=Position.cumulativeOffset(this.element);this.offset=[0,1].map(function(i){return(pointer[i]-pos[i])});Draggables.activate(this);Event.stop(event);}},startDrag:function(event){this.dragging=true;if(this.options.zindex){this.originalZ=parseInt(Element.getStyle(this.element,'z-index')||0);this.element.style.zIndex=this.options.zindex;}
+if(this.options.ghosting){this._clone=this.element.cloneNode(true);Position.absolutize(this.element);this.element.parentNode.insertBefore(this._clone,this.element);}
+if(this.options.scroll){if(this.options.scroll==window){var where=this._getWindowScroll(this.options.scroll);this.originalScrollLeft=where.left;this.originalScrollTop=where.top;}else{this.originalScrollLeft=this.options.scroll.scrollLeft;this.originalScrollTop=this.options.scroll.scrollTop;}}
+Draggables.notify('onStart',this,event);if(this.options.starteffect)this.options.starteffect(this.element);},updateDrag:function(event,pointer){if(!this.dragging)this.startDrag(event);Position.prepare();Droppables.show(pointer,this.element);Draggables.notify('onDrag',this,event);this.draw(pointer);if(this.options.change)this.options.change(this);if(this.options.scroll){this.stopScrolling();var p;if(this.options.scroll==window){with(this._getWindowScroll(this.options.scroll)){p=[left,top,left+width,top+height];}}else{p=Position.page(this.options.scroll);p[0]+=this.options.scroll.scrollLeft+Position.deltaX;p[1]+=this.options.scroll.scrollTop+Position.deltaY;p.push(p[0]+this.options.scroll.offsetWidth);p.push(p[1]+this.options.scroll.offsetHeight);}
+var speed=[0,0];if(pointer[0]<(p[0]+this.options.scrollSensitivity))speed[0]=pointer[0]-(p[0]+this.options.scrollSensitivity);if(pointer[1]<(p[1]+this.options.scrollSensitivity))speed[1]=pointer[1]-(p[1]+this.options.scrollSensitivity);if(pointer[0]>(p[2]-this.options.scrollSensitivity))speed[0]=pointer[0]-(p[2]-this.options.scrollSensitivity);if(pointer[1]>(p[3]-this.options.scrollSensitivity))speed[1]=pointer[1]-(p[3]-this.options.scrollSensitivity);this.startScrolling(speed);}
+if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);Event.stop(event);},finishDrag:function(event,success){this.dragging=false;if(this.options.ghosting){Position.relativize(this.element);Element.remove(this._clone);this._clone=null;}
+if(success)Droppables.fire(event,this.element);Draggables.notify('onEnd',this,event);var revert=this.options.revert;if(revert&&typeof revert=='function')revert=revert(this.element);var d=this.currentDelta();if(revert&&this.options.reverteffect){this.options.reverteffect(this.element,d[1]-this.delta[1],d[0]-this.delta[0]);}else{this.delta=d;}
+if(this.options.zindex)
+this.element.style.zIndex=this.originalZ;if(this.options.endeffect)
+this.options.endeffect(this.element);Draggables.deactivate(this);Droppables.reset();},keyPress:function(event){if(event.keyCode!=Event.KEY_ESC)return;this.finishDrag(event,false);Event.stop(event);},endDrag:function(event){if(!this.dragging)return;this.stopScrolling();this.finishDrag(event,true);Event.stop(event);},draw:function(point){var pos=Position.cumulativeOffset(this.element);if(this.options.ghosting){var r=Position.realOffset(this.element);pos[0]+=r[0]-Position.deltaX;pos[1]+=r[1]-Position.deltaY;}
+var d=this.currentDelta();pos[0]-=d[0];pos[1]-=d[1];if(this.options.scroll&&(this.options.scroll!=window&&this._isScrollChild)){pos[0]-=this.options.scroll.scrollLeft-this.originalScrollLeft;pos[1]-=this.options.scroll.scrollTop-this.originalScrollTop;}
+var p=[0,1].map(function(i){return(point[i]-pos[i]-this.offset[i])}.bind(this));if(this.options.snap){if(typeof this.options.snap=='function'){p=this.options.snap(p[0],p[1],this);}else{if(this.options.snap instanceof Array){p=p.map(function(v,i){return Math.round(v/this.options.snap[i])*this.options.snap[i]}.bind(this))}else{p=p.map(function(v){return Math.round(v/this.options.snap)*this.options.snap}.bind(this))}}}
+var style=this.element.style;if((!this.options.constraint)||(this.options.constraint=='horizontal'))
+style.left=p[0]+"px";if((!this.options.constraint)||(this.options.constraint=='vertical'))
+style.top=p[1]+"px";if(style.visibility=="hidden")style.visibility="";},stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null;Draggables._lastScrollPointer=null;}},startScrolling:function(speed){if(!(speed[0]||speed[1]))return;this.scrollSpeed=[speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];this.lastScrolled=new Date();this.scrollInterval=setInterval(this.scroll.bind(this),10);},scroll:function(){var current=new Date();var delta=current-this.lastScrolled;this.lastScrolled=current;if(this.options.scroll==window){with(this._getWindowScroll(this.options.scroll)){if(this.scrollSpeed[0]||this.scrollSpeed[1]){var d=delta/1000;this.options.scroll.scrollTo(left+d*this.scrollSpeed[0],top+d*this.scrollSpeed[1]);}}}else{this.options.scroll.scrollLeft+=this.scrollSpeed[0]*delta/1000;this.options.scroll.scrollTop+=this.scrollSpeed[1]*delta/1000;}
+Position.prepare();Droppables.show(Draggables._lastPointer,this.element);Draggables.notify('onDrag',this);if(this._isScrollChild){Draggables._lastScrollPointer=Draggables._lastScrollPointer||$A(Draggables._lastPointer);Draggables._lastScrollPointer[0]+=this.scrollSpeed[0]*delta/1000;Draggables._lastScrollPointer[1]+=this.scrollSpeed[1]*delta/1000;if(Draggables._lastScrollPointer[0]<0)
+Draggables._lastScrollPointer[0]=0;if(Draggables._lastScrollPointer[1]<0)
+Draggables._lastScrollPointer[1]=0;this.draw(Draggables._lastScrollPointer);}
+if(this.options.change)this.options.change(this);},_getWindowScroll:function(w){var T,L,W,H;with(w.document){if(w.document.documentElement&&documentElement.scrollTop){T=documentElement.scrollTop;L=documentElement.scrollLeft;}else if(w.document.body){T=body.scrollTop;L=body.scrollLeft;}
+if(w.innerWidth){W=w.innerWidth;H=w.innerHeight;}else if(w.document.documentElement&&documentElement.clientWidth){W=documentElement.clientWidth;H=documentElement.clientHeight;}else{W=body.offsetWidth;H=body.offsetHeight}}
+return{top:T,left:L,width:W,height:H};}}
+var SortableObserver=Class.create();SortableObserver.prototype={initialize:function(element,observer){this.element=$(element);this.observer=observer;this.lastValue=Sortable.serialize(this.element);},onStart:function(){this.lastValue=Sortable.serialize(this.element);},onEnd:function(){Sortable.unmark();if(this.lastValue!=Sortable.serialize(this.element))
+this.observer(this.element)}}
+var Sortable={SERIALIZE_RULE:/^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,sortables:{},_findRootElement:function(element){while(element.tagName.toUpperCase()!="BODY"){if(element.id&&Sortable.sortables[element.id])return element;element=element.parentNode;}},options:function(element){element=Sortable._findRootElement($(element));if(!element)return;return Sortable.sortables[element.id];},destroy:function(element){var s=Sortable.options(element);if(s){Draggables.removeObserver(s.element);s.droppables.each(function(d){Droppables.remove(d)});s.draggables.invoke('destroy');delete Sortable.sortables[s.element.id];}},create:function(element){element=$(element);var options=Object.extend({element:element,tag:'li',dropOnEmpty:false,tree:false,treeTag:'ul',overlap:'vertical',constraint:'vertical',containment:element,handle:false,only:false,delay:0,hoverclass:null,ghosting:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,format:this.SERIALIZE_RULE,onChange:Prototype.emptyFunction,onUpdate:Prototype.emptyFunction},arguments[1]||{});this.destroy(element);var options_for_draggable={revert:true,scroll:options.scroll,scrollSpeed:options.scrollSpeed,scrollSensitivity:options.scrollSensitivity,delay:options.delay,ghosting:options.ghosting,constraint:options.constraint,handle:options.handle};if(options.starteffect)
+options_for_draggable.starteffect=options.starteffect;if(options.reverteffect)
+options_for_draggable.reverteffect=options.reverteffect;else
+if(options.ghosting)options_for_draggable.reverteffect=function(element){element.style.top=0;element.style.left=0;};if(options.endeffect)
+options_for_draggable.endeffect=options.endeffect;if(options.zindex)
+options_for_draggable.zindex=options.zindex;var options_for_droppable={overlap:options.overlap,containment:options.containment,tree:options.tree,hoverclass:options.hoverclass,onHover:Sortable.onHover}
+var options_for_tree={onHover:Sortable.onEmptyHover,overlap:options.overlap,containment:options.containment,hoverclass:options.hoverclass}
+Element.cleanWhitespace(element);options.draggables=[];options.droppables=[];if(options.dropOnEmpty||options.tree){Droppables.add(element,options_for_tree);options.droppables.push(element);}
+(this.findElements(element,options)||[]).each(function(e){var handle=options.handle?$(e).down('.'+options.handle,0):e;options.draggables.push(new Draggable(e,Object.extend(options_for_draggable,{handle:handle})));Droppables.add(e,options_for_droppable);if(options.tree)e.treeNode=element;options.droppables.push(e);});if(options.tree){(Sortable.findTreeElements(element,options)||[]).each(function(e){Droppables.add(e,options_for_tree);e.treeNode=element;options.droppables.push(e);});}
+this.sortables[element.id]=options;Draggables.addObserver(new SortableObserver(element,options.onUpdate));},findElements:function(element,options){return Element.findChildren(element,options.only,options.tree?true:false,options.tag);},findTreeElements:function(element,options){return Element.findChildren(element,options.only,options.tree?true:false,options.treeTag);},onHover:function(element,dropon,overlap){if(Element.isParent(dropon,element))return;if(overlap>.33&&overlap<.66&&Sortable.options(dropon).tree){return;}else if(overlap>0.5){Sortable.mark(dropon,'before');if(dropon.previousSibling!=element){var oldParentNode=element.parentNode;element.style.visibility="hidden";dropon.parentNode.insertBefore(element,dropon);if(dropon.parentNode!=oldParentNode)
+Sortable.options(oldParentNode).onChange(element);Sortable.options(dropon.parentNode).onChange(element);}}else{Sortable.mark(dropon,'after');var nextElement=dropon.nextSibling||null;if(nextElement!=element){var oldParentNode=element.parentNode;element.style.visibility="hidden";dropon.parentNode.insertBefore(element,nextElement);if(dropon.parentNode!=oldParentNode)
+Sortable.options(oldParentNode).onChange(element);Sortable.options(dropon.parentNode).onChange(element);}}},onEmptyHover:function(element,dropon,overlap){var oldParentNode=element.parentNode;var droponOptions=Sortable.options(dropon);if(!Element.isParent(dropon,element)){var index;var children=Sortable.findElements(dropon,{tag:droponOptions.tag,only:droponOptions.only});var child=null;if(children){var offset=Element.offsetSize(dropon,droponOptions.overlap)*(1.0-overlap);for(index=0;index<children.length;index+=1){if(offset-Element.offsetSize(children[index],droponOptions.overlap)>=0){offset-=Element.offsetSize(children[index],droponOptions.overlap);}else if(offset-(Element.offsetSize(children[index],droponOptions.overlap)/2)>=0){child=index+1<children.length?children[index+1]:null;break;}else{child=children[index];break;}}}
+dropon.insertBefore(element,child);Sortable.options(oldParentNode).onChange(element);droponOptions.onChange(element);}},unmark:function(){if(Sortable._marker)Sortable._marker.hide();},mark:function(dropon,position){var sortable=Sortable.options(dropon.parentNode);if(sortable&&!sortable.ghosting)return;if(!Sortable._marker){Sortable._marker=($('dropmarker')||Element.extend(document.createElement('DIV'))).hide().addClassName('dropmarker').setStyle({position:'absolute'});document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);}
+var offsets=Position.cumulativeOffset(dropon);Sortable._marker.setStyle({left:offsets[0]+'px',top:offsets[1]+'px'});if(position=='after')
+if(sortable.overlap=='horizontal')
+Sortable._marker.setStyle({left:(offsets[0]+dropon.clientWidth)+'px'});else
+Sortable._marker.setStyle({top:(offsets[1]+dropon.clientHeight)+'px'});Sortable._marker.show();},_tree:function(element,options,parent){var children=Sortable.findElements(element,options)||[];for(var i=0;i<children.length;++i){var match=children[i].id.match(options.format);if(!match)continue;var child={id:encodeURIComponent(match?match[1]:null),element:element,parent:parent,children:[],position:parent.children.length,container:$(children[i]).down(options.treeTag)}
+if(child.container)
+this._tree(child.container,options,child)
+parent.children.push(child);}
+return parent;},tree:function(element){element=$(element);var sortableOptions=this.options(element);var options=Object.extend({tag:sortableOptions.tag,treeTag:sortableOptions.treeTag,only:sortableOptions.only,name:element.id,format:sortableOptions.format},arguments[1]||{});var root={id:null,parent:null,children:[],container:element,position:0}
+return Sortable._tree(element,options,root);},_constructIndex:function(node){var index='';do{if(node.id)index='['+node.position+']'+index;}while((node=node.parent)!=null);return index;},sequence:function(element){element=$(element);var options=Object.extend(this.options(element),arguments[1]||{});return $(this.findElements(element,options)||[]).map(function(item){return item.id.match(options.format)?item.id.match(options.format)[1]:'';});},setSequence:function(element,new_sequence){element=$(element);var options=Object.extend(this.options(element),arguments[2]||{});var nodeMap={};this.findElements(element,options).each(function(n){if(n.id.match(options.format))
+nodeMap[n.id.match(options.format)[1]]=[n,n.parentNode];n.parentNode.removeChild(n);});new_sequence.each(function(ident){var n=nodeMap[ident];if(n){n[1].appendChild(n[0]);delete nodeMap[ident];}});},serialize:function(element){element=$(element);var options=Object.extend(Sortable.options(element),arguments[1]||{});var name=encodeURIComponent((arguments[1]&&arguments[1].name)?arguments[1].name:element.id);if(options.tree){return Sortable.tree(element,arguments[1]).children.map(function(item){return[name+Sortable._constructIndex(item)+"[id]="+
+encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));}).flatten().join('&');}else{return Sortable.sequence(element,arguments[1]).map(function(item){return name+"[]="+encodeURIComponent(item);}).join('&');}}}
+Element.isParent=function(child,element){if(!child.parentNode||child==element)return false;if(child.parentNode==element)return true;return Element.isParent(child.parentNode,element);}
+Element.findChildren=function(element,only,recursive,tagName){if(!element.hasChildNodes())return null;tagName=tagName.toUpperCase();if(only)only=[only].flatten();var elements=[];$A(element.childNodes).each(function(e){if(e.tagName&&e.tagName.toUpperCase()==tagName&&(!only||(Element.classNames(e).detect(function(v){return only.include(v)}))))
+elements.push(e);if(recursive){var grandchildren=Element.findChildren(e,only,recursive,tagName);if(grandchildren)elements.push(grandchildren);}});return(elements.length>0?elements.flatten():[]);}
+Element.offsetSize=function(element,type){return element['offset'+((type=='vertical'||type=='height')?'Height':'Width')];}
+if(typeof Effect=='undefined')
+throw("controls.js requires including script.aculo.us' effects.js library");var Autocompleter={}
+Autocompleter.Base=function(){};Autocompleter.Base.prototype={baseInitialize:function(element,update,options){this.element=$(element);this.update=$(update);this.hasFocus=false;this.changed=false;this.active=false;this.index=0;this.entryCount=0;if(this.setOptions)
+this.setOptions(options);else
+this.options=options||{};this.options.paramName=this.options.paramName||this.element.name;this.options.tokens=this.options.tokens||[];this.options.frequency=this.options.frequency||0.4;this.options.minChars=this.options.minChars||1;this.options.onShow=this.options.onShow||function(element,update){if(!update.style.position||update.style.position=='absolute'){update.style.position='absolute';Position.clone(element,update,{setHeight:false,offsetTop:element.offsetHeight});}
+Effect.Appear(update,{duration:0.15});};this.options.onHide=this.options.onHide||function(element,update){new Effect.Fade(update,{duration:0.15})};if(typeof(this.options.tokens)=='string')
+this.options.tokens=new Array(this.options.tokens);this.observer=null;this.element.setAttribute('autocomplete','off');Element.hide(this.update);Event.observe(this.element,"blur",this.onBlur.bindAsEventListener(this));Event.observe(this.element,"keypress",this.onKeyPress.bindAsEventListener(this));},show:function(){if(Element.getStyle(this.update,'display')=='none')this.options.onShow(this.element,this.update);if(!this.iefix&&(navigator.appVersion.indexOf('MSIE')>0)&&(navigator.userAgent.indexOf('Opera')<0)&&(Element.getStyle(this.update,'position')=='absolute')){new Insertion.After(this.update,'<iframe id="'+this.update.id+'_iefix" '+'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" '+'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');this.iefix=$(this.update.id+'_iefix');}
+if(this.iefix)setTimeout(this.fixIEOverlapping.bind(this),50);},fixIEOverlapping:function(){Position.clone(this.update,this.iefix,{setTop:(!this.update.style.height)});this.iefix.style.zIndex=1;this.update.style.zIndex=2;Element.show(this.iefix);},hide:function(){this.stopIndicator();if(Element.getStyle(this.update,'display')!='none')this.options.onHide(this.element,this.update);if(this.iefix)Element.hide(this.iefix);},startIndicator:function(){if(this.options.indicator)Element.show(this.options.indicator);},stopIndicator:function(){if(this.options.indicator)Element.hide(this.options.indicator);},onKeyPress:function(event){if(this.active)
+switch(event.keyCode){case Event.KEY_TAB:case Event.KEY_RETURN:this.selectEntry();Event.stop(event);case Event.KEY_ESC:this.hide();this.active=false;Event.stop(event);return;case Event.KEY_LEFT:case Event.KEY_RIGHT:return;case Event.KEY_UP:this.markPrevious();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;case Event.KEY_DOWN:this.markNext();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;}
+else
+if(event.keyCode==Event.KEY_TAB||event.keyCode==Event.KEY_RETURN||(navigator.appVersion.indexOf('AppleWebKit')>0&&event.keyCode==0))return;this.changed=true;this.hasFocus=true;if(this.observer)clearTimeout(this.observer);this.observer=setTimeout(this.onObserverEvent.bind(this),this.options.frequency*1000);},activate:function(){this.changed=false;this.hasFocus=true;this.getUpdatedChoices();},onHover:function(event){var element=Event.findElement(event,'LI');if(this.index!=element.autocompleteIndex)
+{this.index=element.autocompleteIndex;this.render();}
+Event.stop(event);},onClick:function(event){var element=Event.findElement(event,'LI');this.index=element.autocompleteIndex;this.selectEntry();this.hide();},onBlur:function(event){setTimeout(this.hide.bind(this),250);this.hasFocus=false;this.active=false;},render:function(){if(this.entryCount>0){for(var i=0;i<this.entryCount;i++)
+this.index==i?Element.addClassName(this.getEntry(i),"selected"):Element.removeClassName(this.getEntry(i),"selected");if(this.hasFocus){this.show();this.active=true;}}else{this.active=false;this.hide();}},markPrevious:function(){if(this.index>0)this.index--
+else this.index=this.entryCount-1;this.getEntry(this.index).scrollIntoView(true);},markNext:function(){if(this.index<this.entryCount-1)this.index++
+else this.index=0;this.getEntry(this.index).scrollIntoView(false);},getEntry:function(index){return this.update.firstChild.childNodes[index];},getCurrentEntry:function(){return this.getEntry(this.index);},selectEntry:function(){this.active=false;this.updateElement(this.getCurrentEntry());},updateElement:function(selectedElement){if(this.options.updateElement){this.options.updateElement(selectedElement);return;}
+var value='';if(this.options.select){var nodes=document.getElementsByClassName(this.options.select,selectedElement)||[];if(nodes.length>0)value=Element.collectTextNodes(nodes[0],this.options.select);}else
+value=Element.collectTextNodesIgnoreClass(selectedElement,'informal');var lastTokenPos=this.findLastToken();if(lastTokenPos!=-1){var newValue=this.element.value.substr(0,lastTokenPos+1);var whitespace=this.element.value.substr(lastTokenPos+1).match(/^\s+/);if(whitespace)
+newValue+=whitespace[0];this.element.value=newValue+value;}else{this.element.value=value;}
+this.element.focus();if(this.options.afterUpdateElement)
+this.options.afterUpdateElement(this.element,selectedElement);},updateChoices:function(choices){if(!this.changed&&this.hasFocus){this.update.innerHTML=choices;Element.cleanWhitespace(this.update);Element.cleanWhitespace(this.update.down());if(this.update.firstChild&&this.update.down().childNodes){this.entryCount=this.update.down().childNodes.length;for(var i=0;i<this.entryCount;i++){var entry=this.getEntry(i);entry.autocompleteIndex=i;this.addObservers(entry);}}else{this.entryCount=0;}
+this.stopIndicator();this.index=0;if(this.entryCount==1&&this.options.autoSelect){this.selectEntry();this.hide();}else{this.render();}}},addObservers:function(element){Event.observe(element,"mouseover",this.onHover.bindAsEventListener(this));Event.observe(element,"click",this.onClick.bindAsEventListener(this));},onObserverEvent:function(){this.changed=false;if(this.getToken().length>=this.options.minChars){this.startIndicator();this.getUpdatedChoices();}else{this.active=false;this.hide();}},getToken:function(){var tokenPos=this.findLastToken();if(tokenPos!=-1)
+var ret=this.element.value.substr(tokenPos+1).replace(/^\s+/,'').replace(/\s+$/,'');else
+var ret=this.element.value;return/\n/.test(ret)?'':ret;},findLastToken:function(){var lastTokenPos=-1;for(var i=0;i<this.options.tokens.length;i++){var thisTokenPos=this.element.value.lastIndexOf(this.options.tokens[i]);if(thisTokenPos>lastTokenPos)
+lastTokenPos=thisTokenPos;}
+return lastTokenPos;}}
+Ajax.Autocompleter=Class.create();Object.extend(Object.extend(Ajax.Autocompleter.prototype,Autocompleter.Base.prototype),{initialize:function(element,update,url,options){this.baseInitialize(element,update,options);this.options.asynchronous=true;this.options.onComplete=this.onComplete.bind(this);this.options.defaultParams=this.options.parameters||null;this.url=url;},getUpdatedChoices:function(){entry=encodeURIComponent(this.options.paramName)+'='+
+encodeURIComponent(this.getToken());this.options.parameters=this.options.callback?this.options.callback(this.element,entry):entry;if(this.options.defaultParams)
+this.options.parameters+='&'+this.options.defaultParams;new Ajax.Request(this.url,this.options);},onComplete:function(request){this.updateChoices(request.responseText);}});Autocompleter.Local=Class.create();Autocompleter.Local.prototype=Object.extend(new Autocompleter.Base(),{initialize:function(element,update,array,options){this.baseInitialize(element,update,options);this.options.array=array;},getUpdatedChoices:function(){this.updateChoices(this.options.selector(this));},setOptions:function(options){this.options=Object.extend({choices:10,partialSearch:true,partialChars:2,ignoreCase:true,fullSearch:false,selector:function(instance){var ret=[];var partial=[];var entry=instance.getToken();var count=0;for(var i=0;i<instance.options.array.length&&ret.length<instance.options.choices;i++){var elem=instance.options.array[i];var foundPos=instance.options.ignoreCase?elem.toLowerCase().indexOf(entry.toLowerCase()):elem.indexOf(entry);while(foundPos!=-1){if(foundPos==0&&elem.length!=entry.length){ret.push("<li><strong>"+elem.substr(0,entry.length)+"</strong>"+
+elem.substr(entry.length)+"</li>");break;}else if(entry.length>=instance.options.partialChars&&instance.options.partialSearch&&foundPos!=-1){if(instance.options.fullSearch||/\s/.test(elem.substr(foundPos-1,1))){partial.push("<li>"+elem.substr(0,foundPos)+"<strong>"+
+elem.substr(foundPos,entry.length)+"</strong>"+elem.substr(foundPos+entry.length)+"</li>");break;}}
+foundPos=instance.options.ignoreCase?elem.toLowerCase().indexOf(entry.toLowerCase(),foundPos+1):elem.indexOf(entry,foundPos+1);}}
+if(partial.length)
+ret=ret.concat(partial.slice(0,instance.options.choices-ret.length))
+return"<ul>"+ret.join('')+"</ul>";}},options||{});}});Field.scrollFreeActivate=function(field){setTimeout(function(){Field.activate(field);},1);}
+Ajax.InPlaceEditor=Class.create();Ajax.InPlaceEditor.defaultHighlightColor="#FFFF99";Ajax.InPlaceEditor.prototype={initialize:function(element,url,options){this.url=url;this.element=$(element);this.options=Object.extend({paramName:"value",okButton:true,okText:"ok",cancelLink:true,cancelText:"cancel",savingText:"Saving...",clickToEditText:"Click to edit",okText:"ok",rows:1,onComplete:function(transport,element){new Effect.Highlight(element,{startcolor:this.options.highlightcolor});},onFailure:function(transport){alert("Error communicating with the server: "+transport.responseText.stripTags());},callback:function(form){return Form.serialize(form);},handleLineBreaks:true,loadingText:'Loading...',savingClassName:'inplaceeditor-saving',loadingClassName:'inplaceeditor-loading',formClassName:'inplaceeditor-form',highlightcolor:Ajax.InPlaceEditor.defaultHighlightColor,highlightendcolor:"#FFFFFF",externalControl:null,submitOnBlur:false,ajaxOptions:{},evalScripts:false},options||{});if(!this.options.formId&&this.element.id){this.options.formId=this.element.id+"-inplaceeditor";if($(this.options.formId)){this.options.formId=null;}}
+if(this.options.externalControl){this.options.externalControl=$(this.options.externalControl);}
+this.originalBackground=Element.getStyle(this.element,'background-color');if(!this.originalBackground){this.originalBackground="transparent";}
+this.element.title=this.options.clickToEditText;this.onclickListener=this.enterEditMode.bindAsEventListener(this);this.mouseoverListener=this.enterHover.bindAsEventListener(this);this.mouseoutListener=this.leaveHover.bindAsEventListener(this);Event.observe(this.element,'click',this.onclickListener);Event.observe(this.element,'mouseover',this.mouseoverListener);Event.observe(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.observe(this.options.externalControl,'click',this.onclickListener);Event.observe(this.options.externalControl,'mouseover',this.mouseoverListener);Event.observe(this.options.externalControl,'mouseout',this.mouseoutListener);}},enterEditMode:function(evt){if(this.saving)return;if(this.editing)return;this.editing=true;this.onEnterEditMode();if(this.options.externalControl){Element.hide(this.options.externalControl);}
+Element.hide(this.element);this.createForm();this.element.parentNode.insertBefore(this.form,this.element);if(!this.options.loadTextURL)Field.scrollFreeActivate(this.editField);if(evt){Event.stop(evt);}
+return false;},createForm:function(){this.form=document.createElement("form");this.form.id=this.options.formId;Element.addClassName(this.form,this.options.formClassName)
+this.form.onsubmit=this.onSubmit.bind(this);this.createEditField();if(this.options.textarea){var br=document.createElement("br");this.form.appendChild(br);}
+if(this.options.okButton){okButton=document.createElement("input");okButton.type="submit";okButton.value=this.options.okText;okButton.className='editor_ok_button';this.form.appendChild(okButton);}
+if(this.options.cancelLink){cancelLink=document.createElement("a");cancelLink.href="javascript:void(0)";cancelLink.appendChild(document.createTextNode(this.options.cancelText));cancelLink.onclick=this.onclickCancel.bind(this);cancelLink.className='editor_cancel';this.form.appendChild(cancelLink);}},hasHTMLLineBreaks:function(string){if(!this.options.handleLineBreaks)return false;return string.match(/<br/i)||string.match(/<p>/i);},convertHTMLLineBreaks:function(string){return string.replace(/<br>/gi,"\n").replace(/<br\/>/gi,"\n").replace(/<\/p>/gi,"\n").replace(/<p>/gi,"");},createEditField:function(){var text;if(this.options.loadTextURL){text=this.options.loadingText;}else{text=this.getText();}
+var obj=this;if(this.options.rows==1&&!this.hasHTMLLineBreaks(text)){this.options.textarea=false;var textField=document.createElement("input");textField.obj=this;textField.type="text";textField.name=this.options.paramName;textField.value=text;textField.style.backgroundColor=this.options.highlightcolor;textField.className='editor_field';var size=this.options.size||this.options.cols||0;if(size!=0)textField.size=size;if(this.options.submitOnBlur)
+textField.onblur=this.onSubmit.bind(this);this.editField=textField;}else{this.options.textarea=true;var textArea=document.createElement("textarea");textArea.obj=this;textArea.name=this.options.paramName;textArea.value=this.convertHTMLLineBreaks(text);textArea.rows=this.options.rows;textArea.cols=this.options.cols||40;textArea.className='editor_field';if(this.options.submitOnBlur)
+textArea.onblur=this.onSubmit.bind(this);this.editField=textArea;}
+if(this.options.loadTextURL){this.loadExternalText();}
+this.form.appendChild(this.editField);},getText:function(){return this.element.innerHTML;},loadExternalText:function(){Element.addClassName(this.form,this.options.loadingClassName);this.editField.disabled=true;new Ajax.Request(this.options.loadTextURL,Object.extend({asynchronous:true,onComplete:this.onLoadedExternalText.bind(this)},this.options.ajaxOptions));},onLoadedExternalText:function(transport){Element.removeClassName(this.form,this.options.loadingClassName);this.editField.disabled=false;this.editField.value=transport.responseText.stripTags();Field.scrollFreeActivate(this.editField);},onclickCancel:function(){this.onComplete();this.leaveEditMode();return false;},onFailure:function(transport){this.options.onFailure(transport);if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;this.oldInnerHTML=null;}
+return false;},onSubmit:function(){var form=this.form;var value=this.editField.value;this.onLoading();if(this.options.evalScripts){new Ajax.Request(this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this),asynchronous:true,evalScripts:true},this.options.ajaxOptions));}else{new Ajax.Updater({success:this.element,failure:null},this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this)},this.options.ajaxOptions));}
+if(arguments.length>1){Event.stop(arguments[0]);}
+return false;},onLoading:function(){this.saving=true;this.removeForm();this.leaveHover();this.showSaving();},showSaving:function(){this.oldInnerHTML=this.element.innerHTML;this.element.innerHTML=this.options.savingText;Element.addClassName(this.element,this.options.savingClassName);this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);},removeForm:function(){if(this.form){if(this.form.parentNode)Element.remove(this.form);this.form=null;}},enterHover:function(){if(this.saving)return;this.element.style.backgroundColor=this.options.highlightcolor;if(this.effect){this.effect.cancel();}
+Element.addClassName(this.element,this.options.hoverClassName)},leaveHover:function(){if(this.options.backgroundColor){this.element.style.backgroundColor=this.oldBackground;}
+Element.removeClassName(this.element,this.options.hoverClassName)
+if(this.saving)return;this.effect=new Effect.Highlight(this.element,{startcolor:this.options.highlightcolor,endcolor:this.options.highlightendcolor,restorecolor:this.originalBackground});},leaveEditMode:function(){Element.removeClassName(this.element,this.options.savingClassName);this.removeForm();this.leaveHover();this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);if(this.options.externalControl){Element.show(this.options.externalControl);}
+this.editing=false;this.saving=false;this.oldInnerHTML=null;this.onLeaveEditMode();},onComplete:function(transport){this.leaveEditMode();this.options.onComplete.bind(this)(transport,this.element);},onEnterEditMode:function(){},onLeaveEditMode:function(){},dispose:function(){if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;}
+this.leaveEditMode();Event.stopObserving(this.element,'click',this.onclickListener);Event.stopObserving(this.element,'mouseover',this.mouseoverListener);Event.stopObserving(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.stopObserving(this.options.externalControl,'click',this.onclickListener);Event.stopObserving(this.options.externalControl,'mouseover',this.mouseoverListener);Event.stopObserving(this.options.externalControl,'mouseout',this.mouseoutListener);}}};Ajax.InPlaceCollectionEditor=Class.create();Object.extend(Ajax.InPlaceCollectionEditor.prototype,Ajax.InPlaceEditor.prototype);Object.extend(Ajax.InPlaceCollectionEditor.prototype,{createEditField:function(){if(!this.cached_selectTag){var selectTag=document.createElement("select");var collection=this.options.collection||[];var optionTag;collection.each(function(e,i){optionTag=document.createElement("option");optionTag.value=(e instanceof Array)?e[0]:e;if((typeof this.options.value=='undefined')&&((e instanceof Array)?this.element.innerHTML==e[1]:e==optionTag.value))optionTag.selected=true;if(this.options.value==optionTag.value)optionTag.selected=true;optionTag.appendChild(document.createTextNode((e instanceof Array)?e[1]:e));selectTag.appendChild(optionTag);}.bind(this));this.cached_selectTag=selectTag;}
+this.editField=this.cached_selectTag;if(this.options.loadTextURL)this.loadExternalText();this.form.appendChild(this.editField);this.options.callback=function(form,value){return"value="+encodeURIComponent(value);}}});Form.Element.DelayedObserver=Class.create();Form.Element.DelayedObserver.prototype={initialize:function(element,delay,callback){this.delay=delay||0.5;this.element=$(element);this.callback=callback;this.timer=null;this.lastValue=$F(this.element);Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));},delayedListener:function(event){if(this.lastValue==$F(this.element))return;if(this.timer)clearTimeout(this.timer);this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);this.lastValue=$F(this.element);},onTimerEvent:function(){this.timer=null;this.callback(this.element,$F(this.element));}};if(!Control)var Control={};Control.Slider=Class.create();Control.Slider.prototype={initialize:function(handle,track,options){var slider=this;if(handle instanceof Array){this.handles=handle.collect(function(e){return $(e)});}else{this.handles=[$(handle)];}
+this.track=$(track);this.options=options||{};this.axis=this.options.axis||'horizontal';this.increment=this.options.increment||1;this.step=parseInt(this.options.step||'1');this.range=this.options.range||$R(0,1);this.value=0;this.values=this.handles.map(function(){return 0});this.spans=this.options.spans?this.options.spans.map(function(s){return $(s)}):false;this.options.startSpan=$(this.options.startSpan||null);this.options.endSpan=$(this.options.endSpan||null);this.restricted=this.options.restricted||false;this.maximum=this.options.maximum||this.range.end;this.minimum=this.options.minimum||this.range.start;this.alignX=parseInt(this.options.alignX||'0');this.alignY=parseInt(this.options.alignY||'0');this.trackLength=this.maximumOffset()-this.minimumOffset();this.handleLength=this.isVertical()?(this.handles[0].offsetHeight!=0?this.handles[0].offsetHeight:this.handles[0].style.height.replace(/px$/,"")):(this.handles[0].offsetWidth!=0?this.handles[0].offsetWidth:this.handles[0].style.width.replace(/px$/,""));this.active=false;this.dragging=false;this.disabled=false;if(this.options.disabled)this.setDisabled();this.allowedValues=this.options.values?this.options.values.sortBy(Prototype.K):false;if(this.allowedValues){this.minimum=this.allowedValues.min();this.maximum=this.allowedValues.max();}
+this.eventMouseDown=this.startDrag.bindAsEventListener(this);this.eventMouseUp=this.endDrag.bindAsEventListener(this);this.eventMouseMove=this.update.bindAsEventListener(this);this.handles.each(function(h,i){i=slider.handles.length-1-i;slider.setValue(parseFloat((slider.options.sliderValue instanceof Array?slider.options.sliderValue[i]:slider.options.sliderValue)||slider.range.start),i);Element.makePositioned(h);Event.observe(h,"mousedown",slider.eventMouseDown);});Event.observe(this.track,"mousedown",this.eventMouseDown);Event.observe(document,"mouseup",this.eventMouseUp);Event.observe(document,"mousemove",this.eventMouseMove);this.initialized=true;},dispose:function(){var slider=this;Event.stopObserving(this.track,"mousedown",this.eventMouseDown);Event.stopObserving(document,"mouseup",this.eventMouseUp);Event.stopObserving(document,"mousemove",this.eventMouseMove);this.handles.each(function(h){Event.stopObserving(h,"mousedown",slider.eventMouseDown);});},setDisabled:function(){this.disabled=true;},setEnabled:function(){this.disabled=false;},getNearestValue:function(value){if(this.allowedValues){if(value>=this.allowedValues.max())return(this.allowedValues.max());if(value<=this.allowedValues.min())return(this.allowedValues.min());var offset=Math.abs(this.allowedValues[0]-value);var newValue=this.allowedValues[0];this.allowedValues.each(function(v){var currentOffset=Math.abs(v-value);if(currentOffset<=offset){newValue=v;offset=currentOffset;}});return newValue;}
+if(value>this.range.end)return this.range.end;if(value<this.range.start)return this.range.start;return value;},setValue:function(sliderValue,handleIdx){if(!this.active){this.activeHandleIdx=handleIdx||0;this.activeHandle=this.handles[this.activeHandleIdx];this.updateStyles();}
+handleIdx=handleIdx||this.activeHandleIdx||0;if(this.initialized&&this.restricted){if((handleIdx>0)&&(sliderValue<this.values[handleIdx-1]))
+sliderValue=this.values[handleIdx-1];if((handleIdx<(this.handles.length-1))&&(sliderValue>this.values[handleIdx+1]))
+sliderValue=this.values[handleIdx+1];}
+sliderValue=this.getNearestValue(sliderValue);this.values[handleIdx]=sliderValue;this.value=this.values[0];this.handles[handleIdx].style[this.isVertical()?'top':'left']=this.translateToPx(sliderValue);this.drawSpans();if(!this.dragging||!this.event)this.updateFinished();},setValueBy:function(delta,handleIdx){this.setValue(this.values[handleIdx||this.activeHandleIdx||0]+delta,handleIdx||this.activeHandleIdx||0);},translateToPx:function(value){return Math.round(((this.trackLength-this.handleLength)/(this.range.end-this.range.start))*(value-this.range.start))+"px";},translateToValue:function(offset){return((offset/(this.trackLength-this.handleLength)*(this.range.end-this.range.start))+this.range.start);},getRange:function(range){var v=this.values.sortBy(Prototype.K);range=range||0;return $R(v[range],v[range+1]);},minimumOffset:function(){return(this.isVertical()?this.alignY:this.alignX);},maximumOffset:function(){return(this.isVertical()?(this.track.offsetHeight!=0?this.track.offsetHeight:this.track.style.height.replace(/px$/,""))-this.alignY:(this.track.offsetWidth!=0?this.track.offsetWidth:this.track.style.width.replace(/px$/,""))-this.alignY);},isVertical:function(){return(this.axis=='vertical');},drawSpans:function(){var slider=this;if(this.spans)
+$R(0,this.spans.length-1).each(function(r){slider.setSpan(slider.spans[r],slider.getRange(r))});if(this.options.startSpan)
+this.setSpan(this.options.startSpan,$R(0,this.values.length>1?this.getRange(0).min():this.value));if(this.options.endSpan)
+this.setSpan(this.options.endSpan,$R(this.values.length>1?this.getRange(this.spans.length-1).max():this.value,this.maximum));},setSpan:function(span,range){if(this.isVertical()){span.style.top=this.translateToPx(range.start);span.style.height=this.translateToPx(range.end-range.start+this.range.start);}else{span.style.left=this.translateToPx(range.start);span.style.width=this.translateToPx(range.end-range.start+this.range.start);}},updateStyles:function(){this.handles.each(function(h){Element.removeClassName(h,'selected')});Element.addClassName(this.activeHandle,'selected');},startDrag:function(event){if(Event.isLeftClick(event)){if(!this.disabled){this.active=true;var handle=Event.element(event);var pointer=[Event.pointerX(event),Event.pointerY(event)];var track=handle;if(track==this.track){var offsets=Position.cumulativeOffset(this.track);this.event=event;this.setValue(this.translateToValue((this.isVertical()?pointer[1]-offsets[1]:pointer[0]-offsets[0])-(this.handleLength/2)));var offsets=Position.cumulativeOffset(this.activeHandle);this.offsetX=(pointer[0]-offsets[0]);this.offsetY=(pointer[1]-offsets[1]);}else{while((this.handles.indexOf(handle)==-1)&&handle.parentNode)
+handle=handle.parentNode;if(this.handles.indexOf(handle)!=-1){this.activeHandle=handle;this.activeHandleIdx=this.handles.indexOf(this.activeHandle);this.updateStyles();var offsets=Position.cumulativeOffset(this.activeHandle);this.offsetX=(pointer[0]-offsets[0]);this.offsetY=(pointer[1]-offsets[1]);}}}
+Event.stop(event);}},update:function(event){if(this.active){if(!this.dragging)this.dragging=true;this.draw(event);if(navigator.appVersion.indexOf('AppleWebKit')>0)window.scrollBy(0,0);Event.stop(event);}},draw:function(event){var pointer=[Event.pointerX(event),Event.pointerY(event)];var offsets=Position.cumulativeOffset(this.track);pointer[0]-=this.offsetX+offsets[0];pointer[1]-=this.offsetY+offsets[1];this.event=event;this.setValue(this.translateToValue(this.isVertical()?pointer[1]:pointer[0]));if(this.initialized&&this.options.onSlide)
+this.options.onSlide(this.values.length>1?this.values:this.value,this);},endDrag:function(event){if(this.active&&this.dragging){this.finishDrag(event,true);Event.stop(event);}
+this.active=false;this.dragging=false;},finishDrag:function(event,success){this.active=false;this.dragging=false;this.updateFinished();},updateFinished:function(){if(this.initialized&&this.options.onChange)
+this.options.onChange(this.values.length>1?this.values:this.value,this);this.event=null;}};if(!("console"in window)||!("firebug"in console)){var names=["log","debug","info","warn","error","assert","dir","dirxml","group","groupEnd","time","timeEnd","count","trace","profile","profileEnd"];window.console={};for(var i=0;i<names.length;++i){window.console[names[i]]=function(){};}}
+var ua=navigator.userAgent.toLowerCase();var isIE=ua.indexOf("msie")>-1,isIE7=ua.indexOf("msie 7")>-1;if(isIE&&!isIE7){try{document.execCommand("BackgroundImageCache",false,true);}catch(e){}}
+if(typeof Jx=='undefined'){var Jx={};Jx.COMBINED_CSS=true;var aScripts=document.getElementsByTagName('SCRIPT');for(var i=0;i<aScripts.length;i++){var s=aScripts[i].src;var n=s.indexOf('lib/jx');if(n!=-1){Jx.baseURL=s.substring(0,n);break;}}}
+Jx.importRules={};Jx.importRulesIE={};Jx.addStyleSheet=function(styleSheet,ieOnly){if(ieOnly){this.importRulesIE[styleSheet]=styleSheet;}else{this.importRules[styleSheet]=styleSheet;}};Jx.addStyleSheet('reset.css');Jx.applyPNGFilter=function(o){var t=Jx.baseURL+"images/a_pixel.png";if(o.src!=t){var s=o.src;o.src=t;o.runtimeStyle.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')";}};Jx.imgQueue=[];Jx.imgLoaded={};Jx.imagesLoading=0;Jx.addToImgQueue=function(obj){if(Jx.imgLoaded[obj.src]){obj.domElement.src=obj.src;}else{Jx.imgQueue.push(obj);Jx.imgLoaded[obj.src]=true;}
+Jx.checkImgQueue();};Jx.checkImgQueue=function(){while(Jx.imagesLoading<2&&Jx.imgQueue.length>0){Jx.loadNextImg();}};Jx.loadNextImg=function(){var obj=Jx.imgQueue.shift();if(obj){++Jx.imagesLoading;obj.domElement.onload=function(){--Jx.imagesLoading;Jx.checkImgQueue();};obj.domElement.onerror=function(){--Jx.imagesLoading;Jx.checkImgQueue();};obj.domElement.src=obj.src;}};Jx.Listener=Class.create();Jx.Listener.prototype={addListener:function(list,obj){list.push(obj);},removeListener:function(list,obj){for(var i=0;i<list.length;i++){if(list[i]==obj){list.splice(i,1);break;}}},processEvent:function(list,fnName,obj){list.each(function(o){if(o[fnName]){o[fnName](obj);}});}};Jx.UniqueId=Class.create();Jx.UniqueId.prototype={uniqueIdRefs:null,initUniqueId:function(){this.uniqueIdRefs=[];},deregisterIds:function(){this.uniqueIdRefs.length=0;},registerIds:function(aIds,domObj){if(aIds.indexOf(domObj.id)!=-1){this.uniqueIdRefs[domObj.id]=domObj;}
+for(var i=0;i<domObj.childNodes.length;i++){this.registerIds(aIds,domObj.childNodes[i]);}},getObj:function(id){return this.uniqueIdRefs[id]||null;}};Jx.Action=Class.create();Jx.Action.prototype={pcl:null,enabled:null,initialize:function(f){this.pcl=[];this.enabled=true;this.actionPerformed=f;},addPropertyChangeListener:function(obj){this.addListener(this.pcl,obj);},removePropertyChangeListener:function(obj){this.removeListener(this.pcl,obj);},isEnabled:function(){return this.enabled;},setEnabled:function(b){if(this.enabled==b){return;}
+this.enabled=b;this.processEvent(this.pcl,'propertyChanged',this);},bindTo:function(item){this.addPropertyChangeListener(item);item.addActionListener(this);},unbindFrom:function(item){this.removePropertyChangeListener(item);item.removeActionListener(this);},actionPerformed:function(obj){alert('actionPerformed');}};Object.extend(Jx.Action.prototype,Jx.Listener.prototype);Object.extend(Element,{getBoxSizing:function(elem){var result='content-box';elem=$(elem);if(elem.currentStyle||window.opera){var cm=document["compatMode"];if(cm=="BackCompat"||cm=="QuirksMode"){result='border-box';}else{result='content-box';}}else{if(arguments.length==0){node=document.documentElement;}
+var sizing=Element.getStyle(elem,"-moz-box-sizing");if(!sizing){sizing=Element.getStyle(elem,"box-sizing");}
+result=(sizing?sizing:'content-box');}
+return result;},getContentBoxSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var w=elem.offsetWidth;var h=elem.offsetHeight;var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);Element.toggleMeasurable(elem);w=w-padding.left-padding.right-border.left-border.right;h=h-padding.bottom-padding.top-border.bottom-border.top;return{width:w,height:h};},getBorderBoxSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var w=elem.offsetWidth;var h=elem.offsetHeight;Element.toggleMeasurable(elem);return{width:w,height:h};},setContentBoxSize:function(elem,size){elem=$(elem);if(Element.getBoxSizing(elem)=='border-box'){var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);if(typeof size.width!='undefined'){var width=(size.width+padding.left+padding.right+border.left+border.right);if(width<0){width=0;}
+elem.style.width=width+'px';}
+if(typeof size.height!='undefined'){var height=(size.height+padding.top+padding.bottom+border.top+border.bottom);if(height<0){height=0;}
+elem.style.height=height+'px';}}else{if(typeof size.width!='undefined'){elem.style.width=size.width+'px';}
+if(typeof size.height!='undefined'){elem.style.height=size.height+'px';}}},setBorderBoxSize:function(elem,size){elem=$(elem);if(Element.getBoxSizing(elem)=='content-box'){var padding=Element.getPaddingSize(elem);var border=Element.getBorderSize(elem);var margin=Element.getMarginSize(elem);if(typeof size.width!='undefined'){var width=(size.width-padding.left-padding.right-border.left-border.right-margin.left-margin.right);if(width<0){width=0;}
+elem.style.width=width+'px';}
+if(typeof size.height!='undefined'){var height=(size.height-padding.top-padding.bottom-border.top-border.bottom-margin.top-margin.bottom);if(height<0){height=0;}
+elem.style.height=height+'px';}}else{if(typeof size.width!='undefined'&&size.width>=0){elem.style.width=size.width+'px';}
+if(typeof size.height!='undefined'&&size.height>=0){elem.style.height=size.height+'px';}}},getPaddingSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'padding-left'));var t=Element.getNumber(Element.getStyle(elem,'padding-top'));var r=Element.getNumber(Element.getStyle(elem,'padding-right'));var b=Element.getNumber(Element.getStyle(elem,'padding-bottom'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getBorderSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'border-left-width'));var t=Element.getNumber(Element.getStyle(elem,'border-top-width'));var r=Element.getNumber(Element.getStyle(elem,'border-right-width'));var b=Element.getNumber(Element.getStyle(elem,'border-bottom-width'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getMarginSize:function(elem){elem=$(elem);Element.toggleMeasurable(elem);var l=Element.getNumber(Element.getStyle(elem,'margin-left'));var t=Element.getNumber(Element.getStyle(elem,'margin-top'));var r=Element.getNumber(Element.getStyle(elem,'margin-right'));var b=Element.getNumber(Element.getStyle(elem,'margin-bottom'));Element.toggleMeasurable(elem);return{left:l,top:t,right:r,bottom:b};},getNumber:function(n){var result=n==null||isNaN(parseInt(n))?0:parseInt(n);return result;},getPageDimensions:function(){return{width:Element.getInsideWindowWidth(),height:Element.getInsideWindowHeight()};},getInsideWindowWidth:function(){if(window.innerWidth){return window.innerWidth;}else if(document.compatMode&&document.compatMode.indexOf("CSS1")>=0){return document.body.parentElement.clientWidth;}else if(document.body&&document.body.clientWidth){return document.body.clientWidth;}
+return 0;},getInsideWindowHeight:function(){if(window.innerHeight){return window.innerHeight;}else if(document.compatMode&&document.compatMode.indexOf("CSS1")>=0){return document.body.parentElement.clientHeight;}else if(document.body&&document.body.clientHeight){return document.body.clientHeight;}
+return 0;},toggleMeasurable:function(elem){if(Element.getStyle(elem,'display')=='none'){elem.old={};elem.old.display=elem.style.display;elem.old.visibility=elem.style.visibility;elem.old.position=elem.style.position;elem.style.position='absolute';elem.style.visibility='hidden';elem.style.display='block';}else{if(elem.old){elem.style.display=elem.old.display;elem.style.visibility=elem.old.visibility;elem.style.position=elem.old.position;elem.old=null;}}}});Jx.ContentLoader=Class.create();Jx.ContentLoader.prototype={bContentLoaded:false,contentLoaded:function(element,options,r){element.innerHTML=r.responseText;this.bContentLoaded=true;if(options.onContentLoaded){options.onContentLoaded();}},contentLoadFailed:function(options,r){this.bContentLoaded=false;if(options.onContentLoadFailed){options.onContentLoadFailed();}},loadContent:function(element,options){options=options||{};element=$(element);if(options.content){element.appendChild(options.content);this.bContentLoaded=true;}else if(options.contentID){var c=$(options.contentID);if(c){element.appendChild(c);this.bContentLoaded=true;}}else if(options.contentURL){this.bContentLoaded=false;var ts='';var a=new Ajax.Request(options.contentURL,Object.extend({method:'get',onSuccess:this.contentLoaded.bind(this,element,options),onFailure:this.contentLoadFailed.bind(this,options),requestHeaders:['If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT'],parameters:ts}));}else if(options.contentHTML){element.innerHTML=options.contentHTML;this.bContentLoaded=true;}else{this.bContentLoaded=true;}
+if(this.bContentLoaded&&options.onContentLoaded){options.onContentLoaded();}}};Jx.addStyleSheet('button/button.css');Jx.Button=Class.create();Object.extend(Jx.Button.prototype,Jx.Listener.prototype);Object.extend(Jx.Button.prototype,{al:null,domObj:null,enabled:null,initialize:function(action,options){options=options||{};this.al=[];this.action=action;var imgPath=(options.imgPath||options.image)||'';var tooltip=options.tooltip||'';var label=options.label||'';this.disabledClass=options.disabledClass||'jxDisabled';this.domA=document.createElement('a');this.domA.className='jxButton';this.domA.href='javascript:void(0)';this.domA.onclick=this.onclick.bindAsEventListener(this);this.domA.title=tooltip;this.domA.alt=tooltip;var span=document.createElement('span');span.className='jxButtonSpan';this.domA.appendChild(span);this.domLabel=document.createElement('span');this.domLabel.className='jxButtonContent';this.domLabel.innerHTML=label!=''?label:'&nbsp;';span.appendChild(this.domLabel);if(label!=''){Element.addClassName(this.domLabel,'jxButtonLabel');}
+if(imgPath!=''){Element.addClassName(this.domLabel,'jxButtonIcon');this.domLabel.style.backgroundImage="url("+imgPath+")";}
+if(this.action){this.action.bindTo(this);this.propertyChanged(this.action);}
+this.domObj=document.createElement('div');this.domObj.className='jxButtonContainer';this.domObj.appendChild(this.domA);if(options.halign&&options.halign=='left'){Element.addClassName(this.domObj,'jxButtonContentLeft');}
+if(options.valign&&options.valign=='top'){Element.addClassName(this.domObj,'jxButtonContentTop');}},onclick:function(){if(this.enabled){this.processEvent(this.al,'actionPerformed',this);}
+return false;},addActionListener:function(obj){this.addListener(this.al,obj);},removeActionListener:function(obj){this.removeListener(this.al,obj);},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj,this.disabledClass);}else{Element.addClassName(this.domObj,this.disabledClass);}},setImage:function(path){if(this.domImg){this.domImg.src=path;}},setLabel:function(label){if(this.domLabel){this.domLabel.innerHTML=label;}},setTooltip:function(tooltip){if(this.domImg){this.domImg.title=tooltip;this.domImg.alt=tooltip;}}});Jx.Button.Flyout=Class.create();Object.extend(Jx.Button.Flyout.prototype,Jx.Button.prototype);Object.extend(Jx.Button.Flyout.prototype,Jx.ContentLoader.prototype);Object.extend(Jx.Button.Flyout.prototype,{content:null,initialize:function(options){options=options||{};var a=new Jx.Action(this.show.bind(this));Jx.Button.prototype.initialize.apply(this,[a,options]);Element.addClassName(this.domA,'jxButtonFlyout');this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.content=document.createElement('div');Element.addClassName(this.content,'jxFlyout');this.loadContent(this.content,options);this.domObj.appendChild(this.content);this.content.style.display='none';this.keypressWatcher=this.keypressHandler.bindAsEventListener(this);this.hideWatcher=this.clickHandler.bindAsEventListener(this);},show:function(){if(!window.opera&&!this.iframe.parentNode){this.content.appendChild(this.iframe);}
+this.content.style.display='block';Event.observe(window,'keypress',this.keypressWatcher);Event.observe(document,'click',this.hideWatcher);},hide:function(){this.content.style.display='none';Event.stopObserving(window,'keypress',this.keypressWatcher);Event.stopObserving(document,'click',this.hideWatcher);},clickHandler:function(e){var elm=Event.element(e);if(!Element.descendantOf(elm,this.domObj.parentNode)){this.hide();}},keypressHandler:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.hide();}}});Jx.Button.Multi=Class.create();Jx.Button.Multi.prototype={activeButton:null,buttons:null,initialize:function(){this.buttons=[];this.content=document.createElement('div');this.tb=new Jx.Toolbar(this.content,'right');this.flyout=new Jx.Button.Flyout({content:this.content,label:'&nbsp;'});Element.addClassName(this.flyout.domObj.firstChild,'jxButtonMulti');this.domObj=document.createElement('div');this.buttonContainer=document.createElement('div');this.buttonContainer.className='jxButtonMultiContainer';this.domObj.appendChild(this.buttonContainer);this.domObj.appendChild(this.flyout.domObj);},add:function(){for(var i=0;i<arguments.length;i++){var theButton=arguments[i];var action=new Jx.Action(this.setButton.bind(this,theButton));var button=new Jx.Button(action,{});var click=button.domA.onclick;button.domObj=theButton.domObj.cloneNode(true);button.domObj.onclick=click;this.tb.add(button);if(!this.activeButton){this.buttonContainer.appendChild(theButton.domObj);this.activeButton=theButton;}}},setActiveButton:function(button){while(this.buttonContainer.childNodes.length>0){this.buttonContainer.removeChild(this.buttonContainer.firstChild);}
+this.buttonContainer.appendChild(button.domObj);},setButton:function(button){this.setActiveButton(button);button.onclick();this.flyout.hide();}};Jx.Button.Picker=Class.create();Object.extend(Jx.Button.Picker.prototype,Jx.Button.Flyout.prototype);Object.extend(Jx.Button.Picker.prototype,{ul:null,selectedItem:null,initialize:function(){Jx.Button.Flyout.prototype.initialize.apply(this,arguments);this.ul=document.createElement('ul');this.content.appendChild(this.ul);Element.removeClassName(this.domLabel,'jxButtonEmptyLabel');},add:function(){for(var i=0;i<arguments.length;i++){var thing=arguments[i];if(thing.domObj){thing=thing.domObj;}
+var li=document.createElement('li');var a=document.createElement('a');li.appendChild(a);if(typeof(thing)=='string'){a.innerHTML=thing;}else{a.appendChild(thing);}
+this.ul.appendChild(li);if(!this.selectedItem){this.updateButton(a);}}},clickHandler:function(e){var elm=Event.element(e);if(!Element.descendantOf(elm,this.domObj.parentNode)){this.hide();return;}
+var a=Event.findElement(e,'A');if(a&&Element.descendantOf(a,this.ul)){this.updateButton(a);this.hide();}},updateButton:function(a){while(this.domLabel.childNodes.length>0){this.domLabel.removeChild(this.domLabel.firstChild);}
+this.domLabel.appendChild(a.firstChild.cloneNode(true));this.selectedItem=a.firstChild;}});Jx.addStyleSheet('color/color.css');Jx.ColorPanel=Class.create();Jx.ColorPanel.prototype={domObj:null,color:null,alpha:null,ccl:null,hexColors:['00','33','66','99','CC','FF'],initialize:function(options){options=options||{};this.keypressWatcher=this.keypressHandler.bind(this);this.ccl=[];this.color=options.color||'#000000';this.alpha=options.alpha||1;this.domObj=document.createElement('div');this.domObj.className='jxColorPanel';var top=document.createElement('div');top.className='jxColorBar';var d=document.createElement('div');d.className='jxColorPreview';this.selectedSwatch=document.createElement('div');d.appendChild(this.selectedSwatch);top.appendChild(d);this.colorInputLabel=document.createElement('label');this.colorInputLabel.className='jxColorLabel';this.colorInputLabel.innerHTML='#';top.appendChild(this.colorInputLabel);this.colorInput=document.createElement('input');this.colorInput.className='jxHexInput';this.colorInput.type='text';this.colorInput.maxLength=6;Event.observe(this.colorInput,'keyup',this.colorChanged.bind(this));Event.observe(this.colorInput,'blur',this.colorChanged.bind(this));Event.observe(this.colorInput,'change',this.colorChanged.bind(this));top.appendChild(this.colorInput);this.alphaLabel=document.createElement('label');this.alphaLabel.className='jxAlphaLabel';this.alphaLabel.innerHTML='alpha (%)';top.appendChild(this.alphaLabel);this.alphaInput=document.createElement('input');this.alphaInput.className='jxAlphaInput';this.alphaInput.type='text';this.alphaInput.maxLength=3;Event.observe(this.alphaInput,'keyup',this.alphaChanged.bind(this));top.appendChild(this.alphaInput);this.domObj.appendChild(top);var a=document.createElement('a');a.href="javascript:void(0)";a.className='jxColorClose';a.alt='Close';a.title='Close';Event.observe(a,'click',this.hide.bind(this));img=document.createElement('img');img.className='png24';img.src=Jx.baseURL+'images/close.png';a.appendChild(img);this.domObj.appendChild(a);d=document.createElement('div');d.className='jxClearer';this.domObj.appendChild(d);var swatchClick=this.swatchClick.bindAsEventListener(this);var swatchOver=this.swatchOver.bindAsEventListener(this);var table=document.createElement('table');table.className='jxColorGrid';var tbody=document.createElement('tbody');table.appendChild(tbody);for(var i=0;i<12;i++){var tr=document.createElement('tr');for(var j=-3;j<18;j++){var bSkip=false;var r,g,b;if(j<0){if(j==-3||j==-1){r=g=b=0;bSkip=true;}else{if(i<6){r=g=b=i;}else{if(i==6){r=5;g=0;b=0;}else if(i==7){r=0;g=5;b=0;}else if(i==8){r=0;g=0;b=5;}else if(i==9){r=5;g=5;b=0;}else if(i==10){r=0;g=5;b=5;}else if(i==11){r=5;g=0;b=5;}}}}else{r=parseInt(i/6)*3+parseInt(j/6);g=j%6;b=i%6;}
+var bgColor='#'+this.hexColors[r]+this.hexColors[g]+this.hexColors[b];var td=document.createElement('td');if(!bSkip){td.style.backgroundColor=bgColor;var a=document.createElement('a');if((r>2&&g>2)||(r>2&&b>2)||(g>2&&b>2)){a.className='colorSwatch borderBlack';}else{a.className='colorSwatch borderWhite';}
+a.href='#';a.title=bgColor;a.alt=bgColor;a.swatchColor=bgColor;a.onmouseover=swatchOver;a.onclick=swatchClick;td.appendChild(a);}else{var span=document.createElement('span');td.className='emptyCell';td.appendChild(span);}
+tr.appendChild(td);}
+tbody.appendChild(tr);}
+this.domObj.appendChild(table);var d=document.createElement('div');d.className='jxColorPreview';this.previewSwatch=document.createElement('div');d.appendChild(this.previewSwatch);this.previewSwatch.style.backgroundColor=this.color;this.domObj.appendChild(d);this.previewLabel=document.createElement('label');this.previewLabel.className='jxColorLabel';this.previewLabel.innerHTML=this.color;this.domObj.appendChild(this.previewLabel);d=document.createElement('div');d.className='jxClearer';this.domObj.appendChild(d);this.updateSelected();},swatchOver:function(e){var a=Event.element(e);this.previewSwatch.style.backgroundColor=a.swatchColor;this.previewLabel.innerHTML=a.swatchColor;},swatchClick:function(e){var a=Event.element(e);this.color=a.swatchColor;this.updateSelected();this.hide();},colorChanged:function(){var color=this.colorInput.value;if(color.substring(0,1)=='#'){color=color.substring(1);}
+if(color.toLowerCase().match(/^[0-9a-f]{6}$/)){this.color='#'+color.toUpperCase();this.updateSelected();}},alphaChanged:function(){var alpha=this.alphaInput.value;if(alpha.match(/^[0-9]{1,3}$/)){this.alpha=parseFloat(alpha/100);this.updateSelected();}},setColor:function(color){this.colorInput.value=color;this.colorChanged();},setAlpha:function(alpha){this.alphaInput.value=alpha;this.alphaChanged();},updateSelected:function(){this.selectedSwatch.style.backgroundColor=this.color;this.colorInput.value=this.color.substring(1);this.alphaInput.value=parseInt(this.alpha*100);if(this.alpha<1){this.selectedSwatch.style.opacity=this.alpha;this.selectedSwatch.style.filter='Alpha(opacity='+(this.alpha*100)+')';}else{this.selectedSwatch.style.opacity='';this.selectedSwatch.style.filter='';}
+this.processEvent(this.ccl,'colorChanged',this);},show:function(){this.domObj.style.display='block';Event.observe(window,'keypress',this.keypressWatcher);},hide:function(){this.domObj.style.display='none';Event.stopObserving(window,'keypress',this.keypressWatcher);},keypressHandler:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.hide();}},addColorChangeListener:function(obj){this.addListener(this.ccl,obj);},removeColorChangeListener:function(obj){this.removeListener(this.ccl,obj);}};Object.extend(Jx.ColorPanel.prototype,Jx.Listener.prototype);Jx.Button.Color=Class.create();Object.extend(Jx.Button.Color.prototype,Jx.Button.Flyout.prototype);Object.extend(Jx.Button.Color.prototype,{colorPanel:[],swatch:null,color:null,alpha:null,ccl:null,initialize:function(options){options=options||{};options.label=options.label||'&nbsp;';this.color=options.color||'#000000';this.alpha=options.alpha||100;this.ccl=[];if(this.colorPanel.length==0){this.colorPanel[0]=new Jx.ColorPanel();}
+var d=document.createElement('div');d.className='jxColorButtonPreview';this.selectedSwatch=document.createElement('div');d.appendChild(this.selectedSwatch);Jx.Button.Flyout.prototype.initialize.apply(this,[options]);Element.addClassName(this.domObj.firstChild,'jxButtonColor');this.domObj.firstChild.firstChild.insertBefore(d,this.domObj.firstChild.firstChild.firstChild);this.updateSwatch();},show:function(){if(this.colorPanel[0].currentButton){this.colorPanel[0].currentButton.hide();}
+this.colorPanel[0].currentButton=this;this.colorPanel[0].addColorChangeListener(this);this.content.appendChild(this.colorPanel[0].domObj);this.colorPanel[0].domObj.style.display='block';Jx.Button.Flyout.prototype.show.apply(this,arguments);this.colorPanel[0].setColor(this.color);this.colorPanel[0].setAlpha(this.alpha);},hide:function(){this.colorPanel[0].removeColorChangeListener(this);Jx.Button.Flyout.prototype.hide.apply(this,arguments);this.colorPanel[0].currentButton=null;},setColor:function(color){this.color=color;this.updateSwatch();},setAlpha:function(alpha){this.alpha=alpha;this.updateSwatch();},colorChanged:function(panel){this.color=panel.color;this.alpha=panel.alpha*100;this.updateSwatch();this.processEvent(this.ccl,'colorChanged',this);},updateSwatch:function(){this.selectedSwatch.style.backgroundColor=this.color;if(this.alpha<100){this.selectedSwatch.style.opacity=this.alpha/100;this.selectedSwatch.style.filter='Alpha(opacity='+(this.alpha)+')';}else{this.selectedSwatch.style.opacity='';this.selectedSwatch.style.filter='';}},addColorChangeListener:function(obj){this.addListener(this.ccl,obj);},removeColorChangeListener:function(obj){this.removeListener(this.ccl,obj);}});Jx.addStyleSheet('dialog/dialog.css');Jx.Dialog=Class.create();Jx.Dialog.prototype={onClose:null,onOpen:null,onChange:null,title:null,content:null,action:null,values:null,actions:null,handler:null,bContentLoaded:null,zIndex:[101],stack:[],blanket:null,firstShow:true,modal:true,initialize:function(options){this.initUniqueId();this.values={};this.actions={};this.handler=options.handler?options.handler:null;if(options.onChange){this.onChange=options.onChange;}
+if(options.onClose){this.onClose=options.onClose;}
+if(options.onOpen){this.onOpen=options.onOpen;}
+if(options.onContentLoaded){this.onContentLoaded=options.onContentLoaded;}
+this.imageBaseUrl=options.imageBaseUrl||Jx.baseURL+"/images/";if(this.imageBaseUrl.slice(-1)!='/'){this.imageBaseUrl+='/';}
+this.modal=typeof options.modal=='undefined'?true:options.modal;var w=options.width||250;var h=options.height||250;var b=(typeof options.bottom!='undefined')?options.bottom:null;var r=(typeof options.right!='undefined')?options.right:null;var t=(typeof options.top!='undefined')?options.top:(b!=null?null:0);var l=(typeof options.left!='undefined')?options.left:(r!=null?null:0);this.blanket=document.createElement('div');this.blanket.className='jxDialogModal';this.blanket.style.display='none';if(!window.opera&&this.modal){var iframe=document.createElement('iframe');iframe.className='jxDialogShim';iframe.scrolling='no';iframe.frameborder=0;this.blanket.appendChild(iframe);if(options.parentObj){$(options.parentObj).appendChild(this.blanket);}else{document.body.appendChild(this.blanket);}}
+this.dragHandle=document.createElement('div');this.dragHandle.innerHTML=options.title||'&nbsp;';this.dragHandle.style.width='100%';var domObj=document.createElement('div');domObj.className='jxDialogContainer';this.domObj=domObj;if(options.id){domObj.id=options.id;}
+var dialogObj=document.createElement('div');dialogObj.className='jxDialog';this.innerDialogObj=dialogObj;var titleObj=document.createElement('div');titleObj.className='jxDialogTitle';this.title=titleObj;titleObj.appendChild(this.dragHandle);titleObj.style.visibility='hidden';document.getElementsByTagName('BODY')[0].appendChild(titleObj);this.titleHeight=Element.getBorderBoxSize(titleObj).height;document.getElementsByTagName('BODY')[0].removeChild(titleObj);titleObj.style.visibility='';var contentObj=document.createElement('div');contentObj.className='jxDialogContent';this.content=contentObj;domObj.appendChild(dialogObj);dialogObj.appendChild(titleObj);dialogObj.appendChild(contentObj);new Jx.Layout(dialogObj,{width:w,height:h});new Jx.Layout(titleObj,{top:0,left:0,right:0,bottom:null,height:this.titleHeight,width:null});this.actionHeight=0;if(options.buttons){var actionObj=document.createElement('div');actionObj.className='jxDialogAction';actionObj.style.visibility='hidden';document.getElementsByTagName('BODY')[0].appendChild(actionObj);this.actionHeight=parseInt(Element.getStyle(actionObj,'height'));document.getElementsByTagName('BODY')[0].removeChild(actionObj);actionObj.style.visibility='';dialogObj.appendChild(actionObj);new Jx.Layout(actionObj,{top:null,left:0,right:0,bottom:0,height:this.actionHeight,width:null});this.action=actionObj;this.setButtons(options.buttons);}
+new Jx.Layout(contentObj,{top:this.titleHeight,left:0,right:0,bottom:this.actionHeight});var atag=document.createElement('a');atag.href='javascript:void(0)';atag.className='jxDialogCloseButton';atag.onclick=this.close.bindAsEventListener(this);var close=document.createElement('img');if(options.closeImg){close.src=options.closeImg;}
+else{close.src=this.imageBaseUrl+'icon_close.png';}
+close.alt='Close Dialog';close.title='Close Dialog';atag.appendChild(close);titleObj.appendChild(atag);if(options.helpID||options.helpHTML||options.helpURL||options.help){var atag2=document.createElement('a');atag2.href='javascript:void(0)';atag2.className='jxDialogHelpButton';atag2.onclick=this.toggleHelp.bindAsEventListener(this);var help=document.createElement('img');help.src=this.imageBaseUrl+'icon_quickhelp.png';help.alt='Help';help.title='Help';atag2.appendChild(help);titleObj.appendChild(atag2);this.help=document.createElement('div');this.help.className='jxDialogHelp';this.help.style.display='none';this.help.isVisible=false;var helpOpts={};helpOpts.contentID=options.helpID;helpOpts.content=options.help;helpOpts.contentURL=options.helpURL;helpOpts.contentHTML=options.helpHTML;helpOpts.onContentLoaded=this.onHelpContentLoaded.bind(this);this.loadContent(this.help,helpOpts);dialogObj.appendChild(this.help);}
+var contentOpts={};contentOpts.contentID=options.contentID;contentOpts.content=options.content;contentOpts.contentURL=options.contentURL;contentOpts.contentHTML=options.contentHTML;contentOpts.onContentLoaded=this.onDialogContentLoaded.bind(this);this.loadContent(contentObj,contentOpts);dialogObj.style.visibility='hidden';document.body.appendChild(dialogObj);dialogObj.resize();this.dialogBoxSize=Element.getBorderBoxSize(dialogObj);this.dialogBoxMargins=Element.getMarginSize(dialogObj);var containerSize={width:this.dialogBoxSize.width,height:this.dialogBoxSize.height};containerSize.width+=this.dialogBoxMargins.left+this.dialogBoxMargins.right;containerSize.height+=this.dialogBoxMargins.top+this.dialogBoxMargins.bottom;document.body.removeChild(dialogObj);dialogObj.style.visibility='';domObj.appendChild(dialogObj);domObj.style.display="none";Element.setBorderBoxSize(domObj,{width:(containerSize.width),height:(containerSize.height)});domObj.style.position='absolute';if(t!=null){domObj.style.top=(t)+'px';}else{domObj.style.bottom=(b)+'px';}
+if(l!=null){domObj.style.left=(l)+'px';}else{domObj.style.right=(r)+'px';}
+if(options.parentObj){$(options.parentObj).appendChild(domObj);}else{document.body.appendChild(domObj);}
+this.DTOffset=0;this.DBOffset=0;this.DROffset=0;this.DLOffset=0;this.decorationOffsets={top:0,right:0,bottom:0,left:0};var imgContainer=document.createElement('div');imgContainer.className='jxDialogBgTL';var img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_tl.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.top+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.left+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgTR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_tr.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.top+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.right+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgBR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_br.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.bottom+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.right+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgBL';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_bl.png';img.className='png24';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.decorationOffsets.bottom+=parseInt(Element.getStyle(img,'width'));this.decorationOffsets.left+=parseInt(Element.getStyle(img,'height'));imgContainer=document.createElement('div');imgContainer.className='jxDialogBgT';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_t.png';img.className='png24';img.style.width=containerSize.width-this.decorationOffsets.top+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.topImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgB';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_b.png';img.className='png24';img.style.width=containerSize.width-this.decorationOffsets.bottom+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.bottomImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgL';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_l.png';img.className='png24';img.style.height=containerSize.height-this.decorationOffsets.left+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.leftImg=img;imgContainer=document.createElement('div');imgContainer.className='jxDialogBgR';img=document.createElement('img');img.src=this.imageBaseUrl+'dialog_glow_r.png';img.className='png24';img.style.height=containerSize.height-this.decorationOffsets.right+'px';imgContainer.appendChild(img);domObj.appendChild(imgContainer);this.rightImg=img;Event.observe(domObj,'mousedown',this.mouseDown.bind(this));Event.observe(this.title,'mousedown',this.mouseDown.bind(this));if(options.resizeable){this.resizeHandle=document.createElement('div');this.resizeHandle.className='jxDialogResize';this.resizeHandle.style.position='absolute';this.domObj.appendChild(this.resizeHandle);this.resizeHandleSize={width:parseInt(Element.getStyle(this.resizeHandle,'width')),height:parseInt(Element.getStyle(this.resizeHandle,'height'))};this.resizeHandle.style.top=(containerSize.height-this.resizeHandleSize.height)+'px';this.resizeHandle.style.left=(containerSize.width-this.resizeHandleSize.width)+'px';new Draggable(this.resizeHandle,{starteffect:false,endeffect:false,change:this.ondrag.bind(this),zindex:0});}
+this.bOpen=false;},mouseDown:function(){for(var i=0;i<this.stack.length;i++){if(this.stack[i]==this){this.stack.splice(i,1);this.stack.push(this);}}
+for(var i=0;i<this.stack.length;i++){this.stack[i].domObj.style.zIndex=(101+i);}},ondrag:function(obj){this.mouseDown();var delta=obj.currentDelta();var deltaX=delta[0]+this.resizeHandleSize.width;var deltaY=delta[1]+this.resizeHandleSize.height;this.resize({width:deltaX,height:deltaY});},resize:function(newSize){this.innerDialogObj.resize(newSize);if(newSize.width){var outerWidth=newSize.width;Element.setBorderBoxSize(this.domObj,{width:outerWidth});Element.setBorderBoxSize(this.topImg,{width:outerWidth-this.decorationOffsets.top});Element.setBorderBoxSize(this.bottomImg,{width:outerWidth-this.decorationOffsets.bottom});}
+if(newSize.height){var outerHeight=newSize.height;Element.setBorderBoxSize(this.domObj,{height:outerHeight});Element.setBorderBoxSize(this.leftImg,{height:outerHeight-this.decorationOffsets.left});Element.setBorderBoxSize(this.rightImg,{height:outerHeight-this.decorationOffsets.right});if(this.help){Element.setBorderBoxSize(this.help,{height:newSize.height-this.titleHeight});}}},setTitle:function(title){this.title.childNodes[0].innerHTML=title;},setButtons:function(buttons){this.action.innerHTML='';for(var i=0;i<buttons.length;i++){var button=document.createElement('input');button.id=buttons[i];button.type='button';button.className='normalButton';button.name=buttons[i];button.value=buttons[i];button.onclick=this.buttonHandler.bind(this,button);this.action.appendChild(button);this.uniqueIdRefs[button.id]=button;}},processInputs:function(obj){for(var i=0;i<obj.childNodes.length;i++){var node=obj.childNodes[i];if(node.tagName=='INPUT'||node.tagName=='SELECT'||node.tagName=='TEXTAREA'){if(node.type=='button'){this.actions[node.id]=node;node.onclick=this.buttonHandler.bind(this,node);}else{this.values[node.id]=node;if(this.onChange){node.onchange=this.onChangeHandler.bind(this,node);}}}else{if(node.childNodes){this.processInputs(node);}}}},buttonHandler:function(input,event){if(this.handler){this.handler(input.value,this);}},onChangeHandler:function(input,event){if(this.onChange){this.onChange(input,this);}},getValue:function(name){var result='';var input=this.values[name];if(input){switch(input.tagName){case'INPUT':result=input.value;break;case'SELECT':result=input.options[input.selectedIndex].value;}}
+return result;},setValue:function(name,value){if(typeof this.values[name]!='undefined'){if(this.values[name].type=='text'||this.values[name].type=='hidden'){this.values[name].value=value;}}},show:function(){this.stack.push(this);if(this.modal){this.blanket.style.zIndex=this.zIndex[0]++;this.blanket.style.visibility='visible';this.blanket.style.display='block';}
+this.domObj.style.zIndex=this.zIndex[0]++;Effect.Appear(this.domObj,{duration:0.1});this.domObj.style.display='block';new Draggable(this.domObj,{handle:this.dragHandle,starteffect:false,endeffect:false});this.content.resize({forceResize:this.firstShow});this.firstShow=false;},hide:function(){for(var i=0;i<this.stack.length;i++){if(this.stack[i]==this){this.stack.splice(i,1);}}
+this.zIndex[0]--;Effect.Fade(this.domObj,{duration:0.3});if(this.modal){this.blanket.style.visibility='hidden';this.zIndex[0]--;}},open:function(){if(!this.bOpen){this.bOpen=true;}
+if(this.bContentLoaded){this.show();if(this.onOpen)this.onOpen();}},close:function(){this.bOpen=false;this.hide();if(this.onClose)this.onClose();},onDialogContentLoaded:function(){this.processInputs(this.content);if(this.onContentLoaded){this.onContentLoaded(this);}
+if(this.bOpen){this.open();this.bOpen=false;}},onHelpContentLoaded:function(){var img=document.createElement('img');img.className='jxDialogHelpCloseButton png24';img.src=this.imageBaseUrl+'help_close.png';img.onclick=this.toggleHelp.bind(this);img.alt='Close Help';img.title='Close Help';this.help.appendChild(img);},toggleHelp:function(){if(this.help.isVisible){Effect.Fade(this.help,{duration:0.3});}else{var actionSize=this.action?Element.getBorderBoxSize(this.action):{width:0,height:0};var contentSize=Element.getBorderBoxSize(this.content);Element.setBorderBoxSize(this.help,{height:contentSize.height+actionSize.height});Effect.Appear(this.help,{duration:0.3});}
+this.help.isVisible=!this.help.isVisible;}};Object.extend(Jx.Dialog.prototype,Jx.UniqueId.prototype);Object.extend(Jx.Dialog.prototype,Jx.ContentLoader.prototype);Jx.addStyleSheet('grid/grid.css');Jx.Grid=Class.create();Jx.Grid.prototype={domObj:null,model:null,initialize:function(domObj,options){this.domObj=$(domObj);if(!this.domObj.jxLayout){new Jx.Layout(this.domObj);}
+this.domObj.jxLayout.addSizeChangeListener(this);options=options||{};this.rowColObj=document.createElement('div');this.rowColObj.className='jxGridContainer';this.colObj=document.createElement('div');this.colObj.className='jxGridContainer';this.colTable=document.createElement('table');this.colTable.className='jxGridTable';this.colTableHead=document.createElement('thead');this.colTable.appendChild(this.colTableHead);this.colTableBody=document.createElement('tbody');this.colTable.appendChild(this.colTableBody);this.colObj.appendChild(this.colTable);this.rowObj=document.createElement('div');this.rowObj.className='jxGridContainer';this.rowTable=document.createElement('table');this.rowTable.className='jxGridTable';this.rowTableHead=document.createElement('thead');this.rowTable.appendChild(this.rowTableHead);this.rowObj.appendChild(this.rowTable);this.gridObj=document.createElement('div');this.gridObj.className='jxGridContainer';this.gridObj.style.overflow='scroll';this.gridTable=document.createElement('table');this.gridTable.className='jxGridTable';this.gridTableBody=document.createElement('tbody');this.gridTable.appendChild(this.gridTableBody);this.gridObj.appendChild(this.gridTable);this.domObj.appendChild(this.rowColObj);this.domObj.appendChild(this.rowObj);this.domObj.appendChild(this.colObj);this.domObj.appendChild(this.gridObj);this.bAlternateRowColors=options.alternateRowColors||false;this.showRowHeader=options.rowHeaders||false;this.showColumnHeader=options.columnHeaders||false;this.rowSelection=options.rowSelection||false;this.cellSelection=options.cellSelection||false;Event.observe(this.gridObj,'scroll',this.onScroll.bind(this));Event.observe(this.gridObj,'click',this.onClickGrid.bindAsEventListener(this));Event.observe(this.rowObj,'click',this.onClickRowHeader.bindAsEventListener(this));Event.observe(this.colObj,'click',this.onClickColumnHeader.bindAsEventListener(this));Event.observe(this.gridObj,'mousemove',this.onMouseMoveGrid.bindAsEventListener(this));Event.observe(this.rowObj,'mousemove',this.onMouseMoveRowHeader.bindAsEventListener(this));Event.observe(this.colObj,'mousemove',this.onMouseMoveColumnHeader.bindAsEventListener(this));},onScroll:function(){this.colObj.scrollLeft=this.gridObj.scrollLeft;this.rowObj.scrollTop=this.gridObj.scrollTop;},sizeChanged:function(){this.resize();},resize:function(){if(!this.model){return;}
+var colHeight=this.showColumnHeader?this.model.getColumnHeaderHeight():1;var rowWidth=this.showRowHeader?this.model.getRowHeaderWidth():1;var size=Element.getContentBoxSize(this.domObj);this.rowColObj.style.width=(rowWidth-1)+'px';this.rowColObj.style.height=(colHeight-1)+'px';this.rowObj.style.top=(colHeight)+'px';this.rowObj.style.left='0px';this.rowObj.style.width=(rowWidth-1)+'px';this.rowObj.style.height=(size.height-colHeight-1)+'px';this.colObj.style.top='0px';this.colObj.style.left=(rowWidth)+'px';this.colObj.style.width=(size.width-rowWidth-1)+'px';this.colObj.style.height=(colHeight-1)+'px';this.gridObj.style.top=(colHeight)+'px';this.gridObj.style.left=(rowWidth)+'px';this.gridObj.style.width=(size.width-rowWidth-1)+'px';this.gridObj.style.height=(size.height-colHeight-1)+'px';},setModel:function(model){if(this.model){this.model.removeGridListener(this);}
+this.model=model;if(this.model){this.domObj.jxLayout.resize();this.model.addGridListener(this);this.createGrid();this.resize();}else{this.destroyGrid();}},destroyGrid:function(){var n=this.colTableHead.cloneNode(false);this.colTable.replaceChild(n,this.colTableHead);this.colTableHead=n;n=this.colTableBody.cloneNode(false);this.colTable.replaceChild(n,this.colTableBody);this.colTableBody=n;n=this.rowTableHead.cloneNode(false);this.rowTable.replaceChild(n,this.rowTableHead);this.rowTableHead=n;n=this.gridTableBody.cloneNode(false);this.gridTable.replaceChild(n,this.gridTableBody);this.gridTableBody=n;},createGrid:function(){this.destroyGrid();if(this.model){var model=this.model;var nColumns=model.getColumnCount();var nRows=model.getRowCount();if(this.showColumnHeader){var colHeight=model.getColumnHeaderHeight();var trHead=document.createElement('tr');this.colTableHead.appendChild(trHead);var trBody=document.createElement('tr');this.colTableBody.appendChild(trBody);var th=document.createElement('th');th.style.width='0px';th.style.height='0px';trHead.appendChild(th);th=th.cloneNode(true);th.style.height=(colHeight)+'px';trBody.appendChild(th);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);th=document.createElement('th');th.className='jxGridColHeadHide';th.style.width=(colWidth)+'px';var p=document.createElement('p');p.style.height='0px';p.style.width=(colWidth)+'px';th.appendChild(p);trHead.appendChild(th);th=document.createElement('th');th.className='jxGridColHead';th.innerHTML=model.getColumnHeaderHTML(i);trBody.appendChild(th);}
+var th=document.createElement('th');th.style.width='1000px';th.style.height='0px';trHead.appendChild(th);th=th.cloneNode(true);th.style.height=(colHeight-1)+'px';th.className='jxGridColHead';trBody.appendChild(th);}
+if(this.showRowHeader){var rowWidth=model.getRowHeaderWidth();var tr=document.createElement('tr');var td=document.createElement('td');td.style.width='0px';td.style.height='0px';tr.appendChild(td);var th=document.createElement('th');th.style.width=(rowWidth)+'px';th.style.height='0px';tr.appendChild(th);this.rowTableHead.appendChild(tr);for(var i=0;i<nRows;i++){var rowHeight=model.getRowHeight(i);var tr=document.createElement('tr');var td=document.createElement('td');td.className='jxGridRowHeadHide';td.style.width='0px';td.style.height=(rowHeight)+'px';var p=document.createElement('p');p.style.width='0px';p.style.height=(rowHeight)+'px';td.appendChild(p);tr.appendChild(td);var th=document.createElement('th');th.className='jxGridRowHead';th.innerHTML=model.getRowHeaderHTML(i);tr.appendChild(th);this.rowTableHead.appendChild(tr);}
+var tr=document.createElement('tr');var td=document.createElement('td');td.style.width='0px';td.style.height='1000px';tr.appendChild(td);var th=document.createElement('th');th.style.width=(rowWidth)+'px';th.style.height='1000px';th.className='jxGridRowHead';tr.appendChild(th);this.rowTableHead.appendChild(tr);}
+var colHeight=model.getColumnHeaderHeight();var trBody=document.createElement('tr');this.gridTableBody.appendChild(trBody);var td=document.createElement('td');td.style.width='0px';td.style.height='0px';trBody.appendChild(td);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);td=document.createElement('td');td.className='jxGridColHeadHide';td.style.width=(colWidth)+'px';var p=document.createElement('p');p.style.height='0px';p.style.width=(colWidth)+'px';td.appendChild(p);trBody.appendChild(td);}
+for(var j=0;j<nRows;j++){var rowHeight=model.getRowHeight(j);var actualRowHeight=rowHeight;var tr=document.createElement('tr');this.gridTableBody.appendChild(tr);var td=document.createElement('td');td.className='jxGridRowHeadHide';td.style.width='0px';td.style.height=(rowHeight)+'px';var p=document.createElement('p');p.style.height=(rowHeight)+'px';td.appendChild(p);tr.appendChild(td);for(var i=0;i<nColumns;i++){var colWidth=model.getColumnWidth(i);td=document.createElement('td');td.className='jxGridCell';td.innerHTML=model.getValueAt(j,i);tr.appendChild(td);var tdSize=Element.getDimensions(td);if(tdSize.height>actualRowHeight){actualRowHeight=tdSize.height;}}
+if(document.all){actualRowHeight-=1;}
+if(this.showRowHeader){this.setRowHeaderHeight(j,actualRowHeight);}
+if(this.bAlternateRowColors){tr.className=(j%2)?'jxGridRowOdd':'jxGridRowEven';}else{tr.className='jxGridRowAll';}}}},setRowHeaderHeight:function(row,height){this.rowTableHead.childNodes[row+1].childNodes[0].childNodes[0].style.height=(height)+'px';},gridChanged:function(model,row,col,value){if(this.model==model){this.gridObj.childNodes[row].childNodes[col].innerHTML=value;}},prelightRowHeader:function(row){var cell=(row>=0&&row<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[row+1].cells[1]:null;if(this.prelitRowHeader!=cell){if(this.prelitRowHeader){Element.removeClassName(this.prelitRowHeader,'jxGridRowHeaderPrelight');}
+this.prelitRowHeader=cell;if(this.prelitRowHeader){Element.addClassName(this.prelitRowHeader,'jxGridRowHeaderPrelight');}}},prelightColumnHeader:function(col){if(this.colTableBody.rows.length==0){return;}
+var cell=(col>=0&&col<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[col+1]:null;if(this.prelitColumnHeader!=cell){if(this.prelitColumnHeader){Element.removeClassName(this.prelitColumnHeader,'jxGridColumnHeaderPrelight');}
+this.prelitColumnHeader=cell;if(this.prelitColumnHeader){Element.addClassName(this.prelitColumnHeader,'jxGridColumnHeaderPrelight');}}},prelightRow:function(row){var tr=(row>=0&&row<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[row+1]:null;if(this.prelitRow!=row){if(this.prelitRow){Element.removeClassName(this.prelitRow,'jxGridRowPrelight');}
+this.prelitRow=tr;if(this.prelitRow&&!Element.hasClassName(this.prelitRow,'jxGridRowSelected')){this.prelightRowHeader(row);Element.addClassName(this.prelitRow,'jxGridRowPrelight');}}},prelightColumn:function(col){this.prelightColumnHeader(col);},prelightCell:function(row,col){var td=(row>=0&&col>=0&&row<this.gridTableBody.rows.length-1&&col<this.gridTableBody.rows[row+1].cells.length-1)?this.gridTableBody.rows[row+1].cells[col+1]:null;if(this.prelitCell!=td){if(this.prelitCell){Element.removeClassName(this.prelitCell,'jxGridCellPrelight');}
+this.prelitCell=td;if(this.prelitCell){Element.addClassName(this.prelitCell,'jxGridCellPrelight');this.prelightRow(row);this.prelightColumn(col);}}},selectCell:function(row,col){var td=(row>=0&&col>=0&&row<this.gridTableBody.rows.length-1&&col<this.gridTableBody.rows[row+1].cells.length-1)?this.gridTableBody.rows[row+1].cells[col+1]:null;if(!td){return;}
+if(this.selectedCell){Element.addClassName(this.selectedCell,'jxGridCellSelected');}else{Element.removeClassName(this.selectedCell,'jxGridCellSelected');}},selectRowHeader:function(row,selected){var cell=(row>=0&&row<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[row+1].cells[1]:null;if(!cell){return;}
+if(selected){Element.addClassName(cell,'jxGridRowHeaderSelected');}else{Element.removeClassName(cell,'jxGridRowHeaderSelected');}},selectRow:function(row,selected){var tr=(row>=0&&row<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[row+1]:null;if(tr){if(selected){Element.addClassName(tr,'jxGridRowSelected');}else{Element.removeClassName(tr,'jxGridRowSelected');}}
+this.selectRowHeader(row,selected);},selectColumnHeader:function(col,selected){if(this.colTableBody.rows.length==0){return;}
+var cell=(col>=0&&col<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[col+1]:null;if(cell==null){return;}
+if(selected){Element.addClassName(cell,'jxGridColumnHeaderSelected');}else{Element.removeClassName(cell,'jxGridColumnHeaderSelected');}},selectColumn:function(col,selected){if(col>=0&&col<this.gridTable.rows[0].cells.length){if(selected){for(var i=0;i<this.gridTable.rows.length;i++){Element.removeClassName(this.gridTable.rows[i].cells[this.selectedColumn+1],'jxGridColumnSelected');}}else{for(var i=0;i<this.gridTable.rows.length;i++){Element.addClassName(this.gridTable.rows[i].cells[col+1],'jxGridColumnSelected');}}}
+this.selectColumnHeader(col,selected);},onMouseMoveGrid:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightCell(rc.row,rc.column);},onMouseMoveRowHeader:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightRow(rc.row);},onMouseMoveColumnHeader:function(e){var rc=this.getRowColumnFromEvent(e);this.prelightColumn(rc.column);},onClickGrid:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.cellSelected){this.model.cellSelected(this,rc.row,rc.column);}},onClickRowHeader:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.rowSelected){this.model.rowSelected(this,rc.row);}},onClickColumnHeader:function(e){var rc=this.getRowColumnFromEvent(e);if(this.model.columnSelected){this.model.columnSelected(this,rc.column);}},getRowColumnFromEvent:function(e){var td=Event.element(e);if(td.tagName!='TD'&&td.tagName!='TH'){return{row:-1,column:-1};}
+var tr=td.parentNode;var col=td.cellIndex-1;var row=tr.rowIndex-1;if(col==-1){for(var i=0;i<tr.childNodes.length;i++){if(tr.childNodes[i]==td){col=i-1;break;}}}
+return{row:row,column:col};}};Jx.Layout=Class.create();Jx.Layout.prototype={scl:null,initialize:function(domObj,options){options=options||{};this.options=new Jx.Constraint(options);this.domObj=$(domObj);this.domObj.resize=this.resize.bind(this);this.domObj.style.position=this.options.position;this.domObj.jxLayout=this;if(this.domObj.parentNode&&this.domObj.parentNode.tagName=='BODY'){Event.observe(window,'resize',this.windowResize.bind(this));}
+this.scl=[];},windowResize:function(){if(this.resizeTimer){window.clearTimeout(this.resizeTimer);this.resizeTimer=null;}
+this.resizeTimer=window.setTimeout(this.resize.bind(this),250);},resize:function(options){this.resizeTimer=null;var needsResize=false;if(options){for(var i in options){if(this.options[i]!=options[i]){needsResize=true;this.options[i]=options[i];}}
+if(options.forceResize){needsResize=true;}}
+var parentSize;if(this.domObj.parentNode.tagName=='BODY'){parentSize=Element.getPageDimensions();}else{parentSize=Element.getContentBoxSize(this.domObj.parentNode);}
+if(this.lastParentSize&&!needsResize){needsResize=(this.lastParentSize.width!=parentSize.width||this.lastParentSize.height!=parentSize.height);}else{needsResize=true;}
+this.lastParentSize=parentSize;if(!needsResize){return;}
+var l,t,w,h;if(this.options.left!=null){l=this.options.left;if(this.options.right==null){if(this.options.width==null){w=parentSize.width-l;if(w<this.options.minWidth){w=this.options.minWidth;}
+if(this.options.maxWidth>=0&&w>this.options.maxWidth){w=this.options.maxWidth;}}else{w=this.options.width;}}else{if(this.options.width==null){w=parentSize.width-l-this.options.right;if(w<this.options.minWidth){w=this.options.minWidth;}
+if(this.options.maxWidth>=0&&w>this.options.maxWidth){w=this.options.maxWidth;}}else{w=this.options.width;}}}else{if(this.options.right==null){if(this.options.width==null){l=0;w=parentSize.width;if(this.options.maxWidth>=0&&w>this.options.maxWidth){l=l+parseInt(w-this.options.maxWidth)/2;w=this.options.maxWidth;}}else{w=this.options.width;l=parseInt((parentSize.width-w)/2);if(l<0){l=0;}}}else{if(this.options.width!=null){w=this.options.width;l=parentSize.width-w-this.options.right;if(l<0){l=0;}}else{l=0;w=parentSize.width-this.options.right;if(w<this.options.minWidth){w=this.options.minWidth;}
+if(this.options.maxWidth>=0&&w>this.options.maxWidth){l=w-this.options.maxWidth-this.options.right;w=this.options.maxWidth;}}}}
+if(this.options.top!=null){t=this.options.top;if(this.options.bottom==null){if(this.options.height==null){h=parentSize.height-t;if(h<this.options.minHeight){h=this.options.minHeight;}
+if(this.options.maxHeight>=0&&h>this.options.maxHeight){h=this.options.maxHeight;}}else{h=this.options.height;if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=h-this.options.maxHeight;h=this.options.maxHeight;}}}else{if(this.options.height==null){h=parentSize.height-t-this.options.bottom;if(h<this.options.minHeight){h=this.options.minHeight;}
+if(this.options.maxHeight>=0&&h>this.options.maxHeight){h=this.options.maxHeight;}}else{h=this.options.height;}}}else{if(this.options.bottom==null){if(this.options.height==null){t=0;h=parentSize.height;if(h<this.options.minHeight){h=this.options.minHeight;}
+if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=parseInt((parentSize.height-this.options.maxHeight)/2);h=this.options.maxHeight;}}else{h=this.options.height;t=parseInt((parentSize.height-h)/2);if(t<0){t=0;}}}else{if(this.options.height!=null){h=this.options.height;t=parentSize.height-h-this.options.bottom;if(t<0){t=0;}}else{t=0;h=parentSize.height-this.options.bottom;if(h<this.options.minHeight){h=this.options.minHeight;}
+if(this.options.maxHeight>=0&&h>this.options.maxHeight){t=parentSize.height-this.options.maxHeight-this.options.bottom;h=this.options.maxHeight;}}}}
+this.domObj.style.position=this.options.position;if(this.options.position=='absolute'){var padding=Element.getPaddingSize(this.domObj.parentNode);this.domObj.style.left=(l+padding.left)+'px';this.domObj.style.top=(t+padding.top)+'px';Element.setBorderBoxSize(this.domObj,{width:w,height:h});}else{var sizeOpts={width:w};if(this.options.height){sizeOpts.height=this.options.height;}
+Element.setBorderBoxSize(this.domObj,sizeOpts);}
+var o={forceResize:options?options.forceResize:false};for(var i=0;i<this.domObj.childNodes.length;i++){var c=this.domObj.childNodes[i];if(c.resize){c.resize(o);}}
+this.processEvent(this.scl,'sizeChanged',this);},addSizeChangeListener:function(obj){this.addListener(this.scl,obj);},removeSizeChangeListener:function(o){this.removeListener(this.scl,o);}};Object.extend(Jx.Layout.prototype,Jx.Listener.prototype);Jx.Constraint=Class.create();Jx.Constraint.prototype={position:'absolute',left:0,right:0,top:0,bottom:0,width:null,height:null,minWidth:0,minHeight:0,maxWidth:-1,maxHeight:-1,initialize:function(o){for(var i in o){this[i]=o[i];}}};Jx.addStyleSheet('menu/menu.css');Jx.addStyleSheet('button/button.css');Jx.MenuItem=Class.create();Object.extend(Jx.MenuItem.prototype,Jx.Listener.prototype);Object.extend(Jx.MenuItem.prototype,{al:null,domObj:null,parent:null,enabled:false,button:null,initialize:function(action,options){this.initializeItem(options);action.bindTo(this);this.propertyChanged(action);},initializeItem:function(options){if(!options.image){options.image=Jx.baseURL+'images/a_pixel.png';}
+if(!options.label){options.label='&nbsp;';}
+this.label=options.label||'&nbsp;';this.image=options.image||null;this.al=[];this.domObj=document.createElement('li');this.domObj.className='jxMenuItem';var action=new Jx.Action(this.processActionEvent.bindAsEventListener(this))
+this.button=new Jx.Button(action,options);Event.observe(this.button.domObj,'mouseover',this.onmouseover.bindAsEventListener(this),true);this.domObj.appendChild(this.button.domObj);},setParent:function(obj){this.parent=obj;},hide:function(){},show:function(){},addActionListener:function(obj){this.addListener(this.al,obj);},removeActionListener:function(obj){this.removeListener(this.al,obj);},processActionEvent:function(e){if(this.enabled){this.processEvent(this.al,'actionPerformed',this);if(this.parent&&this.parent.deactivate){this.parent.deactivate(e);}}},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj.childNodes[0].childNodes[0],'jxDisabled');}else{Element.addClassName(this.domObj.childNodes[0].childNodes[0],'jxDisabled');}},onmouseover:function(e){var target=Event.element(e);if(this.parent&&this.parent.setVisibleItem){this.parent.setVisibleItem(this);}
+this.show();}});Jx.MenuSeparator=Class.create();Object.extend(Jx.MenuSeparator.prototype,{domObj:null,parent:null,initialize:function(){this.domObj=document.createElement('li');this.domObj.className='jxMenuItem';var span=document.createElement('span');span.className='jxMenuSeparator';span.innerHTML='&nbsp;';this.domObj.appendChild(span);},setParent:function(obj){this.parent=obj;},hide:function(){},show:function(){}});Jx.SubMenu=Class.create();Object.extend(Jx.SubMenu.prototype,Jx.MenuItem.prototype);Object.extend(Jx.SubMenu.prototype,{subDomObj:null,parent:null,visibleItem:null,items:null,initialize:function(options){this.open=false;this.items=[];this.initializeItem(options);Element.addClassName(this.domObj.childNodes[0].childNodes[0],'jxButtonSubMenu');this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.subDomObj=document.createElement('ul');this.subDomObj.className='jxSubMenu';this.subDomObj.style.display='none';this.domObj.appendChild(this.subDomObj);},setParent:function(obj){this.parent=obj;},show:function(){if(this.open||this.items.length==0){return;}
+this.open=true;this.subDomObj.style.display='block';if(!window.opera){this.subDomObj.childNodes[0].appendChild(this.iframe);var size=Element.getBorderBoxSize(this.subDomObj);this.iframe.style.width=size.width+"px";this.iframe.style.height=size.height+"px";}
+this.setActive(true);},hide:function(){if(!this.open){return;}
+this.open=false;for(var i=0;i<this.items.length;i++){this.items[i].hide();}
+this.subDomObj.style.display='none';if(!window.opera&&this.iframe.parentNode){this.subDomObj.childNodes[0].removeChild(this.iframe);}
+this.visibleItem=null;},add:function(){for(var i=0;i<arguments.length;i++){var item=arguments[i];this.items.push(item);item.setParent(this);this.subDomObj.appendChild(item.domObj);}},insertBefore:function(newItem,targetItem){var bInserted=false;for(var i=0;i<this.items.length;i++){if(this.items[i]==targetItem){this.items.splice(i,0,newItem);this.subDomObj.insertBefore(newItem.domObj,targetItem.domObj);bInserted=true;break;}}
+if(!bInserted){this.add(newItem);}},remove:function(item){for(var i=0;i<this.items.length;i++){if(this.items[i]==item){this.items.splice(i,1);this.subDomObj.removeChild(item.domObj);break;}}},processActionEvent:function(e){if(this.open){this.hide();}else{this.show();}
+return Event.stop(e);},deactivate:function(e){if(this.parent){this.parent.deactivate(e);}},isActive:function(){if(this.parent){return this.parent.isActive();}else{return false;}},setActive:function(isActive){if(this.parent&&this.parent.setActive){this.parent.setActive(isActive);}},setVisibleItem:function(obj){if(this.visibleItem!=obj){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide();}
+this.visibleItem=obj;this.visibleItem.show();}}});Jx.Menu=Class.create();Jx.Menu.prototype={domObj:null,buttonObj:null,subDomObj:null,items:null,menus:[],initialize:function(options){this.items=[];this.iframe=document.createElement('iframe');this.iframe.className='jxMenuShim';this.iframe.scrolling='no';this.iframe.frameborder=0;this.subDomObj=document.createElement('ul');this.subDomObj.className='jxMenu';this.subDomObj.style.display='none';if(options){this.domObj=document.createElement('li');var action=new Jx.Action(this.show.bind(this));this.button=new Jx.Button(action,options);Element.addClassName(this.button.domObj.firstChild,'jxButtonMenu');this.domObj.appendChild(this.button.domObj);Event.observe(this.domObj,'mouseover',this.onMouseOver.bindAsEventListener(this));this.domObj.appendChild(this.subDomObj);}
+this.hideWatcher=this.hide.bindAsEventListener(this);},add:function(){for(var i=0;i<arguments.length;i++){var item=arguments[i];this.items.push(item);item.setParent(this);this.subDomObj.appendChild(item.domObj);}},deactivate:function(){this.hide();},actionPerformed:function(){this.hide();},onMouseOver:function(e){if(this.menus[0]&&this.menus[0]!=this){this.show(e);}},hide:function(e){if(e){var root=Event.findElement(e,'LI');if(root==this.domObj){return;}}
+if(this.menus[0]&&this.menus[0]==this){this.menus[0]=null;}
+for(var i=0;i<this.items.length;i++){this.items[i].hide(e);}
+Event.stopObserving(document,'click',this.hideWatcher,true);this.subDomObj.style.display='none';},show:function(e){if(this.menus[0]&&this.menus[0]!=this){this.menus[0].hide(e);}
+if(this.items.length==0){return;}
+this.menus[0]=this;this.subDomObj.style.display='block';this.subDomObj.style.visibility='visible';if(!window.opera){this.subDomObj.childNodes[0].appendChild(this.iframe);var size=Element.getContentBoxSize(this.subDomObj);this.iframe.style.width=size.width+"px";this.iframe.style.height=size.height+"px";}
+Event.stop(e);Event.observe(document,'click',this.hideWatcher,true);},setVisibleItem:function(obj){if(this.visibleItem!=obj){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide();}
+this.visibleItem=obj;this.visibleItem.show();}}};Jx.ContextMenu=Class.create();Object.extend(Jx.ContextMenu.prototype,Jx.Menu.prototype);Object.extend(Jx.ContextMenu.prototype,{initialize:function(id){Jx.Menu.prototype.initialize.apply(this,[]);document.getElementsByTagName('BODY')[0].appendChild(this.subDomObj);if($(id)){$(id).oncontextmenu=this.show.bindAsEventListener(this);;}},show:function(e){this.subDomObj.style.left=Event.pointerX(e)+"px";this.subDomObj.style.top=Event.pointerY(e)+"px";Jx.Menu.prototype.show.apply(this,[e]);}});Jx.addStyleSheet('panel/panel.css');Jx.PanelManager=Class.create();Jx.PanelManager.prototype={panels:null,height:null,firstLayout:true,initialize:function(domObj,panels){this.domObj=$(domObj);this.panels=panels;var d=document.createElement('div');d.style.position='absolute';new Jx.Layout(d,{minHeight:0,maxHeight:0,height:0});var elements=[d];for(var i=0;i<this.panels.length;i++){elements.push(this.panels[i].domObj);}
+this.splitter=new Jx.Splitter(this.domObj,{splitInto:panels.length+1,layout:'vertical',elements:elements});this.splitter.sizeChanged=this.sizeChanged.bind(this);for(var i=0;i<this.panels.length;i++){var panel=this.panels[i];this.splitter.bars[i].appendChild(panel.title);this.splitter.bars[i].style.height=Element.getBorderBoxSize(panel.title).height+'px';Element.removeClassName(this.splitter.bars[i],'jxSplitterBar');Element.addClassName(this.splitter.bars[i],'jxPanelBar');panel.manager=this;}},sizeChanged:function(){if(this.firstLayout){if(Element.getBorderBoxSize(this.panels[0].title).height!=0){for(var i=0;i<this.splitter.bars.length;i++){var panel=this.panels[i];this.splitter.bars[i].style.height=Element.getBorderBoxSize(panel.title).height+'px';this.splitter.bars[i].size=null;}
+this.firstLayout=false;Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[]);}}else{Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[]);}},maximizePanel:function(panel){var h=Element.getContentBoxSize(this.domObj).height;var t=0;for(var i=1;i<this.splitter.elements.length;i++){var p=this.splitter.elements[i];t+=Element.getBorderBoxSize(p.leftBar).height;if(p!==panel.domObj){p.jxLayout.resize({top:t,height:p.jxLayout.options.minHeight,bottom:null});t+=p.jxLayout.options.minHeight;p.rightBar.style.top=t+'px';}else{break;}}
+b=h;for(var i=this.splitter.elements.length-1;i>0;i--){p=this.splitter.elements[i];if(p!==panel.domObj){b-=p.jxLayout.options.minHeight;p.jxLayout.resize({top:b,height:p.jxLayout.options.minHeight,bottom:null});b-=Element.getBorderBoxSize(p.leftBar).height;p.leftBar.style.top=b+'px';}else{break;}}
+panel.domObj.jxLayout.resize({top:t,height:b-t,bottom:null});}};Jx.Panel=Class.create();Jx.Panel.prototype={labelObj:null,state:'open',busyCount:null,bContentReady:null,onContentReady:null,initialize:function(options){this.initUniqueId();this.title=document.createElement('div');this.title.className="jxPanelTitle";this.title.style.height='22px';this.labelObj=document.createElement('span');this.labelObj.className='jxPanelLabel';this.labelObj.innerHTML=options.label?options.label:'empty';this.imageBaseUrl=options.imageBaseUrl||Jx.baseURL+'images/';var a,img;if(options.helpCallback){a=document.createElement('a');a.className='jxPanelHelp';a.href='javascript:void(0)';Event.observe(a,'click',options.helpCallback);img=document.createElement('img');img.src=this.imageBaseUrl+"help.png";img.alt='Help on this panel';img.title='Help on this panel';a.appendChild(img);this.title.appendChild(a);}
+a=document.createElement('a');a.className='jxPanelMaximize';a.href='javascript:void(0)';Event.observe(a,'click',this.maximize.bindAsEventListener(this));img=document.createElement('img');img.src=this.imageBaseUrl+"maximize.png";img.alt='Maximize Panel';img.title='Maximize Panel';a.appendChild(img);this.title.appendChild(a);a=document.createElement('a');a.className='jxPanelLoading';a.href='javascript:void(0)';img=document.createElement('img');img.src=this.imageBaseUrl+"loading.gif";img.alt='Loading Panel';img.title='Loading Panel';a.appendChild(img);this.loadingObj={};this.loadingObj.link=a;this.loadingObj.img=img;this.title.appendChild(this.loadingObj.link);this.title.appendChild(this.labelObj);Event.observe(this.title,'dblclick',this.maximize.bindAsEventListener(this));this.domObj=document.createElement('div');this.domObj.className='jxPanel';this.jxLayout=new Jx.Layout(this.domObj,options.constraint||{});this.jxLayout.addSizeChangeListener(this);var top=0;var bottom=0;if(options.menubar){this.menubar=options.menubar;this.domObj.appendChild(options.menubar);var h=Element.getBorderBoxSize(options.menubar).height;new Jx.Layout(this.menubar,{top:top,height:h});top+=h;}
+if(options.toolbar){this.toolbar=options.toolbar;this.domObj.appendChild(options.toolbar);var h=Element.getBorderBoxSize(options.toolbar).height;new Jx.Layout(this.toolbar,{top:top,height:h});}
+if(options.statusbar){this.statusbar=options.statusbar;this.domObj.appendChild(options.statusbar);var h=Element.getBorderBoxSize(options.statusbar).height;new Jx.Layout(this.statusbar,{bottom:bottom,height:h,top:null});bottom+=h;}
+this.content=document.createElement('div');Element.addClassName(this.content,'jxPanelContent');new Jx.Layout(this.content,{top:top,bottom:bottom});this.domObj.appendChild(this.content);this.loadContent(this.content,options);this.busyCount=0;this.bContentReady=false;},setLabel:function(s){this.labelObj.innerHTML=s;},getLabel:function(){return this.labelObj.innerHTML;},finalize:function(){this.domObj=null;this.deregisterIds();},maximize:function(){if(this.manager){this.manager.maximizePanel(this);}},setContent:function(html){this.content.innerHTML=html;this.bContentReady=true;},setContentURL:function(url){this.bContentReady=false;this.setBusy(true);if(arguments[1]){this.onContentReady=arguments[1];}
+if(url.indexOf('?')==-1){url=url+'?';}
+var opts={method:'get',onComplete:this.panelContentLoaded.bind(this),requestHeaders:['If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT']};var a=new Ajax.Request(url,opts);},panelContentLoaded:function(r){this.content.innerHTML=r.responseText;this.bContentReady=true;this.setBusy(false);if(this.onContentReady){window.setTimeout(this.onContentReady.bind(this),1);}},setBusy:function(isBusy){this.busyCount+=isBusy?1:-1;this.loadingObj.img.style.visibility=(this.busyCount>0)?'visible':'hidden';},sizeChanged:function(){var top=0;var bottom=0;if(this.menubar){this.menubar.style.height='';var size=Element.getBorderBoxSize(this.menubar);this.menubar.resize({height:size.height});top+=size.height;}
+if(this.toolbar){this.toolbar.style.height='';var size=Element.getBorderBoxSize(this.toolbar);this.toolbar.resize({height:size.height});top+=size.height;}
+if(this.statusbar){this.statusbar.style.height='';var size=Element.getBorderBoxSize(this.statusbar);this.statusbar.resize({height:size.height});bottom+=size.height;}
+if(top||bottom){this.content.resize({bottom:bottom,top:top});}}};Object.extend(Jx.Panel.prototype,Jx.UniqueId.prototype);Object.extend(Jx.Panel.prototype,Jx.ContentLoader.prototype);Jx.addStyleSheet('picker/picker.css');Jx.Picker=Class.create();Jx.Picker.prototype={sl:null,domObj:null,ul:null,currentSelection:null,isEditable:false,initialize:function(options){options=options||{};this.domObj=document.createElement('div');this.domObj.className='jxPicker';this.isEditable=options.editable||false;if(this.isEditable){this.domInput=document.createElement('input');this.domInput.type='text';Event.observe(this.domInput,'change',this.valueChanged.bind(this));Event.observe(this.domInput,'keydown',this.onKeyPress.bind(this));}else{this.domInput=document.createElement('span');}
+this.domInput.className='jxPickerInput';this.domObj.appendChild(this.domInput);this.domA=document.createElement('a');this.domA.href='javascript:void(0)';this.domA.className='jxPickerDiscloser';Event.observe(this.domA,'click',this.toggle.bind(this));this.domButton=document.createElement('img');this.domButton.src=Jx.baseURL+'images/disclose2.png';Element.addClassName(this.domButton,'png24');this.domA.appendChild(this.domButton);this.domObj.appendChild(this.domA);if(!window.opera){var iframe=document.createElement('iframe');iframe.className='jxDialogShim';iframe.scrolling='no';iframe.frameborder=0;this.domObj.appendChild(iframe);}
+this.domListDiv=document.createElement('div');this.domListDiv.className='jxPickerOptions';this.domListDiv.style.display='none';this.domObj.appendChild(this.domListDiv);this.domList=document.createElement('ul');this.domListDiv.appendChild(this.domList);this.sl=[];},onKeyPress:function(e){var charCode=(e.charCode)?e.charCode:((e.keyCode)?e.keyCode:e.which);if(charCode==Event.KEY_RETURN){this.valueChanged();}},valueChanged:function(){this.processEvent(this.sl,'selectionChanged',this);},add:function(domObj,idx){var li=document.createElement('li');var a=document.createElement('a');a.href="javascript:void(0)";if(typeof(domObj)=='string'){a.innerHTML=domObj;}else{a.appendChild(domObj);}
+Event.observe(a,'click',this.pick.bindAsEventListener(this));li.appendChild(a);if(arguments.length>1&&this.domList.childNodes.length>idx){this.domList.insertBefore(li,this.domList.childNodes[idx]);}else{this.domList.appendChild(li);}
+if(this.getValue()==''){this.setValue(a.childNodes[0]);}},remove:function(idx){if(idx>0&&idx<this.domList.childNodes.length){this.domList.removeChild(this.domList.childNodes[idx]);}},pick:function(e){var target=Event.element(e);if(target.tagName=='A'){this.currentSelection=target;this.setValue(this.currentSelection.childNodes[0]);this.valueChanged();}
+this.close();},setValue:function(value){if(this.isEditable){if(typeof(value)=='string'){this.domInput.value=value;}else if(value.nodeType&&value.nodeType==3){this.domInput.value=value.nodeValue;}else{this.domInput.value=value.innerHTML;}}else if(!this.isEditable){if(typeof(value)=='string'){this.domInput.innerHTML=value;}else if(value.nodeType&&value.nodeType==3){this.domInput.innerHTML=value.nodeValue;}else{this.domInput.appendChild(value);}}},getValue:function(){value='';if(this.isEditable){value=this.domInput.value;}else if(this.domInput.childNodes.length>0){if(this.domInput.childNodes[0].nodeType==3){value=this.domInput.innerHTML;}else{value=this.domInput.childNodes[0];}}
+return value;},toggle:function(){if(this.domListDiv.style.display=='block'){this.close();}else{this.open();}},open:function(){if(!this.keypressListener){this.keypressListener=this.keypress.bindAsEventListener(this);}
+this.domListDiv.style.display='block';Event.observe(document,'keypress',this.keypressListener);},keypress:function(e){var charCode=(e.charCode)?e.charCode:e.keyCode;if(charCode==Event.KEY_ESC){this.close();}},close:function(){this.domListDiv.style.display='none';Event.stopObserving(document,'keypress',this.keypressListener);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);},getSelection:function(){return this.currentSelection?this.currentSelection.name:'';}};Object.extend(Jx.Picker.prototype,Jx.Listener.prototype);Jx.Splitter=Class.create();Jx.Splitter.prototype={domObj:null,elements:null,bars:null,firstUpdate:true,initialize:function(domObj,options){options=options||{};this.domObj=$(domObj);this.domObj.style.overflow='hidden';if(this.domObj.jxLayout){this.domObj.jxLayout.addSizeChangeListener(this);}
+this.elements=[];this.bars=[];var nSplits=options.splitInto||(options.elements?options.elements.length:2);var aContainerOpts=options.containerOptions||[];for(var i=0;i<nSplits;i++){this.elements[i]=options.elements?options.elements[i]:this.prepareElement();this.domObj.appendChild(this.elements[i]);if(!this.elements[i].jxLayout){new Jx.Layout(this.elements[i],aContainerOpts[i]);}}
+for(var i=1;i<nSplits;i++){this.bars[i-1]=this.prepareBar();this.bars[i-1].leftSide=this.elements[i-1];this.bars[i-1].rightSide=this.elements[i];this.elements[i-1].rightBar=this.bars[i-1];this.elements[i].leftBar=this.bars[i-1];this.domObj.appendChild(this.bars[i-1]);}
+this.layout=options.layout||'horizontal';this.establishConstraints();if(options.snappers){for(var i=0;i<options.snappers.length;i++){if(options.snappers[i]){new Jx.Splitter.Snapper(options.snappers[i],this.elements[i],this);}}}},prepareElement:function(){var o=document.createElement('div');o.style.position='absolute';o.leftBar=null;o.rightBar=null;return o;},prepareBar:function(){var o=document.createElement('div');o.className='jxSplitterBar';o.style.position='absolute';o.title='drag this bar to resize';o.style.lineHeight='1px';o.splitterObj=this;return o;},establishConstraints:function(){if(this.layout=='horizontal'){for(var i=0;i<this.bars.length;i++){this.bars[i].style.top='0px';this.bars[i].style.height='100%';new Draggable(this.bars[i],{constraint:'horizontal',starteffect:function(element){element.style.backgroundColor='#eee';},endeffect:function(element){element.style.backgroundColor='';}});}}else{for(var i=0;i<this.bars.length;i++){this.bars[i].style.left='0px';this.bars[i].style.width='100%';new Draggable(this.bars[i],{constraint:'vertical',starteffect:function(element){element.style.backgroundColor='#eee';},endeffect:function(element){element.style.backgroundColor='';}});}}
+Draggables.addObserver(this);},onEnd:function(eventName,obj,event){if(obj.element.splitterObj!=this){return;}
+if(this.layout=='horizontal'){this.dragHorizontal(eventName,obj,event);}else{this.dragVertical(eventName,obj,event);}},dragHorizontal:function(eventName,obj,event){var leftEdge=parseInt(obj.element.style.left);var leftSide=obj.element.leftSide;var rightSide=obj.element.rightSide;var rsLeft,rsWidth,rsRight;if(!obj.element.size){obj.element.size=Element.getBorderBoxSize(obj.element);}
+var barSize=obj.element.size;rsLeft=leftEdge+barSize.width;var parentSize=Element.getContentBoxSize(this.domObj);if(rightSide.jxLayout.options.width!=null){rsWidth=rightSide.jxLayout.options.width+rightSide.jxLayout.options.left-rsLeft;rsRight=parentSize.width-rsLeft-rsWidth;}else{rsWidth=parentSize.width-rightSide.jxLayout.options.right-rsLeft;rsRight=rightSide.jxLayout.options.right;}
+if(rsWidth<0){rsWidth=0;}
+if(rsWidth<rightSide.jxLayout.options.minWidth){rsWidth=rightSide.jxLayout.options.minWidth;}
+if(rightSide.jxLayout.options.maxWidth>=0&&rsWidth>rightSide.jxLayout.options.maxWidth){rsWidth=rightSide.jxLayout.options.maxWidth;}
+rsLeft=parentSize.width-rsRight-rsWidth;leftEdge=rsLeft-barSize.width;var lsLeft,lsWidth;lsLeft=leftSide.jxLayout.options.left;lsWidth=leftEdge-lsLeft;if(lsWidth<0){lsWidth=0;}
+if(lsWidth<leftSide.jxLayout.options.minWidth){lsWidth=leftSide.jxLayout.options.minWidth;}
+if(leftSide.jxLayout.options.maxWidth>=0&&lsWidth>leftSide.jxLayout.options.maxWidth){lsWidth=leftSide.jxLayout.options.maxWidth;}
+if(lsLeft+lsWidth!=leftEdge){leftEdge=lsLeft+lsWidth;var delta=leftEdge+barSize.width-rsLeft;rsLeft+=delta;rsWidth-=delta;}
+obj.element.style.left=leftEdge+'px';if(leftSide.jxLayout.options.width==null){var parentSize=Element.getContentBoxSize(this.domObj);leftSide.jxLayout.resize({right:parentSize.width-lsLeft-lsWidth});}else{leftSide.jxLayout.resize({width:lsWidth});}
+if(rightSide.jxLayout.options.width==null){rightSide.jxLayout.resize({left:rsLeft});}else{rightSide.jxLayout.resize({left:rsLeft,width:rsWidth});}},dragVertical:function(eventName,obj,event){var topEdge=parseInt(obj.element.style.top);var topSide=obj.element.leftSide;var bottomSide=obj.element.rightSide;if(!obj.element.size){obj.element.size=Element.getBorderBoxSize(obj.element);}
+var barSize=obj.element.size;var parentSize=Element.getContentBoxSize(this.domObj);var bsTop,bsHeight,bsBottom;bsTop=topEdge+barSize.height;if(bottomSide.jxLayout.options.height!=null){bsHeight=bottomSide.jxLayout.options.height+bottomSide.jxLayout.options.top-bsTop;bsBottom=parentSize.height-bsTop-bsHeight;}else{bsHeight=parentSize.height-bottomSide.jxLayout.options.bottom-bsTop;bsBottom=bottomSide.jxLayout.options.bottom;}
+if(bsHeight<0){bsHeight=0;}
+if(bsHeight<bottomSide.jxLayout.options.minHeight){bsHeight=bottomSide.jxLayout.options.minHeight;}
+if(bottomSide.jxLayout.options.maxHeight>=0&&bsHeight>bottomSide.jxLayout.options.maxHeight){bsHeight=bottomSide.jxLayout.options.maxHeight;}
+bsTop=parentSize.height-bsBottom-bsHeight;topEdge=bsTop-barSize.height;var tsTop,tsHeight;tsTop=topSide.jxLayout.options.top;tsHeight=topEdge-tsTop;if(tsHeight<0){tsHeight=0;}
+if(tsHeight<topSide.jxLayout.options.minHeight){tsHeight=topSide.jxLayout.options.minHeight;}
+if(topSide.jxLayout.options.maxHeight>=0&&tsHeight>topSide.jxLayout.options.maxHeight){tsHeight=topSide.jxLayout.options.maxHeight;}
+if(tsTop+tsHeight!=topEdge){topEdge=tsTop+tsHeight;var delta=topEdge+barSize.height-bsTop;bsTop+=delta;bsHeight-=delta;}
+obj.element.style.top=topEdge+'px';if(topSide.jxLayout.options.height==null){topSide.jxLayout.resize({bottom:parentSize.height-tsTop-tsHeight});}else{topSide.jxLayout.resize({height:tsHeight});}
+if(bottomSide.jxLayout.options.height==null){bottomSide.jxLayout.resize({top:bsTop});}else{bottomSide.jxLayout.resize({top:bsTop,height:bsHeight});}},sizeChanged:function(){if(this.layout=='horizontal'){this.horizontalResize();}else{this.verticalResize();}},horizontalResize:function(){var availableSpace=Element.getContentBoxSize(this.domObj).width;var overallWidth=availableSpace;for(var i=0;i<this.bars.length;i++){var bar=this.bars[i];if(!bar.size){bar.size=Element.getBorderBoxSize(bar);}
+availableSpace-=bar.size.width;}
+var nVariable=0;var jxo;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];jxo=e.jxLayout.options;if(jxo.width!=null){availableSpace-=parseInt(jxo.width);}else{var w=0;if(jxo.right!=0||jxo.left!=0){w=Element.getBorderBoxSize(e).width;}
+availableSpace-=w;nVariable++;}}
+if(nVariable==0){availableSpace+=jxo.width;jxo.width=null;nVariable=1;}
+var amount=parseInt(availableSpace/nVariable);var remainder=availableSpace%nVariable;var currentPosition=0;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];var jxl=e.jxLayout;var jxo=jxl.options;if(jxo.width!=null){jxl.resize({left:currentPosition});currentPosition+=jxo.width;}else{var a=amount;if(nVariable==1){a+=remainder;}
+nVariable--;var w=0;if(jxo.right!=0||jxo.left!=0){w=Element.getBorderBoxSize(e).width+a;}else{w=a;}
+if(w<0){if(nVariable>0){amount=amount+w/nVariable;}
+w=0;}
+if(w<jxo.minWidth){if(nVariable>0){amount=amount+(w-jxo.minWidth)/nVariable;}
+w=jxo.minWidth;}
+if(jxo.maxWidth>=0&&w>jxo.maxWidth){if(nVariable>0){amount=amount+(w-jxo.maxWidth)/nVariable;}
+w=e.options.maxWidth;}
+var r=overallWidth-currentPosition-w;jxl.resize({left:currentPosition,right:r});currentPosition+=w;}
+if(e.rightBar){e.rightBar.style.left=currentPosition+'px';currentPosition+=e.rightBar.size.width;}}},verticalResize:function(){var availableSpace=Element.getContentBoxSize(this.domObj).height;var overallHeight=availableSpace;for(var i=0;i<this.bars.length;i++){var bar=this.bars[i];if(!bar.size){bar.size=Element.getBorderBoxSize(bar);}
+availableSpace-=bar.size.height;}
+var nVariable=0;var jxo;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];jxo=e.jxLayout.options;if(jxo.height!=null){availableSpace-=parseInt(jxo.height);}else{var h=0;if(jxo.bottom!=0||jxo.top!=0){h=Element.getBorderBoxSize(e).height;}
+availableSpace-=h;nVariable++;}}
+if(nVariable==0){availableSpace+=jxo.height;jxo.height=null;nVariable=1;}
+var amount=parseInt(availableSpace/nVariable);var remainder=availableSpace%nVariable;var currentPosition=0;for(var i=0;i<this.elements.length;i++){var e=this.elements[i];var jxl=e.jxLayout;var jxo=jxl.options;if(jxo.height!=null){jxl.resize({top:currentPosition});currentPosition+=jxo.height;}else{var a=amount;if(nVariable==1){a+=remainder;}
+nVariable--;var h=0;if(jxo.bottom!=0||jxo.top!=0){h=Element.getBorderBoxSize(e).height+a;}else{h=a;}
+if(h<0){if(nVariable>0){amount=amount+h/nVariable;}
+h=0;}
+if(h<jxo.minHeight){if(nVariable>0){amount=amount+(h-jxo.minHeight)/nVariable;}
+h=jxo.minHeight;}
+if(jxo.maxHeight>=0&&h>jxo.maxHeight){if(nVariable>0){amount=amount+(h-jxo.maxHeight)/nVariable;}
+h=jxo.maxHeight;}
+var r=overallHeight-currentPosition-h;jxl.resize({top:currentPosition,bottom:r});currentPosition+=h;}
+if(e.rightBar){e.rightBar.style.top=currentPosition+'px';currentPosition+=e.rightBar.size.height;}}}};Jx.Splitter.Snapper=Class.create();Jx.Splitter.Snapper.prototype={snapper:null,element:null,splitter:null,layout:'vertical',initialize:function(snapper,element,splitter){this.snapper=snapper;this.element=element;element.jxLayout.addSizeChangeListener(this);this.splitter=splitter;this.layout=splitter.layout;var jxo=this.element.jxLayout.options;var size=Element.getBorderBoxSize(this.element);if(this.layout=='vertical'){this.originalSize=size.height;this.minimumSize=jxo.minHeight?jxo.minHeight:0;}else{this.originalSize=size.width;this.minimumSize=jxo.minWidth?jxo.minWidth:0;}
+Event.observe(snapper,'click',this.toggleElement.bind(this));},toggleElement:function(){var size=Element.getBorderBoxSize(this.element);var newSize={};if(this.layout=='vertical'){if(size.height==this.minimumSize){newSize.height=this.originalSize;}else{this.originalSize=size.height;newSize.height=this.minimumSize;}}else{if(size.width==this.minimumSize){newSize.width=this.originalSize;}else{this.originalSize=size.width;newSize.width=this.minimumSize;}}
+this.element.jxLayout.resize(newSize);this.splitter.sizeChanged();},sizeChanged:function(){var size=Element.getBorderBoxSize(this.element);if(this.layout=='vertical'){if(size.height==this.minimumSize){Element.addClassName(this.snapper,'jxSnapClosed');Element.removeClassName(this.snapper,'jxSnapOpened');}else{Element.addClassName(this.snapper,'jxSnapOpened');Element.removeClassName(this.snapper,'jxSnapClosed');}}else{if(size.width==this.minimumSize){Element.addClassName(this.snapper,'jxSnapClosed');Element.removeClassName(this.snapper,'jxSnapOpened');}else{Element.addClassName(this.snapper,'jxSnapOpened');Element.removeClassName(this.snapper,'jxSnapClosed');}}}};Jx.addStyleSheet('tab/tabs.css');Jx.addStyleSheet('tabs/tabs_ie.css',true);Jx.TabSet=Class.create();Jx.TabSet.prototype={domObj:null,sl:null,initialize:function(domObj){this.domObj=$(domObj);if(!Element.hasClassName(this.domObj,'jxTabSetContainer')){Element.addClassName(this.domObj,'jxTabSetContainer');}
+this.sl=[];},sizeChanged:function(){this.resizeTabBox();},resizeTabBox:function(){var parentSize=Element.getContentBoxSize(this.domObj.parentNode);Element.setBorderBoxSize(this.domObj,{width:parentSize.width,height:parentSize.height});for(var i=0;i<this.domObj.childNodes.length;i++){if(this.domObj.childNodes[i].nodeType==3){continue;}
+Element.setBorderBoxSize(this.domObj.childNodes[i],{height:parentSize.height});if(this.domObj.childNodes[i].resize){this.domObj.childNodes[i].resize({forceResize:true});}}},add:function(){for(var i=0;i<arguments.length;i++){var tab=arguments[i];tab.addSelectionListener(this);this.domObj.appendChild(tab.content);if(!this.activeTab){this.setActiveTab(tab);}}},remove:function(tab){},setActiveTab:function(tab){if(this.activeTab){Element.removeClassName(this.activeTab.domObj,'tabActive');Element.removeClassName(this.activeTab.content,'tabContentActive');}
+this.activeTab=tab;Element.addClassName(this.activeTab.domObj,'tabActive');Element.addClassName(this.activeTab.content,'tabContentActive');if(this.activeTab.content.resize){this.activeTab.content.resize({forceResize:true});}},selectionChanged:function(tab){this.setActiveTab(tab);this.processEvent(this.sl,'selectionChanged',tab);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);}};Object.extend(Jx.TabSet.prototype,Jx.Listener.prototype);Jx.Tab=Class.create();Jx.Tab.prototype={domObj:null,content:null,name:null,sl:null,initialize:function(name,options){this.sl=[];options=options||{};this.name=name;this.content=document.createElement('div');this.content.className='tabContent';this.loadContent(this.content,options);var a=new Jx.Action(this.clicked.bind(this));var b=new Jx.Button(a,{label:name});this.domObj=b.domA;Element.addClassName(this.domObj,'jxTab');new Jx.Layout(this.content,options);},clicked:function(){this.processEvent(this.sl,'selectionChanged',this);this.domObj.childNodes[0].blur();},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);}};Object.extend(Jx.Tab.prototype,Jx.Listener.prototype);Object.extend(Jx.Tab.prototype,Jx.ContentLoader.prototype);Jx.TabBox=Class.create();Jx.TabBox.prototype={tabBar:null,tabSet:null,initialize:function(domObj,position){var parent=$(domObj);position=position||'top';var tabBarDiv=document.createElement('div');parent.appendChild(tabBarDiv);this.tabBar=new Jx.Toolbar(tabBarDiv,position);this.tabSet=new Jx.TabSet(parent);switch(position){case'top':Element.addClassName(parent,'jxTabBoxTop');break;case'bottom':Element.addClassName(parent,'jxTabBoxBottom');break;case'left':Element.addClassName(parent,'jxTabBoxLeft');Element.addClassName(tabBarDiv,'verticalToolbar');break;case'right':Element.addClassName(parent,'jxTabBoxRight');Element.addClassName(tabBarDiv,'verticalToolbar');break;}
+this.sl=[];},sizeChanged:function(){this.tabSet.sizeChanged();},add:function(){this.tabBar.add.apply(this.tabBar,arguments);this.tabSet.add.apply(this.tabSet,arguments);},remove:function(tab){}};Object.extend(Jx.TabBox.prototype,Jx.Listener.prototype);Jx.addStyleSheet('toolbar/toolbar.css');Jx.addStyleSheet('button/button.css');Jx.Toolbar=Class.create();Jx.Toolbar.prototype={items:null,domObj:null,isActive:false,initialize:function(domObj,position){var parent=$(domObj);this.domObj=document.createElement('ul');Element.addClassName(this.domObj,'jxToolbar');if(!Element.hasClassName(parent,'jxToolbarContainer')){Element.addClassName(parent,'jxToolbarContainer');parent.appendChild(this.domObj);var clearer=document.createElement('div');clearer.className='jxClearer';parent.appendChild(clearer);}else{parent.insertBefore(this.domObj,parent.lastChild);}
+switch(position){case'top':Element.addClassName(parent,'jxBarTop');break;case'right':Element.addClassName(parent,'jxBarRight');break;case'bottom':Element.addClassName(parent,'jxBarBottom');break;case'left':Element.addClassName(parent,'jxBarLeft');break;default:Element.addClassName(parent,'jxBarTop');}
+this.deactivateWatcher=this.deactivate.bindAsEventListener(this);},add:function(){for(var i=0;i<arguments.length;i++){var thing=arguments[i];thing.toolbar=this;if(thing.domObj){thing=thing.domObj;}
+if(thing.tagName=='LI'){if(!Element.hasClassName(thing,'jxToolItem')){Element.addClassName(thing,'jxToolItem');}
+this.domObj.appendChild(thing);}else{var item=new Jx.ToolbarItem(thing);this.domObj.appendChild(item.domObj);}}},deactivate:function(){for(var i=0;i<this.items.length;i++){this.items[i].hide();}
+this.setActive(false);},isActive:function(){return this.isActive;},setActive:function(b){this.isActive=b;if(this.isActive){Event.observe(document,'click',this.deactivateWatcher);}else{Event.stopObserving(document,'click',this.deactivateWatcher);}},setVisibleItem:function(obj){if(this.visibleItem&&this.visibleItem.hide&&this.visibleItem!=obj){this.visibleItem.hide();}
+this.visibleItem=obj;if(this.isActive()){this.visibleItem.show();}}};Jx.ToolbarItem=Class.create();Jx.ToolbarItem.prototype={domObj:null,initialize:function(jxThing){this.al=[];this.domObj=document.createElement('li');this.domObj.className='jxToolItem';if(jxThing){if(jxThing.domObj){this.domObj.appendChild(jxThing.domObj);if(jxThing instanceof Jx.Tab){Element.addClassName(this.domObj,'jxTabItem');}}else{this.domObj.appendChild(jxThing);if(Element.hasClassName(jxThing,'jxTab')){Element.addClassName(this.domObj,'jxTabItem');}}}}};Jx.ToolbarSeparator=Class.create();Jx.ToolbarSeparator.prototype={domObj:null,initialize:function(){this.domObj=document.createElement('li');this.domObj.className='jxToolItem';this.domSpan=document.createElement('span');this.domSpan.className='separator';this.domObj.appendChild(this.domSpan);}};Jx.addStyleSheet('tree/tree.css');Jx.addStyleSheet('tree/tree_ie.css',true);Jx.TreeItem=Class.create();Jx.TreeItem.prototype={data:null,domObj:null,parent:null,currentClassName:null,onClick:null,sl:null,enabled:null,contextMenu:null,initialize:function(options){this.initializeItem(options);},initializeItem:function(options){options=options||{};this.sl=[];var label=options.label||'new node';this.data=options.data||null;this.contextMenu=options.contextMenu||null;this.imgNode=options.imgNode||Jx.baseURL+'images/tree_none.png';this.imgIcon=options.imgIcon||Jx.baseURL+'images/tree_page.png';this.domObj=document.createElement('li');this.domObj.className='jxTreeNode';this.currentClassName='jxTreeNode';var elm=document.createElement('img');elm.className='jxTreeNodeImage';Jx.addToImgQueue({domElement:elm,src:this.imgNode});this.domObj.appendChild(elm);elm=document.createElement('img');elm.className='jxTreeNodeIcon';Jx.addToImgQueue({domElement:elm,src:this.imgIcon});this.domObj.appendChild(elm);elm=document.createElement('a');elm.href='javascript:void(0)';elm.onclick=this.selected.bindAsEventListener(this);elm.ondblclick=this.selected.bindAsEventListener(this);elm.oncontextmenu=this.showMenu.bindAsEventListener(this);elm.innerHTML=label;this.domObj.appendChild(elm);this.domObj.jxTreeItem=this;this.domObj.childNodes[2].jxTreeItem=this;this.onClick=options.onClick||null;this.enabled=typeof options.enabled!='undefined'?options.enabled:true;if(this.enabled){Element.removeClassName(this.domObj,'jxDisabled');}else{Element.addClassName(this.domObj,'jxDisabled');}
+var clearer=document.createElement('span');clearer.className='jxClearer';this.domObj.appendChild(clearer);},finalize:function(){this.finalizeItem();},finalizeItem:function(){if(!this.domObj){return;}
+this.domObj.childNodes[2].onclick=null;this.domObj.childNodes[2].ondblclick=null;this.domObj.childNodes[2].oncontextmenu=null;this.contextMenu=null;this.onClick=null;for(var i=this.sl.length;i>=0;i--){this.removeSelectionListener(this.sl[i]);}
+this.parent=null;this.domObj.jxTreeItem=null;this.domObj=null;},clone:function(){var options={label:this.domObj.childNodes[2].innerHTML,data:this.data,onClick:this.onClick,imgNode:this.imgNode,imgIcon:this.imgIcon};var item=new Jx.TreeItem(options);return item;},update:function(shouldDescend){var isLast=(arguments.length>1)?arguments[1]:(this.parent&&this.parent.isLastNode(this));if(isLast){Element.removeClassName(this.domObj,'jxTreeNode');Element.addClassName(this.domObj,'jxTreeNodeLast');}else{Element.removeClassName(this.domObj,'jxTreeNodeLast');Element.addClassName(this.domObj,'jxTreeNode');}},selected:function(e){this.lastEvent=e?e:event;this.processEvent(this.sl,'selectionChanged',this);},showMenu:function(e){this.lastEvent=e?e:event;this.processEvent(this.sl,'selectionChanged',this);if(this.contextMenu){this.contextMenu.show(this.lastEvent);}
+Event.stop(e);},addSelectionListener:function(obj){this.addListener(this.sl,obj);},removeSelectionListener:function(obj){this.removeListener(this.sl,obj);},getName:function(){return this.domObj.childNodes[2].innerHTML;},setName:function(name){this.domObj.childNodes[2].innerHTML=name;},propertyChanged:function(obj){this.enabled=obj.isEnabled();if(this.enabled){Element.removeClassName(this.domObj,'jxDisabled');}else{Element.addClassName(this.domObj,'jxDisabled');}}};Object.extend(Jx.TreeItem.prototype,Jx.Listener.prototype);Jx.TreeFolder=Class.create();Object.extend(Jx.TreeFolder.prototype,Jx.TreeItem.prototype);Object.extend(Jx.TreeFolder.prototype,{subDomObj:null,nodes:null,isOpen:false,dl:null,initialize:function(options){this.initializeFolder(options);},initializeFolder:function(options){options=options||{};this.initializeItem(options);this.imgTreePlus=options.imgTreePlus||Jx.baseURL+'images/tree_plus.png';this.imgTreeMinus=options.imgTreeMinus||Jx.baseURL+'images/tree_minus.png';this.imgTreeFolder=options.imgTreeFolder||Jx.baseURL+'images/tree_folder.png';this.imgTreeFolderOpen=options.imgTreeFolderOpen||Jx.baseURL+'images/tree_folder_open.png';Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreePlus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolder});this.domObj.childNodes[0].onclick=this.clicked.bindAsEventListener(this);this.nodes=[];this.subDomObj=document.createElement('ul');this.domObj.appendChild(this.subDomObj);this.subDomObj.className='jxTree';this.isOpen=options.isOpen||false;this.dl=[];if(this.isOpen){this.expand();}else{this.collapse();}},finalize:function(){this.finalizeFolder();this.finalizeItem();this.subDomObj=null;},finalizeFolder:function(){this.domObj.childNodes[0].onclick=null;for(var i=this.nodes.length-1;i>=0;i--){this.nodes[i].finalize();if(this.nodes[i].domObj)this.subDomObj.removeChild(this.nodes[i].domObj);this.nodes.pop();}
+for(var i=this.dl.length-1;i>=0;i--){this.removeDisclosureListener(this.dl[i]);}},clone:function(){var options={label:this.domObj.childNodes[2].innerHTML,data:this.data,onClick:this.onClick,imgTreePlus:this.imgTreePlus,imgTreeMinus:this.imgTreeMinus,imgTreeFolder:this.imgTreeFolder,imgTreeFolderOpen:this.imgTreeFolderOpen};var node=new Jx.TreeFolder(options);for(var i=0;i<this.nodes.length;i++){node.append(this.nodes[i].clone());}
+return node;},isLastNode:function(node){if(this.nodes.length==0){return false;}else{return this.nodes[this.nodes.length-1]==node;}},update:function(bDescend){if(!this.parent)return;var bLast=false;if(arguments.length>1){bLast=arguments[1];}else{bLast=(this.parent&&this.parent.isLastNode(this));}
+if(bLast){this.domObj.className='jxTreeNodeLast';this.subDomObj.className='jxTree';}else{this.domObj.className='jxTreeNode';this.subDomObj.className='jxTree jxTreeNest';}
+if(this.isOpen){Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreeMinus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolderOpen});}else{Jx.addToImgQueue({domElement:this.domObj.childNodes[0],src:this.imgTreePlus});Jx.addToImgQueue({domElement:this.domObj.childNodes[1],src:this.imgTreeFolder});}
+if(this.nodes&&bDescend){for(var i=0;i<this.nodes.length;i++){this.nodes[i].update(false,i==this.nodes.length-1);}}},append:function(node){node.parent=this;this.nodes.push(node);this.subDomObj.appendChild(node.domObj);this.update(true);},insert:function(node,refNode){node.parent=this;if(!refNode){this.nodes.unshift(node);if(this.subDomObj.childNodes.length==0){this.subDomObj.appendChild(node.domObj);}else{this.subDomObj.insertBefore(node.domObj,this.subDomObj.childNodes[0]);}}else{var b=false;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==refNode){i=i+1;if(i<this.nodes.length){this.nodes.splice(i,0,node);this.subDomObj.insertBefore(node.domObj,this.subDomObj.childNodes[i]);b=true;break;}}}
+if(!b){this.nodes.push(node);this.subDomObj.appendChild(node.domObj);}}
+this.update(true);},remove:function(node){node.parent=null;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==node){this.nodes.splice(i,1);this.subDomObj.removeChild(this.subDomObj.childNodes[i]);break;}}
+this.update(true);},replace:function(newNode,refNode){var b=false;for(var i=0;i<this.nodes.length;i++){if(this.nodes[i]==refNode){if(i<this.nodes.length){newNode.parent=this;this.nodes.splice(i,1,newNode);this.subDomObj.replaceChild(newNode.domObj,refNode.domObj);return true;}}}
+return false;},clicked:function(e){e=e?e:event;if(this.isOpen){this.collapse();}else{this.expand();}},expand:function(){this.isOpen=true;this.subDomObj.style.display='block';this.update(true);this.processEvent(this.dl,'disclosed',this);},collapse:function(){this.isOpen=false;this.subDomObj.style.display='none';this.update(true);this.processEvent(this.dl,'disclosed',this);},addDisclosureListener:function(obj){this.addListener(this.dl,obj);},removeDisclosureListener:function(obj){this.removeListener(this.dl,obj);},findChild:function(path){if(path.length==0)
+return this;if(path.length==1)
+{for(var i=0;i<this.nodes.length;i++)
+{if(this.nodes[i].getName()==path[0])
+return this.nodes[i];}
+return null;}
+var childName=path.shift();for(var i=0;i<this.nodes.length;i++)
+{if(this.nodes[i].getName()==childName&&this.nodes[i].findChild)
+return this.nodes[i].findChild(path);}
+return null;}});Jx.Tree=Class.create();Object.extend(Jx.Tree.prototype,Jx.TreeFolder.prototype);Object.extend(Jx.Tree.prototype,{initialize:function(id){this.subDomObj=document.createElement('ul');this.subDomObj.className='jxTreeRoot';$(id).appendChild(this.subDomObj);this.nodes=[];this.dl=[];this.isOpen=true;},finalize:function(){this.clear();this.subDomObj.parentNode.removeChild(this.subDomObj);},clear:function(){for(var i=this.nodes.length-1;i>=0;i--){this.subDomObj.removeChild(this.nodes[i].domObj);this.nodes[i].finalize();this.nodes.pop();}},update:function(shouldDescend){var bLast=true;if(this.subDomObj)
+{if(bLast){Element.removeClassName(this.subDomObj,'jxTreeNest');}else{Element.addClassName(this.subDomObj,'jxTreeNest');}}
+if(this.nodes&&shouldDescend){this.nodes.each(function(n){n.update(false);});}},append:function(node){node.parent=this;this.nodes.push(node);this.subDomObj.appendChild(node.domObj);this.update(true);}});if(Jx.COMBINED_CSS){document.write('<link type="text/css" rel="stylesheet" href="'+Jx.baseURL+'lib/jx_combined.css" />\n');}else{for(var styleSheet in Jx.importRules){var url=Jx.baseURL+styleSheet;document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');}
+document.write('<!--[if IE]>');for(var styleSheet in Jx.importRulesIE){var url=Jx.baseURL+styleSheet;document.write('<link type="text/css" rel="stylesheet" href="'+url+'" />\n');}
+document.write('<![endif]-->\n');}
\ No newline at end of file

Modified: sandbox/aboudreault/lib/ApplicationDefinition.js
===================================================================
--- sandbox/aboudreault/lib/ApplicationDefinition.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/ApplicationDefinition.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Lib.ApplicationDefinition
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -99,7 +99,7 @@
     
     loadFailure: function() {
       Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL, 
-              'failed to load: ' + this.applicationDefinition));
+        OpenLayers.String.translate('appDefLoadFailed',this.applicationDefinition)));
     },
 
     /**
@@ -130,13 +130,26 @@
             new Ajax.Request( this.applicationDefinition, options);
         } else {
             //TODO: request as JSON format
-            var r = new Fusion.Lib.MGRequest.MGGetResourceContent(this.applicationDefinition);
-            r.parameters.session = this.sessionId;
-            this.oBroker.dispatchRequest(r, this.convertXML.bind(this));
+            if (!this.sessionId) {
+              var r = new Fusion.Lib.MGRequest.MGCreateSession();
+              this.oBroker.dispatchRequest(r, this.getAppDef.bind(this));
+            } else {
+              this.getAppDef();
+            }
         }
         return true;
     },
     
+    getAppDef: function(xhr){
+      if (xhr) {
+        this.sessionId = xhr.responseText;
+        Fusion.sessionId = this.sessionId;
+      }
+      var r = new Fusion.Lib.MGRequest.MGGetResourceContent(this.applicationDefinition);
+      r.parameters.session = this.sessionId;
+      this.oBroker.dispatchRequest(r, this.convertXML.bind(this));
+    },
+    
     /**
      * Function: convertXML
      *
@@ -207,7 +220,7 @@
                 }
             } else {
               Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL, 
-                'failed to parse ApplicationDefinition'));
+                            OpenLayers.String.translate('appDefParseError')));
             }
             
             /* process WIDGET sets */
@@ -218,7 +231,7 @@
                 }
             } else {
               Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL, 
-                'failed to parse the WidgetSet'));
+                          OpenLayers.String.translate('widgetSetParseError')));
             }
             
             /* process extensions */
@@ -322,7 +335,7 @@
      */
      getMapByIndice : function(indice) {
          var map = null;
-         if (this.widgetSets.length < indice) {
+         if (this.widgetSets.length > indice) {
              map = this.widgetSets[indice].getMapWidget();
          }
          return map;
@@ -405,63 +418,87 @@
         if (jsonNode.Map instanceof Array) {
             for (var i=0; i<jsonNode.Map.length; i++) {
                 var map = new Fusion.Lib.ApplicationDefinition.Map(jsonNode.Map[i]);
-                this.maps.push(map);
-            }
-        } else {
-            //TODO: do we need a warning that there are no layers in this map?
-        }
-        this.links = {groups:[], layers:[]};
-        this.layerEvents = {};
-        if (jsonNode.Extension) {
-            var extension = jsonNode.Extension[0];
-            if (extension.Links) {
-                /* process Groups */
-                if (extension.Links[0].Group instanceof Array) {
-                    for (var j=0; j<extension.Links[0].Group.length; j++) {
-                        var group = extension.Links[0].Group[j];
-                        this.links.groups.push({name:group.Name,url:group.Url});
+                var links = {groups:[], layers:[]};
+                var mapEvents = {layerEvents:{},groupEvents:{}};
+                if (jsonNode.Map[i].Extension) {
+                    var extension = jsonNode.Map[i].Extension[0];
+                    if (extension.Links) {
+                        /* process Groups */
+                        if (extension.Links[0].Group instanceof Array) {
+                            for (var j=0; j<extension.Links[0].Group.length; j++) {
+                                var group = extension.Links[0].Group[j];
+                                links.groups.push({name:group.Name,url:group.Url});
+                            }
+                        }
+                        if (extension.Links[0].Layer instanceof Array) {
+                            for (var j=0; j<extension.Links[0].Layer.length; j++) {
+                                var layer = extension.Links[0].Layer[j];
+                                links.layers.push({name:layer.Name,url:layer.Url});
+                            }
+                        }
                     }
-                }
-                if (extension.Links[0].Layer instanceof Array) {
-                    for (var j=0; j<extension.Links[0].Layer.length; j++) {
-                        var layer = extension.Links[0].Layer[j];
-                        this.links.layers.push({name:layer.Name,url:layer.Url});
-                    }
-                }
-            }
-            /* process layer events */
-            //TODO: Should this be called MapEvents?
-            if (extension.LayerEvents) {
-                if (extension.LayerEvents[0].Layer instanceof Array) {
-                    for (var j=0; j<extension.LayerEvents[0].Layer.length; j++) {
-                        var layer = extension.LayerEvents[0].Layer[j];
-                        var layerObj = {};
-                        layerObj.name = layer.Name[0];
-                        layerObj.onEnable = [];
-                        layerObj.onDisable = [];
-                        
-                        if (layer.OnEnable instanceof Array) {
-                            for (var k=0; k<layer.OnEnable[0].Layer.length; k++) {
-                                var kLayer = layer.OnEnable[0].Layer[k];
-                                layerObj.onEnable.push({name:kLayer.Name[0], enable: kLayer.Enable[0] == 'true' ? true : false});
+                    /* process layer events */
+                    //TODO: Should this be called MapEvents?
+                    if (extension.MapEvents) {
+                        if (extension.MapEvents[0].Layer instanceof Array) {
+                            for (var j=0; j<extension.MapEvents[0].Layer.length; j++) {
+                                var layer = extension.MapEvents[0].Layer[j];
+                                var layerObj = {};
+                                layerObj.name = layer.Name[0];
+                                layerObj.onEnable = [];
+                                if (layer.OnEnable instanceof Array) {
+                                    layerObj.onEnable = this.parseMapEventSubBlock(layer.OnEnable[0]);
+                                }
+                                layerObj.onDisable = [];
+                                if (layer.OnDisable instanceof Array) {
+                                    layerObj.onDisable = this.parseMapEventSubBlock(layer.OnDisable[0]);
+                                }
+                                mapEvents.layerEvents[layerObj.name] = layerObj;
                             }
                         }
-                        if (layer.OnDisable instanceof Array) {
-                            for (var k=0; k<layer.OnDisable[0].Layer.length; k++) {
-                                var kLayer = layer.OnDisable[0].Layer[k];
-                                layerObj.onDisable.push({name:kLayer.Name[0], enable: kLayer.Enable[0] == 'true' ? true : false});
+                        if (extension.MapEvents[0].Group instanceof Array) {
+                            for (var j=0; j<extension.MapEvents[0].Group.length; j++) {
+                                var group = extension.MapEvents[0].Group[j];
+                                var groupObj = {};
+                                groupObj.name = group.Name[0];
+                                groupObj.onEnable = [];
+                                if (layer.OnEnable instanceof Array) {
+                                    groupObj.onEnable = this.parseMapEventSubBlock(group.OnEnable[0]);
+                                }
+                                groupObj.onDisable = [];
+                                if (layer.OnDisable instanceof Array) {
+                                    groupObj.onDisable = this.parseMapEventSubBlock(group.OnDisable[0]);
+                                }
+                                mapEvents.groupEvents[groupObj.name] = groupObj;
                             }
                         }
-                        this.layerEvents[layerObj.name] = layerObj;
                     }
                 }
+                map.mapInfo = {links: links, mapEvents: mapEvents};
+                this.maps.push(map);
             }
         } else {
-            this.extension = {};
+            //TODO: do we need a warning that there are no layers in this map?
         }
-        
     },
     
+    parseMapEventSubBlock: function(block) {
+        var a = [];
+        if (block.Layer && block.Layer instanceof Array) {
+            for (var i=0; i<block.Layer.length; i++) {
+                var layer = block.Layer[i];
+                a.push({type: 'layer', name:layer.Name[0], enable: layer.Enable[0] == 'true' ? true : false});
+            }
+        }
+        if (block.Group && block.Group instanceof Array) {
+            for (var i=0; i<block.Group.length; i++) {
+                var group = block.Group[i];
+                a.push({type: 'group', name:group.Name[0], enable: group.Enable[0] == 'true' ? true : false});
+            }            
+        }
+        return a;
+    },
+    
     getInitialView: function() {
         return this.initialView;
     },
@@ -715,12 +752,24 @@
                 $(this.name).container = container;
             }
             this.createWidgets(widgetSet, container);
+        } else if (this.type == 'Splitterbar') {
+            if ($(this.name)) {
+                container = new Jx.Splitter(this.name, {splitInto: this.items.length});
+                for (var i=0; i<this.items.length; i++) {
+                    container.elements[i].id = this.name + '_' + i;
+                }
+                $(this.name).container = container;
+            }
+            this.createWidgets(widgetSet, container);
         }
+        if (container && container.domObj.jxLayout) {
+            container.domObj.jxLayout.resize();
+        }
     },
     
     createWidgets: function(widgetSet, container) {
         for (var i=0; i<this.items.length; i++) {
-            this.items[i].create(widgetSet, container);
+            this.items[i].create(widgetSet, container, this.name + '_' + i);
         }
     }
     
@@ -845,10 +894,11 @@
                 break;
             case 'Separator':   
                 break;
+                  break;
         }
     },
       
-    create: function(widgetSet, container) {
+    create: function(widgetSet, container, idx) {
         switch(this.type) {
             case 'Widget':
                 var widgetTag = widgetSet.getWidgetByName(this.widgetName);
@@ -860,18 +910,28 @@
                         var tbItem = new Jx.ToolbarItem();
                         tbItem.domObj.id = name;
                         container.add(tbItem);
-                        //debugger;
                         widgetTag.create(widgetSet, name);
+                    } else if (container instanceof Jx.Splitter) {
+                        var widget = widgetTag.create(widgetSet, idx);
                     } else if (container instanceof Jx.Menu ||
                                container instanceof Jx.ContextMenu ||
                                container instanceof Jx.SubMenu) {
                         var widget = widgetTag.create(widgetSet, '');
-                        var action = new Jx.Action(widget.activateTool.bind(widget));
-                        var opt = {};
-                        opt.label = widgetTag.label;
-                        opt.image = widgetTag.imageUrl;
-                        var menuItem = new Jx.MenuItem(action, opt);
-                        container.add(menuItem);
+                        widget.id = name; 
+                        if (widget.oMenu) {   //for widgets that extend MenuBase
+                          widget.oMenu.domObj.id = name;
+                          widget.oMenu.domObj.widget = widget;
+                          container.add(widget.oMenu);
+                        } else {
+                          var action = new Jx.Action(widget.activateTool.bind(widget));
+                          var opt = {};
+                          opt.label = widgetTag.label;
+                          opt.image = widgetTag.imageUrl;
+                          var menuItem = new Jx.MenuItem(action, opt);
+                          menuItem.domObj.id = name;
+                          menuItem.domObj.widget = widget;
+                          container.add(menuItem);
+                        }
                     }
                 } else {
                   Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 
@@ -1124,4 +1184,4 @@
         var wildcard = this.operator == 'like' ? '*' : '';
         return upper + '('+this.column + ') ' + this.operator + ' ' + this.quote + prewildcard + value + postwildcard + this.quote;
     }
-};
\ No newline at end of file
+};


Property changes on: sandbox/aboudreault/lib/ApplicationDefinition.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/lib/ButtonBase.js
===================================================================
--- sandbox/aboudreault/lib/ButtonBase.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/ButtonBase.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -99,7 +99,9 @@
     enable: function() {
         //console.log('button base enable');
         Fusion.Widget.prototype.enable.apply(this,[]);
-        this._oButton.enableTool();
+        if (this._oButton) {
+          this._oButton.enableTool();
+        }
     },
     
     disable: function() {

Modified: sandbox/aboudreault/lib/CanvasTool.js
===================================================================
--- sandbox/aboudreault/lib/CanvasTool.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/CanvasTool.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -270,13 +270,8 @@
     },
     
     setRadius: function(r) {
-        if (r > 1 || r < -1) {
-            this.radius = Math.abs(r);
-            this.radiusPx = this.map.geoToPixMeasure(this.radius);
-        } else {
-            this.radius = 1;
-            this.radiusPx = 1;
-        }
+        this.radius = Math.abs(r);
+        this.radiusPx = this.map.geoToPixMeasure(this.radius);
     },
     
     draw: function( context ) {
@@ -959,4 +954,4 @@
             }
         }
     }
-};
\ No newline at end of file
+};

Modified: sandbox/aboudreault/lib/Error.js
===================================================================
--- sandbox/aboudreault/lib/Error.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/Error.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -45,7 +45,7 @@
     
     alert: function() {
         var type = this.typeToString(this.type);
-        alert('Fusion Error: ' + type + '\n' + this.message);
+        alert(OpenLayers.String.translate('fusionError', type, this.message));
     },
     
     toString: function() {

Modified: sandbox/aboudreault/lib/Map.js
===================================================================
--- sandbox/aboudreault/lib/Map.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/Map.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -140,6 +140,9 @@
         this.registerEventID(Fusion.Event.MAP_SELECTION_ON);
         this.registerEventID(Fusion.Event.MAP_SELECTION_OFF);
         
+        //register for OL map extent change events
+        this.oMapOL.events.register('moveend', this, this.mapExtentsChanged);
+        
         this._oDomObj.oncontextmenu = function() {return false;};
         OpenLayers.Event.observe(this._oDomObj, 'contextmenu', this.onContextMenu.bind(this));
         
@@ -246,17 +249,21 @@
     getMapName : function() {  
         //TODO: what is the mapname in the case of multiple map layer objects?
         //just return baselayer mapname for now
-        //return this._sMapname;
         return this.aMaps[0].getMapName();
     },
 
     getMapTitle : function() {  
-        //TODO: what is the mapname in the case of multiple map layer objects?
-        //just return baselayer mapname for now
-        //return this._sMapname;
+        //TODO: what is the map title in the case of multiple map layer objects?
+        //just return baselayer mapTitle for now
         return this.aMaps[0]._sMapTitle;
     },
 
+    getSessionID : function() {  
+        //TODO: what is the mapname in the case of multiple map layer objects?
+        //just return baselayer session ID for now
+        return this.aMaps[0].getSessionID();
+    },
+
     getDomId : function() {  
         return this._sDomObj;
     },
@@ -290,6 +297,14 @@
         return this.aMaps;
     },
     
+    //this uses setTimeout so this method can be called from an IFRAME
+    reloadMap: function() {
+      for (var i=0; i<this.aMaps.length; ++i) {
+        var map = this.aMaps[i];
+        window.setTimeout(map.reloadMap.bind(map),1);
+      }
+    },
+    
     /**
      * Function: query
      *
@@ -441,6 +456,11 @@
         this.triggerEvent(Fusion.Event.MAP_BUSY_CHANGED, this);
     },
     
+    mapExtentsChanged: function() {
+        this._oCurrentExtents = this.oMapOL.getExtent();
+        this.triggerEvent(Fusion.Event.MAP_EXTENTS_CHANGED);
+    },
+
     isBusy: function() {
         return this._nWorkers > 0;
     },
@@ -474,7 +494,8 @@
     
     setExtents : function(oExtents) {
         if (!oExtents) {
-            Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 'Map.setExtents called with null extents'));
+            Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 
+                                OpenLayers.String.translate('nullExtents')));
         }
         if (oExtents instanceof Array && oExtents.length == 4) {
             oExtents = new OpenLayers.Bounds(oExtents[0], oExtents[1], oExtents[2], oExtents[3]);
@@ -496,8 +517,6 @@
           this.aMaps[i].oLayerOL.params.ts = (new Date()).getTime();
         }
         this.oMapOL.zoomToExtent(oExtents);
-        this._oCurrentExtents = this.oMapOL.getExtent();
-        this.triggerEvent(Fusion.Event.MAP_EXTENTS_CHANGED);
     },
 
     fullExtents : function() {
@@ -686,9 +705,13 @@
     },
     
     getScale : function() {
-        return this.oMapOL.getScale();
+    return Math.round(this.oMapOL.getScale());
     },
     
+    getResolution : function() {
+        return this.oMapOL.getResolution();
+    },
+    
     getUnits : function() {
         return this.oMapOL.baseLayer.units;
     },
@@ -1020,10 +1043,10 @@
 
         this.aElements = [];
 
-        this.nProperties = o[layerName].propertynames.length;
+        this.nProperties = o[layerName].propertyvalues.length;
 
         this.aPropertiesName = [];
-        this.aPropertiesName  = o[layerName].propertynames;
+        this.aPropertiesName  = o[layerName].propertyvalues;
 
         this.aPropertiesTypes = [];
         this.aPropertiesTypes = o[layerName].propertytypes;

Modified: sandbox/aboudreault/lib/MenuBase.js
===================================================================
--- sandbox/aboudreault/lib/MenuBase.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/MenuBase.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Tool.MenuBase
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -44,14 +44,18 @@
         this.disable = Fusion.Tool.MenuBase.prototype.disable;
 
         //console.log('Fusion.Tool.MenuBase.initialize');
-            var options = {};
-            options.imgPath = this.widgetTag.imageUrl;
-            options.imgClass = this.widgetTag.imageClass;
-            options.tooltip = this.widgetTag.tooltip;
-            options.label = this.widgetTag.label;
+        var options = {};
+        options.imgPath = this.widgetTag.imageUrl;
+        options.imgClass = this.widgetTag.imageClass;
+        options.tooltip = this.widgetTag.tooltip;
+        options.label = this.widgetTag.label;
 
-        this.oMenu = new Jx.Menu(options);
-        $(this.widgetTag.name).appendChild(this.oMenu.domObj);
+        if ( $(this.widgetTag.name) ) { 
+          this.oMenu = new Jx.Menu(options);
+          $(this.widgetTag.name).appendChild(this.oMenu.domObj);
+        } else {
+          this.oMenu = new Jx.SubMenu(options);
+        }
     },
     
     enable: function() {


Property changes on: sandbox/aboudreault/lib/MenuBase.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/lib/OpenLayers/OpenLayers.js
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/OpenLayers.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/OpenLayers/OpenLayers.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -43,12505 +43,12913 @@
 *
 **/
 
-/* ======================================================================
-    OpenLayers/SingleFile.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-OpenLayers = {
-    singleFile: true
-};
-
-
-/* ======================================================================
-    OpenLayers.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/* 
- * @requires OpenLayers/BaseTypes.js
- */ 
-
-(function() {
-    /**
-     * Before creating the OpenLayers namespace, check to see if
-     * OpenLayers.singleFile is true.  This occurs if the
-     * OpenLayers/SingleFile.js script is included before this one - as is the
-     * case with single file builds.
-     */
-    var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
-    
-    /**
-     * Namespace: OpenLayers
-     * The OpenLayers object provides a namespace for all things OpenLayers
-     */
-    OpenLayers = {
-        
-        /**
-         * Property: _scriptName
-         * {String} Relative path of this script.
-         */
-        _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
-
-        /**
-         * Function: _getScriptLocation
-         * Return the path to this script.
-         *
-         * Returns:
-         * Path to this script
-         */
-        _getScriptLocation: function () {
-            var scriptLocation = "";
-            var scriptName = OpenLayers._scriptName;
-         
-            var scripts = document.getElementsByTagName('script');
-            for (var i = 0; i < scripts.length; i++) {
-                var src = scripts[i].getAttribute('src');
-                if (src) {
-                    var index = src.lastIndexOf(scriptName); 
-                    // is it found, at the end of the URL?
-                    if ((index > -1) && (index + scriptName.length == src.length)) {  
-                        scriptLocation = src.slice(0, -scriptName.length);
-                        break;
-                    }
-                }
-            }
-            return scriptLocation;
-         }
-    };
-    /**
-     * OpenLayers.singleFile is a flag indicating this file is being included
-     * in a Single File Library build of the OpenLayers Library.
-     * 
-     * When we are *not* part of a SFL build we dynamically include the
-     * OpenLayers library code.
-     * 
-     * When we *are* part of a SFL build we do not dynamically include the 
-     * OpenLayers library code as it will be appended at the end of this file.
-      */
-    if(!singleFile) {
-        var jsfiles = new Array(
-            "OpenLayers/Util.js",
-            "OpenLayers/BaseTypes.js",
-            "OpenLayers/BaseTypes/Class.js",
-            "OpenLayers/BaseTypes/Bounds.js",
-            "OpenLayers/BaseTypes/Element.js",
-            "OpenLayers/BaseTypes/LonLat.js",
-            "OpenLayers/BaseTypes/Pixel.js",
-            "OpenLayers/BaseTypes/Size.js",
-            "OpenLayers/Console.js",
-            "Rico/Corner.js",
-            "Rico/Color.js",
-            "OpenLayers/Ajax.js",
-            "OpenLayers/Events.js",
-            "OpenLayers/Map.js",
-            "OpenLayers/Layer.js",
-            "OpenLayers/Icon.js",
-            "OpenLayers/Marker.js",
-            "OpenLayers/Marker/Box.js",
-            "OpenLayers/Popup.js",
-            "OpenLayers/Tile.js",
-            "OpenLayers/Tile/Image.js",
-            "OpenLayers/Tile/WFS.js",
-            "OpenLayers/Layer/Image.js",
-            "OpenLayers/Layer/SphericalMercator.js",
-            "OpenLayers/Layer/EventPane.js",
-            "OpenLayers/Layer/FixedZoomLevels.js",
-            "OpenLayers/Layer/Google.js",
-            "OpenLayers/Layer/VirtualEarth.js",
-            "OpenLayers/Layer/Yahoo.js",
-            "OpenLayers/Layer/HTTPRequest.js",
-            "OpenLayers/Layer/Grid.js",
-            "OpenLayers/Layer/MapServer.js",
-            "OpenLayers/Layer/MapGuide.js",
-            "OpenLayers/Layer/MapServer/Untiled.js",
-            "OpenLayers/Layer/KaMap.js",
-            "OpenLayers/Layer/MultiMap.js",
-            "OpenLayers/Layer/Markers.js",
-            "OpenLayers/Layer/Text.js",
-            "OpenLayers/Layer/WorldWind.js",
-            "OpenLayers/Layer/WMS.js",
-            "OpenLayers/Layer/WMS/Untiled.js",
-            "OpenLayers/Layer/GeoRSS.js",
-            "OpenLayers/Layer/Boxes.js",
-            "OpenLayers/Layer/TMS.js",
-            "OpenLayers/Layer/TileCache.js",
-            "OpenLayers/Popup/Anchored.js",
-            "OpenLayers/Popup/AnchoredBubble.js",
-            "OpenLayers/Feature.js",
-            "OpenLayers/Feature/Vector.js",
-            "OpenLayers/Feature/WFS.js",
-            "OpenLayers/Handler.js",
-            "OpenLayers/Handler/Point.js",
-            "OpenLayers/Handler/Path.js",
-            "OpenLayers/Handler/Polygon.js",
-            "OpenLayers/Handler/Feature.js",
-            "OpenLayers/Handler/Drag.js",
-            "OpenLayers/Handler/RegularPolygon.js",
-            "OpenLayers/Handler/Box.js",
-            "OpenLayers/Handler/MouseWheel.js",
-            "OpenLayers/Handler/Keyboard.js",
-            "OpenLayers/Control.js",
-            "OpenLayers/Control/Attribution.js",
-            "OpenLayers/Control/ZoomBox.js",
-            "OpenLayers/Control/ZoomToMaxExtent.js",
-            "OpenLayers/Control/DragPan.js",
-            "OpenLayers/Control/Navigation.js",
-            "OpenLayers/Control/MouseDefaults.js",
-            "OpenLayers/Control/MousePosition.js",
-            "OpenLayers/Control/OverviewMap.js",
-            "OpenLayers/Control/KeyboardDefaults.js",
-            "OpenLayers/Control/PanZoom.js",
-            "OpenLayers/Control/PanZoomBar.js",
-            "OpenLayers/Control/ArgParser.js",
-            "OpenLayers/Control/Permalink.js",
-            "OpenLayers/Control/Scale.js",
-            "OpenLayers/Control/LayerSwitcher.js",
-            "OpenLayers/Control/DrawFeature.js",
-            "OpenLayers/Control/DragFeature.js",
-            "OpenLayers/Control/ModifyFeature.js",
-            "OpenLayers/Control/Panel.js",
-            "OpenLayers/Control/SelectFeature.js",
-            "OpenLayers/Geometry.js",
-            "OpenLayers/Geometry/Rectangle.js",
-            "OpenLayers/Geometry/Collection.js",
-            "OpenLayers/Geometry/Point.js",
-            "OpenLayers/Geometry/MultiPoint.js",
-            "OpenLayers/Geometry/Curve.js",
-            "OpenLayers/Geometry/LineString.js",
-            "OpenLayers/Geometry/LinearRing.js",        
-            "OpenLayers/Geometry/Polygon.js",
-            "OpenLayers/Geometry/MultiLineString.js",
-            "OpenLayers/Geometry/MultiPolygon.js",
-            "OpenLayers/Geometry/Surface.js",
-            "OpenLayers/Renderer.js",
-            "OpenLayers/Renderer/Elements.js",
-            "OpenLayers/Renderer/SVG.js",
-            "OpenLayers/Renderer/VML.js",
-            "OpenLayers/Layer/Vector.js",
-            "OpenLayers/Layer/GML.js",
-            "OpenLayers/Format.js",
-            "OpenLayers/Format/XML.js",
-            "OpenLayers/Format/GML.js",
-            "OpenLayers/Format/KML.js",
-            "OpenLayers/Format/GeoRSS.js",
-            "OpenLayers/Format/WFS.js",
-            "OpenLayers/Format/WKT.js",
-            "OpenLayers/Format/JSON.js",
-            "OpenLayers/Format/GeoJSON.js",
-            "OpenLayers/Layer/WFS.js",
-            "OpenLayers/Control/MouseToolbar.js",
-            "OpenLayers/Control/NavToolbar.js",
-            "OpenLayers/Control/EditingToolbar.js",
-            "OpenLayers/Projection.js",
-            "OpenLayers/Strings/en.js"
-        ); // etc.
-
-
-
-        var allScriptTags = "";
-        var host = OpenLayers._getScriptLocation() + "lib/";
-    
-        for (var i = 0; i < jsfiles.length; i++) {
-            if (/MSIE/.test(navigator.userAgent) || /Safari/.test(navigator.userAgent)) {
-                var currentScriptTag = "<script src='" + host + jsfiles[i] + "'></script>"; 
-                allScriptTags += currentScriptTag;
-            } else {
-                var s = document.createElement("script");
-                s.src = host + jsfiles[i];
-                var h = document.getElementsByTagName("head").length ? 
-                           document.getElementsByTagName("head")[0] : 
-                           document.body;
-                h.appendChild(s);
-            }
-        }
-        if (allScriptTags) document.write(allScriptTags);
-    }
-})();
-
-/**
- * Constant: VERSION_NUMBER
- */
-OpenLayers.VERSION_NUMBER="$Revision: 5560 $";
-/* ======================================================================
-    OpenLayers/Util.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * Namespace: Util
- */
-OpenLayers.Util = {};
-
-/** 
- * Function: getElement
- * This is the old $() from prototype
- */
-OpenLayers.Util.getElement = function() {
-    var elements = [];
-
-    for (var i = 0; i < arguments.length; i++) {
-        var element = arguments[i];
-        if (typeof element == 'string') {
-            element = document.getElementById(element);
-        }
-        if (arguments.length == 1) {
-            return element;
-        }
-        elements.push(element);
-    }
-    return elements;
-};
-
-/** 
- * Maintain $() from prototype
- */
-if ($ == null) {
-    var $ = OpenLayers.Util.getElement;
-}
-
-/**
- * APIFunction: extend
- * Copy all properties of a source object to a destination object.  Modifies
- *     the passed in destination object.
- *
- * Parameters:
- * destination - {Object} The object that will be modified
- * source - {Object} The object with properties to be set on the destination
- *
- * Returns:
- * {Object} The destination object.
- */
-OpenLayers.Util.extend = function(destination, source) {
-    if(destination && source) {
-        for(var property in source) {
-            destination[property] = source[property];
-        }
-        /**
-         * IE doesn't include the toString property when iterating over an object's
-         * properties with the for(property in object) syntax.  Explicitly check if
-         * the source has its own toString property.
-         */
-        if(source.hasOwnProperty && source.hasOwnProperty('toString')) {
-            destination.toString = source.toString;
-        }
-    }
-    return destination;
-};
-
-
-/** 
- * Function: removeItem
- * Remove an object from an array. Iterates through the array
- *     to find the item, then removes it.
- *
- * Parameters:
- * array - {Array}
- * item - {Object}
- * 
- * Return
- * {Array} A reference to the array
- */
-OpenLayers.Util.removeItem = function(array, item) {
-    for(var i=0; i < array.length; i++) {
-        if(array[i] == item) {
-            array.splice(i,1);
-            //break;more than once??
-        }
-    }
-    return array;
-};
-
-/**
- * Function: clearArray
- * *Deprecated*. This function will disappear in 3.0.
- * Please use "array.length = 0" instead.
- * 
- * Parameters:
- * array - {Array}
- */
-OpenLayers.Util.clearArray = function(array) {
-    var msg = OpenLayers.String.translate("clearArrayDeprecated");
-    OpenLayers.Console.warn(msg);
-    array.length = 0;
-};
-
-/** 
- * Function: indexOf
- * Seems to exist already in FF, but not in MOZ.
- * 
- * Parameters:
- * array - {Array}
- * obj - {Object}
- * 
- * Returns:
- * {Integer} The index at, which the object was found in the array.
- *           If not found, returns -1.v
- */
-OpenLayers.Util.indexOf = function(array, obj) {
-
-    for(var i=0; i < array.length; i++) {
-        if (array[i] == obj) return i;
-    }
-    return -1;   
-};
-
-
-
-/**
- * Function: modifyDOMElement
- * 
- * Modifies many properties of a DOM element all at once.  Passing in 
- * null to an individual parameter will avoid setting the attribute.
- *
- * Parameters:
- * id - {String} The element id attribute to set.
- * px - {<OpenLayers.Pixel>} The left and top style position.
- * sz - {<OpenLayers.Size>}  The width and height style attributes.
- * position - {String}       The position attribute.  eg: absolute, 
- *                           relative, etc.
- * border - {String}         The style.border attribute.  eg:
- *                           solid black 2px
- * overflow - {String}       The style.overview attribute.  
- * opacity - {Float}         Fractional value (0.0 - 1.0)
- */
-OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
-                                            border, overflow, opacity) {
-
-    if (id) {
-        element.id = id;
-    }
-    if (px) {
-        element.style.left = px.x + "px";
-        element.style.top = px.y + "px";
-    }
-    if (sz) {
-        element.style.width = sz.w + "px";
-        element.style.height = sz.h + "px";
-    }
-    if (position) {
-        element.style.position = position;
-    }
-    if (border) {
-        element.style.border = border;
-    }
-    if (overflow) {
-        element.style.overflow = overflow;
-    }
-    if (opacity) {
-        element.style.opacity = opacity;
-        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
-    }
-};
-
-/** 
- * Function: createDiv
- * Creates a new div and optionally set some standard attributes.
- * Null may be passed to each parameter if you do not wish to
- * set a particular attribute.d
- * 
- * Note: zIndex is NOT set
- * 
- * Parameters:
- * id - {String} An identifier for this element.  If no id is
- *               passed an identifier will be created 
- *               automatically.
- * px - {<OpenLayers.Pixel>} The element left and top position. 
- * sz - {<OpenLayers.Size>} The element width and height.
- * imgURL - {String} A url pointing to an image to use as a 
- *                   background image.
- * position - {String} The style.position value. eg: absolute,
- *                     relative etc.
- * border - {String} The the style.border value. 
- *                   eg: 2px solid black
- * overflow - {String} The style.overflow value. Eg. hidden
- * opacity - {Float} Fractional value (0.0 - 1.0)
- * 
- * Returns: 
- * {DOMElement} A DOM Div created with the specified attributes.
- */
-OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
-                                     border, overflow, opacity) {
-
-    var dom = document.createElement('div');
-
-    if (imgURL) {
-        dom.style.backgroundImage = 'url(' + imgURL + ')';
-    }
-
-    //set generic properties
-    if (!id) {
-        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
-    }
-    if (!position) {
-        position = "absolute";
-    }
-    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
-                                     border, overflow, opacity);
-
-    return dom;
-};
-
-/**
- * Function: createImage
- * Creates an img element with specific attribute values.
- *  
- * Parameters:
- * id - {String} The id field for the img.  If none assigned one will be
- *               automatically generated.
- * px - {<OpenLayers.Pixel>} The left and top positions.
- * sz - {<OpenLayers.Size>} The style.width and style.height values.
- * imgURL - {String} The url to use as the image source.
- * position - {String} The style.position value.
- * border - {String} The border to place around the image.
- * delayDisplay - {Boolean} If true waits until the image has been
- *                          loaded.
- * opacity - {Float} Fractional value (0.0 - 1.0)
- * 
- * Returns:
- * {DOMElement} A DOM Image created with the specified attributes.
- */
-OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
-                                       opacity, delayDisplay) {
-
-    var image = document.createElement("img");
-
-    //set generic properties
-    if (!id) {
-        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
-    }
-    if (!position) {
-        position = "relative";
-    }
-    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
-                                     border, null, opacity);
-
-    if(delayDisplay) {
-        image.style.display = "none";
-        OpenLayers.Event.observe(image, "load", 
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
-        OpenLayers.Event.observe(image, "error", 
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
-        
-    }
-    
-    //set special properties
-    image.style.alt = id;
-    image.galleryImg = "no";
-    if (imgURL) {
-        image.src = imgURL;
-    }
-
-
-        
-    return image;
-};
-
-/**
- * Function: setOpacity
- * Deprecated.
- * This function has been deprecated. Instead, please use 
- *     OpenLayers.Util.modifyDOMElement() 
- *     or 
- *     OpenLayers.Util.modifyAlphaImageDiv()
- * 
- * Set the opacity of a DOM Element
- *     Note that for this function to work in IE, elements must "have layout"
- *     according to:
- *     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
- *
- * Parameters:
- * element - {DOMElement} Set the opacity on this DOM element
- * opacity - {Float} Opacity value (0.0 - 1.0)
- */
-OpenLayers.Util.setOpacity = function(element, opacity) {
-    OpenLayers.Util.modifyDOMElement(element, null, null, null,
-                                     null, null, null, opacity);
-}
-
-/**
- * Function: onImageLoad
- */
-OpenLayers.Util.onImageLoad = function() {
-    // The complex check here is to solve issues described in #480.
-    // Every time a map view changes, it increments the 'viewRequestID' 
-    // property. As the requests for the images for the new map view are sent
-    // out, they are tagged with this unique viewRequestID. 
-    // 
-    // If an image has no viewRequestID property set, we display it regardless, 
-    // but if it does have a viewRequestID property, we check that it matches 
-    // the viewRequestID set on the map.
-    // 
-    // If the viewRequestID on the map has changed, that means that the user
-    // has changed the map view since this specific request was sent out, and
-    // therefore this tile does not need to be displayed (so we do not execute
-    // this code that turns its display on).
-    //
-    if (!this.viewRequestID ||
-        (this.map && this.viewRequestID == this.map.viewRequestID)) { 
-        this.style.backgroundColor = null;
-        this.style.display = "";  
-    }
-};
-
-/**
- * Property: onImageLoadErrorColor
- * {String} The color tiles with load errors will turn.
- *          Default is "pink"
- */
-OpenLayers.Util.onImageLoadErrorColor = "pink";
-
-/**
- * Property: onImageLoadErrorColor
- * {Integer} How many times should we try to reload an image before giving up?
- *           Default is 0
- */
-OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
-
-/**
- * Function: onImageLoadError 
- */
-OpenLayers.Util.onImageLoadError = function() {
-    this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
-    if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
-        this.src = this.src;
-    } else {
-        this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
-    }
-    this.style.display = "";
-};
-
-/**
- * Function: alphaHack
- * Checks whether it's necessary (and possible) to use the png alpha
- * hack which allows alpha transparency for png images under Internet
- * Explorer.
- * 
- * Returns:
- * {Boolean} true if alpha has is necessary and possible, false otherwise.
- */
-OpenLayers.Util.alphaHack = function() {
-    var arVersion = navigator.appVersion.split("MSIE");
-    var version = parseFloat(arVersion[1]);
-    var filter = false;
-    
-    // IEs4Lin dies when trying to access document.body.filters, because 
-    // the property is there, but requires a DLL that can't be provided. This
-    // means that we need to wrap this in a try/catch so that this can
-    // continue.
-    
-    try { 
-        filter = document.body.filters;
-    } catch (e) {
-    }    
-    
-    return ( filter &&
-                      (version >= 5.5) && (version < 7) );
-}
-
-/** 
- * Function: modifyAlphaImageDiv
- * 
- * div - {DOMElement} Div containing Alpha-adjusted Image
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * border - {String}
- * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
- * opacity - {Float} Fractional value (0.0 - 1.0)
- */ 
-OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, 
-                                               position, border, sizing, 
-                                               opacity) {
-
-    OpenLayers.Util.modifyDOMElement(div, id, px, sz);
-
-    var img = div.childNodes[0];
-
-    if (imgURL) {
-        img.src = imgURL;
-    }
-    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
-                                     "relative", border);
-    if (opacity) {
-        div.style.opacity = opacity;
-        div.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
-    }
-    
-    if (OpenLayers.Util.alphaHack()) {
-
-        div.style.display = "inline-block";
-        if (sizing == null) {
-            sizing = "scale";
-        }
-        
-        div.style.filter = "progid:DXImageTransform.Microsoft" +
-                           ".AlphaImageLoader(src='" + img.src + "', " +
-                           "sizingMethod='" + sizing + "')";
-        if (div.style.opacity) {
-            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
-        }
-
-        img.style.filter = "progid:DXImageTransform.Microsoft" +
-                                ".Alpha(opacity=0)";
-    }
-};
-
-/** 
- * Function: createAlphaImageDiv
- * 
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * border - {String}
- * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
- * delayDisplay{Boolean}
- * 
- * Returns:
- * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is 
- *              needed for transparency in IE, it is added.
- */ 
-OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, 
-                                               position, border, sizing, 
-                                               opacity, delayDisplay) {
-    
-    var div = OpenLayers.Util.createDiv();
-    var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
-                                          null, false);
-    div.appendChild(img);
-
-    if (delayDisplay) {
-        img.style.display = "none";
-        OpenLayers.Event.observe(img, "load",
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
-        OpenLayers.Event.observe(img, "error",
-            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
-    }
-
-    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
-                                        border, sizing, opacity);
-    
-    return div;
-};
-
-
-/** 
- * Function: upperCaseObject
- * Creates a new hashtable and copies over all the keys from the 
- *     passed-in object, but storing them under an uppercased
- *     version of the key at which they were stored.
- * 
- * Parameters: 
- * object - {Object}
- * 
- * Returns: 
- * {Object} A new Object with all the same keys but uppercased
- */
-OpenLayers.Util.upperCaseObject = function (object) {
-    var uObject = {};
-    for (var key in object) {
-        uObject[key.toUpperCase()] = object[key];
-    }
-    return uObject;
-};
-
-/** 
- * Function: applyDefaults
- * Takes a hashtable and copies any keys that don't exist from
- *     another hashtable, by analogy with OpenLayers.Util.extend() from
- *     Prototype.js.
- * 
- * Parameters:
- * to - {Object}
- * from - {Object}
- */
-OpenLayers.Util.applyDefaults = function (to, from) {
-    for (var key in from) {
-        if (to[key] == null) {
-            to[key] = from[key];
-        }
-    }
-};
-
-/**
- * Function: getParameterString
- * 
- * Parameters:
- * params - {Object}
- * 
- * Returns:
- * {String} A concatenation of the properties of an object in 
- *          http parameter notation. 
- *          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
- *          If a parameter is actually a list, that parameter will then
- *          be set to a comma-seperated list of values (foo,bar) instead
- *          of being URL escaped (foo%3Abar). 
- */
-OpenLayers.Util.getParameterString = function(params) {
-    paramsArray = [];
-    
-    for (var key in params) {
-      var value = params[key];
-      if ((value != null) && (typeof value != 'function')) {
-        var encodedValue;
-        if (typeof value == 'object' && value.constructor == Array) {
-          /* value is an array; encode items and separate with "," */
-          var encodedItemArray = [];
-          for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
-            encodedItemArray.push(encodeURIComponent(value[itemIndex]));
-          }
-          encodedValue = encodedItemArray.join(",");
-        }
-        else {
-          /* value is a string; simply encode */
-          encodedValue = encodeURIComponent(value);
-        }
-        paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
-      }
-    }
-    
-    return paramsArray.join("&");
-};
-
-/**
- * Property: ImgPath
- * {String} Default is ''.
- */
-OpenLayers.ImgPath = '';
-
-/** 
- * Function: getImagesLocation
- * 
- * Returns:
- * {String} The fully formatted image location string
- */
-OpenLayers.Util.getImagesLocation = function() {
-    return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
-};
-
-
-/** 
- * Function: Try
- * Execute functions until one of them doesn't throw an error. 
- *     Capitalized because "try" is a reserved word in JavaScript.
- *     Taken directly from OpenLayers.Util.Try()
- * 
- * Parameters:
- * [*] - {Function} Any number of parameters may be passed to Try()
- *    It will attempt to execute each of them until one of them 
- *    successfully executes. 
- *    If none executes successfully, returns null.
- * 
- * Returns:
- * {*} The value returned by the first successfully executed function.
- */
-OpenLayers.Util.Try = function() {
-    var returnValue = null;
-
-    for (var i = 0; i < arguments.length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-}
-
-
-/** 
- * Function: getNodes
- * 
- * These could/should be made namespace aware?
- * 
- * Parameters:
- * p - {}
- * tagName - {String}
- * 
- * Returns:
- * {Array}
- */
-OpenLayers.Util.getNodes=function(p, tagName) {
-    var nodes = OpenLayers.Util.Try(
-        function () {
-            return OpenLayers.Util._getNodes(p.documentElement.childNodes,
-                                            tagName);
-        },
-        function () {
-            return OpenLayers.Util._getNodes(p.childNodes, tagName);
-        }
-    );
-    return nodes;
-};
-
-/**
- * Function: _getNodes
- * 
- * Parameters:
- * nodes - {Array}
- * tagName - {String}
- * 
- * Returns:
- * {Array}
- */
-OpenLayers.Util._getNodes=function(nodes, tagName) {
-    var retArray = [];
-    for (var i=0;i<nodes.length;i++) {
-        if (nodes[i].nodeName==tagName) {
-            retArray.push(nodes[i]);
-        }
-    }
-
-    return retArray;
-};
-
-
-
-/**
- * Function: getTagText
- * 
- * Parameters:
- * parent - {}
- * item - {String}
- * index - {Integer}
- * 
- * Returns:
- * {String}
- */
-OpenLayers.Util.getTagText = function (parent, item, index) {
-    var result = OpenLayers.Util.getNodes(parent, item);
-    if (result && (result.length > 0))
-    {
-        if (!index) {
-            index=0;
-        }
-        if (result[index].childNodes.length > 1) {
-            return result.childNodes[1].nodeValue; 
-        }
-        else if (result[index].childNodes.length == 1) {
-            return result[index].firstChild.nodeValue; 
-        }
-    } else { 
-        return ""; 
-    }
-};
-
-/**
- * Function: getXmlNodeValue
- * 
- * Parameters:
- * node - {XMLNode}
- * 
- * Returns:
- * {String} The text value of the given node, without breaking in firefox or IE
- */
-OpenLayers.Util.getXmlNodeValue = function(node) {
-    var val = null;
-    OpenLayers.Util.Try( 
-        function() {
-            val = node.text;
-            if (!val)
-                val = node.textContent;
-            if (!val)
-                val = node.firstChild.nodeValue;
-        }, 
-        function() {
-            val = node.textContent;
-        }); 
-    return val;
-};
-
-/** 
- * Function: mouseLeft
- * 
- * Parameters:
- * evt - {Event}
- * div - {HTMLDivElement}
- * 
- * Returns:
- * {Boolean}
- */
-OpenLayers.Util.mouseLeft = function (evt, div) {
-    // start with the element to which the mouse has moved
-    var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
-    // walk up the DOM tree.
-    while (target != div && target != null) {
-        target = target.parentNode;
-    }
-    // if the target we stop at isn't the div, then we've left the div.
-    return (target != div);
-};
-
-/**
- * Function: rad
- * 
- * Parameters:
- * x - {Float}
- * 
- * Returns:
- * {Float}
- */
-OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
-
-/**
- * Function: distVincenty
- * 
- * Parameters:
- * p1 - {Float}
- * p2 - {Float}
- * 
- * Returns:
- * {Float}
- */
-OpenLayers.Util.distVincenty=function(p1, p2) {
-    var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;
-    var L = OpenLayers.Util.rad(p2.lon - p1.lon);
-    var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
-    var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
-    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
-    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
-    var lambda = L, lambdaP = 2*Math.PI;
-    var iterLimit = 20;
-    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
-        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
-        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
-        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
-        if (sinSigma==0) return 0;  // co-incident points
-        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
-        var sigma = Math.atan2(sinSigma, cosSigma);
-        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
-        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
-        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
-        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
-        lambdaP = lambda;
-        lambda = L + (1-C) * f * Math.sin(alpha) *
-        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
-    }
-    if (iterLimit==0) return NaN  // formula failed to converge
-    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
-    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
-    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
-    var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
-        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
-    var s = b*A*(sigma-deltaSigma);
-    var d = s.toFixed(3)/1000; // round to 1mm precision
-    return d;
-};
-
-/**
- * Function: getParameters
- * Parse the parameters from a URL or from the current page itself into a 
- *     JavaScript Object. Note that parameter values with commas are separated
- *     out into an Array.
- * 
- * Parameters:
- * url - {String} Optional url used to extract the query string.
- *                If null, query string is taken from page location.
- * 
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getParameters = function(url) {
-    //if no url specified, take it from the location bar
-    url = url || window.location.href
-    if(url == null) {
-        url = window.location.href;
-    }
-
-    //parse out parameters portion of url string
-    var paramsString = "";
-    if (OpenLayers.String.contains(url, '?')) {
-        var start = url.indexOf('?') + 1;
-        var end = OpenLayers.String.contains(url, "#") ?
-                    url.indexOf('#') : url.length;
-        paramsString = url.substring(start, end);
-    }
-        
-    var parameters = {};
-    var pairs = paramsString.split(/[&;]/);
-    for(var i = 0; i < pairs.length; ++i) {
-        var keyValue = pairs[i].split('=');
-        if (keyValue[0]) {
-            var key = decodeURIComponent(keyValue[0]);
-            var value = keyValue[1] || ''; //empty string if no value
-
-            //decode individual values
-            value = value.split(",");
-            for(var j=0; j < value.length; j++) {
-                value[j] = decodeURIComponent(value[j]);
-            }
-
-            //if there's only one value, do not return as array                    
-            if (value.length == 1) {
-                value = value[0];
-            }                
-            
-            parameters[key] = value;
-         }
-     }
-    return parameters;
-};
-
-/**
- * Function: getArgs
- * Deprecated - Will be removed in 3.0. 
- *     Please use instead OpenLayers.Util.getParameters
- * 
- * Parameters:
- * url - {String} Optional url used to extract the query string.
- *                If null, query string is taken from page location.
- * 
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getArgs = function(url) {
-    var err = OpenLayers.String.translate("getArgsDeprecated");
-    OpenLayers.Console.warn(err);
-    return OpenLayers.Util.getParameters(url);
-};
-
-/**
- * Property: lastSeqID
- * {Integer} The ever-incrementing count variable.
- *           Used for generating unique ids.
- */
-OpenLayers.Util.lastSeqID = 0;
-
-/**
- * Function: createUniqueID
- * 
- * Parameters:
- * prefix {String} String to prefix unique id. 
- *                 If null, default is "id_"
- * 
- * Returns:
- * {String} A unique id string, built on the passed in prefix
- */
-OpenLayers.Util.createUniqueID = function(prefix) {
-    if (prefix == null) {
-        prefix = "id_";
-    }
-    OpenLayers.Util.lastSeqID += 1; 
-    return prefix + OpenLayers.Util.lastSeqID;        
-};
-
-/**
- * Constant: INCHES_PER_UNIT
- * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
- */
-OpenLayers.INCHES_PER_UNIT = { 
-    'inches': 1.0,
-    'ft': 12.0,
-    'mi': 63360.0,
-    'm': 39.3701,
-    'km': 39370.1,
-    'dd': 4374754
-};
-OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
-OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
-
-/** 
- * Constant: DOTS_PER_INCH
- * {Integer} 72 (A sensible default)
- */
-OpenLayers.DOTS_PER_INCH = 72;
-
-/**
- * Function: normalzeScale
- * 
- * Parameters:
- * scale - {float}
- * 
- * Returns:
- * {Float} A normalized scale value, in 1 / X format. 
- *         This means that if a value less than one ( already 1/x) is passed
- *         in, it just returns scale directly. Otherwise, it returns 
- *         1 / scale
- */
-OpenLayers.Util.normalizeScale = function (scale) {
-    var normScale = (scale > 1.0) ? (1.0 / scale) 
-                                  : scale;
-    return normScale;
-};
-
-/**
- * Function: getResolutionFromScale
- * 
- * Parameters:
- * scale - {Float}
- * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
- *                  Default is degrees
- * 
- * Returns:
- * {Float} The corresponding resolution given passed-in scale and unit 
- *         parameters.
- */
-OpenLayers.Util.getResolutionFromScale = function (scale, units) {
-
-    if (units == null) {
-        units = "degrees";
-    }
-
-    var normScale = OpenLayers.Util.normalizeScale(scale);
-
-    var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
-                                    * OpenLayers.DOTS_PER_INCH);
-    return resolution;
-};
-
-/**
- * Function: getScaleFromResolution
- * 
- * Parameters:
- * resolution - {Float}
- * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
- *                  Default is degrees
- * 
- * Returns:
- * {Float} The corresponding scale given passed-in resolution and unit 
- *         parameters.
- */
-OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
-
-    if (units == null) {
-        units = "degrees";
-    }
-
-    var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
-                    OpenLayers.DOTS_PER_INCH;
-    return scale;
-};
-
-/**
- * Function: safeStopPropagation
- * Deprecated.
- * 
- * This function has been deprecated. Please use directly 
- *     OpenLayers.Event.stop() passing 'true' as the 2nd 
- *     argument (preventDefault)
- * 
- * Safely stop the propagation of an event *without* preventing
- *   the default browser action from occurring.
- * 
- * Parameter:
- * evt - {Event}
- */
-OpenLayers.Util.safeStopPropagation = function(evt) {
-    OpenLayers.Event.stop(evt, true);
-};
-
-/**
- * Function: pagePositon
- * Calculates the position of an element on the page. 
- *
- * Parameters:
- * forElement - {DOMElement}
- * 
- * Returns:´
- * {Array} two item array, L value then T value.
- */
-OpenLayers.Util.pagePosition = function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    var child = forElement;
-    while(element) {
-
-        if(element == document.body) {
-            if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
-                break;
-            }
-        }
-        
-        valueT += element.offsetTop  || 0;
-        valueL += element.offsetLeft || 0;
-
-        child = element;
-        try {
-            // wrapping this in a try/catch because IE chokes on the offsetParent
-            element = element.offsetParent;
-        } catch(e) {
-            OpenLayers.Console.error(OpenLayers.String.translate(
-                                              "pagePositionFailed",element.id));
-            break;
-        }
-    }
-
-    element = forElement;
-    while(element) {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-        element = element.parentNode;
-    }
-    
-    return [valueL, valueT];
-};
-
-
-/** 
- * Function: isEquivalentUrl
- * Test two URLs for equivalence. 
- * 
- * Setting 'ignoreCase' allows for case-independent comparison.
- * 
- * Comparison is based on: 
- *  - Protocol
- *  - Host (evaluated without the port)
- *  - Port (set 'ignorePort80' to ignore "80" values)
- *  - Hash ( set 'ignoreHash' to disable)
- *  - Pathname (for relative <-> absolute comparison) 
- *  - Arguments (so they can be out of order)
- *  
- * Parameters:
- * url1 - {String}
- * url2 - {String}
- * options - {Object} Allows for customization of comparison:
- *                    'ignoreCase' - Default is True
- *                    'ignorePort80' - Default is True
- *                    'ignoreHash' - Default is True
- *
- * Returns:
- * {Boolean} Whether or not the two URLs are equivalent
- */
-OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
-    options = options || {};
-
-    OpenLayers.Util.applyDefaults(options, {
-        ignoreCase: true,
-        ignorePort80: true,
-        ignoreHash: true
-    });
-
-    urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
-    urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
-
-    //compare all keys (host, port, etc)
-    for(var key in urlObj1) {
-        if (options.test) {
-            alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
-        }
-        var val1 = urlObj1[key];
-        var val2 = urlObj2[key];
-        
-        switch(key) {
-            case "args":
-                //do nothing, they'll be treated below
-                break;
-            case "host":
-            case "port":
-            case "protocol":
-                if ((val1 == "") || (val2 == "")) {
-                    //these will be blank for relative urls, so no need to 
-                    // compare them here -- call break. 
-                    // 
-                    break;
-                } 
-                // otherwise continue with default compare
-                //
-            default: 
-                if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
-                    return false;
-                }
-                break;
-        }
-        
-    }
-
-    // compare search args - irrespective of order
-    for(var key in urlObj1.args) {
-        if(urlObj1.args[key] != urlObj2.args[key]) {
-            return false;
-        }
-        delete urlObj2.args[key];
-    }
-    // urlObj2 shouldn't have any args left
-    for(var key in urlObj2.args) {
-        return false;
-    }
-    
-    return true;
-};
-
-/**
- * Function: createUrlObject
- * 
- * Parameters:
- * url - {String}
- * options - {Object} A hash of options.  Can be one of:
- *            ignoreCase: lowercase url,
- *            ignorePort80: don't include explicit port if port is 80,
- *            ignoreHash: Don't include part of url after the hash (#).
- * 
- * Returns:
- * {Object} An object with separate url, a, port, host, and args parsed out 
- *          and ready for comparison
- */
-OpenLayers.Util.createUrlObject = function(url, options) {
-    options = options || {};
-
-    var urlObject = {};
-  
-    if (options.ignoreCase) {
-        url = url.toLowerCase(); 
-    }
-
-    var a = document.createElement('a');
-    a.href = url;
-    
-  //host (without port)
-    urlObject.host = a.host;
-    var port = a.port;
-    if (port.length <= 0) {
-        var newHostLength = urlObject.host.length - (port.length);
-        urlObject.host = urlObject.host.substring(0, newHostLength); 
-    }
-
-  //protocol
-    urlObject.protocol = a.protocol;  
-
-  //port
-    urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
-                                                                     
-  //hash
-    urlObject.hash = (options.ignoreHash) ? "" : a.hash;  
-    
-  //args
-    var queryString = a.search;
-    if (!queryString) {
-        var qMark = url.indexOf("?");
-        queryString = (qMark != -1) ? url.substr(qMark) : "";
-    }
-    urlObject.args = OpenLayers.Util.getParameters(queryString);
-
-
-  //pathname (this part allows for relative <-> absolute comparison)
-    if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) || 
-         ((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
-
-        urlObject.pathname = a.pathname;  
-
-        //Test to see if the pathname includes the arguments (Opera)
-        var qIndex = urlObject.pathname.indexOf("?");
-        if (qIndex != -1) {
-            urlObject.pathname = urlObject.pathname.substring(0, qIndex);
-        }
-
-    } else {
-        var relStr = OpenLayers.Util.removeTail(url);
-
-        var backs = 0;
-        do {
-            var index = relStr.indexOf("../");
-
-            if (index == 0) {
-                backs++
-                relStr = relStr.substr(3);
-            } else if (index >= 0) {
-                var prevChunk = relStr.substr(0,index - 1);
-                
-                var slash = prevChunk.indexOf("/");
-                prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
-                                          : "";
-                
-                var postChunk = relStr.substr(index + 3);                
-                relStr = prevChunk + postChunk;
-            }
-        } while(index != -1)
-
-        var windowAnchor = document.createElement("a");
-        var windowUrl = window.location.href;
-        if (options.ignoreCase) {
-            windowUrl = windowUrl.toLowerCase();
-        }
-        windowAnchor.href = windowUrl;
-
-      //set protocol of window
-        urlObject.protocol = windowAnchor.protocol;
-
-        var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
-        var dirs = windowAnchor.pathname.split(splitter);
-        dirs.pop(); //remove filename
-        while ((backs > 0) && (dirs.length > 0)) {
-            dirs.pop();
-            backs--;
-        }
-        relStr = dirs.join("/") + "/"+ relStr;
-        urlObject.pathname = relStr;
-    }
-    
-    if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
-        urlObject.host = "localhost";
-    }
-
-    return urlObject; 
-};
- 
-/**
- * Function: removeTail
- * Takes a url and removes everything after the ? and #
- * 
- * Parameters:
- * url - {String} The url to process
- * 
- * Returns:
- * {String} The string with all queryString and Hash removed
- */
-OpenLayers.Util.removeTail = function(url) {
-    var head = null;
-    
-    var qMark = url.indexOf("?");
-    var hashMark = url.indexOf("#");
-
-    if (qMark == -1) {
-        head = (hashMark != -1) ? url.substr(0,hashMark) : url;
-    } else {
-        head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) 
-                                  : url.substr(0, qMark);
-    }
-    return head;
-};
-
-
-/**
- * Function: getBrowserName
- * 
- * Returns:
- * {String} A string which specifies which is the current 
- *          browser in which we are running. 
- * 
- *          Currently-supported browser detection and codes:
- *           * 'opera' -- Opera
- *           * 'msie'  -- Internet Explorer
- *           * 'safari' -- Safari
- *           * 'firefox' -- FireFox
- *           * 'mozilla' -- Mozilla
- * 
- *          If we are unable to property identify the browser, we 
- *           return an empty string.
- */
-OpenLayers.Util.getBrowserName = function() {
-    var browserName = "";
-    
-    var ua = navigator.userAgent.toLowerCase();
-    if ( ua.indexOf( "opera" ) != -1 ) {
-        browserName = "opera";
-    } else if ( ua.indexOf( "msie" ) != -1 ) {
-        browserName = "msie";
-    } else if ( ua.indexOf( "safari" ) != -1 ) {
-        browserName = "safari";
-    } else if ( ua.indexOf( "mozilla" ) != -1 ) {
-        if ( ua.indexOf( "firefox" ) != -1 ) {
-            browserName = "firefox";
-        } else {
-            browserName = "mozilla";
-        }
-    }
-    
-    return browserName;
-};
-/* ======================================================================
-    OpenLayers/Console.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Namespace: OpenLayers.Console
- * The OpenLayers.Console namespace is used for debugging and error logging.
- * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
- * calls to OpenLayers.Console methods will get redirected to window.console.
- * This makes use of the Firebug extension where available and allows for
- * cross-browser debugging Firebug style.
- *
- * Note:
- * Note that behavior will differ with the Firebug extention and Firebug Lite.
- * Most notably, the Firebug Lite console does not currently allow for
- * hyperlinks to code or for clicking on object to explore their properties.
- * 
- */
-OpenLayers.Console = {
-    /**
-     * Create empty functions for all console methods.  The real value of these
-     * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
-     * included.  We explicitly require the Firebug Lite script to trigger
-     * functionality of the OpenLayers.Console methods.
-     */
-    
-    /**
-     * APIFunction: log
-     * Log an object in the console.  The Firebug Lite console logs string
-     * representation of objects.  Given multiple arguments, they will
-     * be cast to strings and logged with a space delimiter.  If the first
-     * argument is a string with printf-like formatting, subsequent arguments
-     * will be used in string substitution.  Any additional arguments (beyond
-     * the number substituted in a format string) will be appended in a space-
-     * delimited line.
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    log: function() {},
-
-    /**
-     * APIFunction: debug
-     * Writes a message to the console, including a hyperlink to the line
-     * where it was called.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    debug: function() {},
-
-    /**
-     * APIFunction: info
-     * Writes a message to the console with the visual "info" icon and color
-     * coding and a hyperlink to the line where it was called.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    info: function() {},
-
-    /**
-     * APIFunction: warn
-     * Writes a message to the console with the visual "warning" icon and
-     * color coding and a hyperlink to the line where it was called.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    warn: function() {},
-
-    /**
-     * APIFunction: error
-     * Writes a message to the console with the visual "error" icon and color
-     * coding and a hyperlink to the line where it was called.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    error: function() {},
-
-    /**
-     * APIFunction: assert
-     * Tests that an expression is true. If not, it will write a message to
-     * the console and throw an exception.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    assert: function() {},
-
-    /**
-     * APIFunction: dir
-     * Prints an interactive listing of all properties of the object. This
-     * looks identical to the view that you would see in the DOM tab.
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    dir: function() {},
-
-    /**
-     * APIFunction: dirxml
-     * Prints the XML source tree of an HTML or XML element. This looks
-     * identical to the view that you would see in the HTML tab. You can click
-     * on any node to inspect it in the HTML tab.
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    dirxml: function() {},
-
-    /**
-     * APIFunction: trace
-     * Prints an interactive stack trace of JavaScript execution at the point
-     * where it is called.  The stack trace details the functions on the stack,
-     * as well as the values that were passed as arguments to each function.
-     * You can click each function to take you to its source in the Script tab,
-     * and click each argument value to inspect it in the DOM or HTML tabs.
-     * 
-     */
-    trace: function() {},
-
-    /**
-     * APIFunction: group
-     * Writes a message to the console and opens a nested block to indent all
-     * future messages sent to the console. Call OpenLayers.Console.groupEnd()
-     * to close the block.
-     *
-     * May be called with multiple arguments as with OpenLayers.Console.log().
-     * 
-     * Parameters:
-     * object - {Object}
-     */
-    group: function() {},
-
-    /**
-     * APIFunction: groupEnd
-     * Closes the most recently opened block created by a call to
-     * OpenLayers.Console.group
-     */
-    groupEnd: function() {},
-    
-    /**
-     * APIFunction: time
-     * Creates a new timer under the given name. Call
-     * OpenLayers.Console.timeEnd(name)
-     * with the same name to stop the timer and print the time elapsed.
-     *
-     * Parameters:
-     * name - {String}
-     */
-    time: function() {},
-
-    /**
-     * APIFunction: timeEnd
-     * Stops a timer created by a call to OpenLayers.Console.time(name) and
-     * writes the time elapsed.
-     *
-     * Parameters:
-     * name - {String}
-     */
-    timeEnd: function() {},
-
-    /**
-     * APIFunction: profile
-     * Turns on the JavaScript profiler. The optional argument title would
-     * contain the text to be printed in the header of the profile report.
-     *
-     * This function is not currently implemented in Firebug Lite.
-     * 
-     * Parameters:
-     * title - {String} Optional title for the profiler
-     */
-    profile: function() {},
-
-    /**
-     * APIFunction: profileEnd
-     * Turns off the JavaScript profiler and prints its report.
-     * 
-     * This function is not currently implemented in Firebug Lite.
-     */
-    profileEnd: function() {},
-
-    /**
-     * APIFunction: count
-     * Writes the number of times that the line of code where count was called
-     * was executed. The optional argument title will print a message in
-     * addition to the number of the count.
-     *
-     * This function is not currently implemented in Firebug Lite.
-     *
-     * Parameters:
-     * title - {String} Optional title to be printed with count
-     */
-    count: function() {},
-
-    CLASS_NAME: "OpenLayers.Console"
-};
-
-/**
- * Execute an anonymous function to extend the OpenLayers.Console namespace
- * if the firebug.js script is included.  This closure is used so that the
- * "scripts" and "i" variables don't pollute the global namespace.
- */
-(function() {
-    /**
-     * If Firebug Lite is included (before this script), re-route all
-     * OpenLayers.Console calls to the console object.
-     */
-    if(window.console) {
-        var scripts = document.getElementsByTagName("script");
-        for(var i=0; i<scripts.length; ++i) {
-            if(scripts[i].src.indexOf("firebug.js") != -1) {
-                OpenLayers.Util.extend(OpenLayers.Console, console);
-                break;
-            }
-        }
-    }
-})();
-/* ======================================================================
-    OpenLayers/BaseTypes.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/BaseTypes/LonLat.js
- * @requires OpenLayers/BaseTypes/Size.js
- * @requires OpenLayers/BaseTypes/Pixel.js
- * @requires OpenLayers/BaseTypes/Bounds.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/Strings/en.js
- * 
- * Header: OpenLayers Base Types
- * OpenLayers custom string, number and function functions are described here.
- */
-
-/*********************
- *                   *
- *      STRING       * 
- *                   * 
- *********************/
-
-OpenLayers.String = {
-    /**
-     * APIMethod: OpenLayers.String.startsWith
-     * Test whether a string starts with another string. 
-     * 
-     * Parameters:
-     * str - {String} The string to test.
-     * sub - {Sring} The substring to look for.
-     *  
-     * Returns:
-     * {Boolean} The first string starts with the second.
-     */
-    startsWith: function(str, sub) {
-        return (str.indexOf(sub) == 0);
-    },
-
-    /**
-     * APIMethod: OpenLayers.String.contains
-     * Test whether a string contains another string.
-     * 
-     * Parameters:
-     * str - {String} The string to test.
-     * sub - {String} The substring to look for.
-     * 
-     * Returns:
-     * {Boolean} The first string contains the second.
-     */
-    contains: function(str, sub) {
-        return (str.indexOf(sub) != -1);
-    },
-    
-    /**
-     * APIMethod: OpenLayers.String.trim
-     * Removes leading and trailing whitespace characters from a string.
-     * 
-     * Parameters:
-     * str - {String} The (potentially) space padded string.  This string is not
-     *     modified.
-     * 
-     * Returns:
-     * {String} A trimmed version of the string with all leading and 
-     *     trailing spaces removed.
-     */
-    trim: function(str) {
-        return str.replace(/^\s*(.*?)\s*$/, "$1");    
-    },
-    
-    /**
-     * APIMethod: OpenLayers.String.camelize
-     * Camel-case a hyphenated string. 
-     *     Ex. "chicken-head" becomes "chickenHead", and
-     *     "-chicken-head" becomes "ChickenHead".
-     *
-     * Parameters:
-     * str - {String} The string to be camelized.  The original is not modified.
-     * 
-     * Returns:
-     * {String} The string, camelized
-     */
-    camelize: function(str) {
-        var oStringList = str.split('-');
-        var camelizedString = oStringList[0];
-        for (var i = 1; i < oStringList.length; i++) {
-            var s = oStringList[i];
-            camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
-        }
-        return camelizedString;
-    },
-    
-    langCode: (OpenLayers.Util.getBrowserName() == "msie") ?
-                  navigator.userLanguage.substring(0,2)://only use the prefix part for now, 
-                  navigator.language.substring(0,2),    //e.g. en-CA becomes just en
-    defaultLangCode: 'en',
-    
-    /**
-     * APIMethod: OpenLayers.String.translate
-     * uses the key into a dictionary of values based on the current language string.
-     * any number of additional arguments. If additional arguments are passed,
-     *  they will be interpolated in the string in order.
-     * 
-     * Parameters:
-     * key - {String} The key for an i18n string value in the dictionary
-     * 
-     * Returns:
-     * {String} A internationalized string
-     */
-    translate: function(key) {
-      var langCode = OpenLayers.String.langCode;
-      if (!OpenLayers.Strings[langCode]) {
-        var msg = 'failed to find ' +OpenLayers.String.langCode+ ' dictionary, falling back to default language';
-        OpenLayers.Console.log(msg);
-        OpenLayers.Strings[langCode] = OpenLayers.Strings[OpenLayers.String.defaultLangCode];
-        langCode = OpenLayers.String.defaultLangCode;
-      }
-      
-      var dictionary = OpenLayers.Strings[langCode];
-      var message = "NoMsgsFound";
-      var msgValue = dictionary[key];
-      if (!msgValue) {
-        // Message not found, fall back to message key
-        message = key;
-      } else {
-        // Message found; pick last one so user can override messages
-        message = msgValue;
-        if (arguments[this.translate.length]) {
-          // Extra arguments, format message
-          var varArgs = [].slice.call(arguments, this.translate.length);
-          varArgs.unshift(message);
-          message = this.formatMessage.apply(this, varArgs);
-        }
-      }
-      return message;
-    },
-    
-  /**
-     * APIMethod: OpenLayers.String.formatMessage
-     * Formats a message template with the extra arguments. 
-     * E.g. if called as: <code>OpenLayers.String.formatMessage("{1} is {0} {2}, {1}", "a good", "this", "test")</code>
-     * the formatted message returned is: <code>"this is a good test, this"</code>
-     *
-     * Parameters:
-     * messageTemplate  the message format string
-     * args       optional extra parameters for formatting the message
-     *
-     * Returns:
-     * the formatted message
-     */
-    formatMessage: function(messageTemplate)
-    {
-      var message = messageTemplate;
-      var varArgs = [].slice.call(arguments, this.formatMessage.length);
-      for (var i in varArgs) {
-        var parm = new RegExp("\\{" + i + "\\}", "g");
-        message = message.replace(parm, varArgs[i]);
-      }
-      return message;
-    }
-};
-
-/**
- * Header: OpenLayers Strings
- * OpenLayers I18n strings in various langauges.  Default language is English, langcode='en'
- */
-OpenLayers.Strings = {};
-
-if (!String.prototype.startsWith) {
-    /**
-     * APIMethod: String.startsWith
-     * *Deprecated*. Whether or not a string starts with another string. 
-     * 
-     * Parameters:
-     * sStart - {Sring} The string we're testing for.
-     *  
-     * Returns:
-     * {Boolean} Whether or not this string starts with the string passed in.
-     */
-    String.prototype.startsWith = function(sStart) {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                              "OpenLayers.String.startsWith"));
-        return OpenLayers.String.startsWith(this, sStart);
-    };
-}
-
-if (!String.prototype.contains) {
-    /**
-     * APIMethod: String.contains
-     * *Deprecated*. Whether or not a string contains another string.
-     * 
-     * Parameters:
-     * str - {String} The string that we're testing for.
-     * 
-     * Returns:
-     * {Boolean} Whether or not this string contains with the string passed in.
-     */
-    String.prototype.contains = function(str) {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                              "OpenLayers.String.contains"));
-        return OpenLayers.String.contains(this, str);
-    };
-}
-
-if (!String.prototype.trim) {
-    /**
-     * APIMethod: String.trim
-     * *Deprecated*. Removes leading and trailing whitespace characters from a string.
-     * 
-     * Returns:
-     * {String} A trimmed version of the string - all leading and 
-     *          trailing spaces removed
-     */
-    String.prototype.trim = function() {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                              "OpenLayers.String.trim"));
-        return OpenLayers.String.trim(this);
-    };
-}
-
-if (!String.prototype.camelize) {
-    /**
-     * APIMethod: String.camelize
-     * *Deprecated*. Camel-case a hyphenated string. 
-     *     Ex. "chicken-head" becomes "chickenHead", and
-     *     "-chicken-head" becomes "ChickenHead".
-     * 
-     * Returns:
-     * {String} The string, camelized
-     */
-    String.prototype.camelize = function() {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                              "OpenLayers.String.camelize"));
-        return OpenLayers.String.camelize(this);
-    };
-}
-
-/*********************
- *                   *
- *      NUMBER       * 
- *                   * 
- *********************/
-
-OpenLayers.Number = {
-    /**
-     * APIMethod: OpenLayers.Number.limitSigDigs
-     * Limit the number of significant digits on an integer.
-     * 
-     * Parameters:
-     * num - {Integer}
-     * sig - {Integer}
-     * 
-     * Returns:
-     * {Integer} The number, rounded to the specified number of significant
-     *     digits.
-     */
-    limitSigDigs: function(num, sig) {
-        var fig;
-        if(sig > 0) {
-            fig = parseFloat(num.toPrecision(sig));
-        } else {
-            fig = 0;
-        }
-        return fig;
-    }
-};
-
-if (!Number.prototype.limitSigDigs) {
-    /**
-     * APIMethod: Number.limitSigDigs
-     * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
-     *     work with floats!
-     * 
-     * Parameters:
-     * sig - {Integer}
-     * 
-     * Returns:
-     * {Integer} The number, rounded to the specified number of significant digits.
-     *           If null, 0, or negative value passed in, returns 0
-     */
-    Number.prototype.limitSigDigs = function(sig) {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                            "OpenLayers.Number.limitSigDigs"));
-        return OpenLayers.Number.limitSigDigs(this, sig);
-    };
-}
-
-/*********************
- *                   *
- *      FUNCTION     * 
- *                   * 
- *********************/
-
-OpenLayers.Function = {
-    /**
-     * APIMethod: OpenLayers.Function.bind
-     * Bind a function to an object.  Method to easily create closures with
-     *     'this' altered.
-     * 
-     * Parameters:
-     * func - {Function} Input function.
-     * object - {Object} The object to bind to the input function (as this).
-     * 
-     * Returns:
-     * {Function} A closure with 'this' set to the passed in object.
-     */
-    bind: function(func, object) {
-        // create a reference to all arguments past the second one
-        var args = Array.prototype.slice.apply(arguments, [2]);
-        return function() {
-            // Push on any additional arguments from the actual function call.
-            // These will come after those sent to the bind call.
-            var newArgs = args.concat(
-                Array.prototype.slice.apply(arguments, [0])
-            );
-            return func.apply(object, newArgs);
-        };
-    },
-    
-    /**
-     * APIMethod: OpenLayers.Function.bindAsEventListener
-     * Bind a function to an object, and configure it to receive the event
-     *     object as first parameter when called. 
-     * 
-     * Parameters:
-     * func - {Function} Input function to serve as an event listener.
-     * object - {Object} A reference to this.
-     * 
-     * Returns:
-     * {Function}
-     */
-    bindAsEventListener: function(func, object) {
-        return function(event) {
-            return func.call(object, event || window.event);
-        };
-    }
-};
-
-if (!Function.prototype.bind) {
-    /**
-     * APIMethod: Function.bind
-     * *Deprecated*. Bind a function to an object. 
-     * Method to easily create closures with 'this' altered.
-     * 
-     * Parameters:
-     * object - {Object} the this parameter
-     * 
-     * Returns:
-     * {Function} A closure with 'this' altered to the first
-     *            argument.
-     */
-    Function.prototype.bind = function() {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                              "OpenLayers.Function.bind"));
-        // new function takes the same arguments with this function up front
-        Array.prototype.unshift.apply(arguments, [this]);
-        return OpenLayers.Function.bind.apply(null, arguments);
-    };
-}
-
-if (!Function.prototype.bindAsEventListener) {
-    /**
-     * APIMethod: Function.bindAsEventListener
-     * *Deprecated*. Bind a function to an object, and configure it to receive the
-     *     event object as first parameter when called. 
-     * 
-     * Parameters:
-     * object - {Object} A reference to this.
-     * 
-     * Returns:
-     * {Function}
-     */
-    Function.prototype.bindAsEventListener = function(object) {
-        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
-                                    "OpenLayers.Function.bindAsEventListener"));
-        return OpenLayers.Function.bindAsEventListener(this, object);
-    };
-}
-/* ======================================================================
-    OpenLayers/BaseTypes/Class.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Constructor: OpenLayers.Class
- * Base class used to construct all other classes. Includes support for 
- *     multiple inheritance. 
- *     
- * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
- *     syntax for creating classes and dealing with inheritance 
- *     will be removed.
- * 
- * To create a new OpenLayers-style class, use the following syntax:
- * > var MyClass = OpenLayers.Class(prototype);
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- *     following syntax:
- * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- *
- */
-OpenLayers.Class = function() {
-    var Class = function() {
-        /**
-         * This following condition can be removed at 3.0 - this is only for
-         * backwards compatibility while the Class.inherit method is still
-         * in use.  So at 3.0, the following three lines would be replaced with
-         * simply:
-         * this.initialize.apply(this, arguments);
-         */
-        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
-            this.initialize.apply(this, arguments);
-        }
-    }
-    var extended = {};
-    var parent;
-    for(var i=0; i<arguments.length; ++i) {
-        if(typeof arguments[i] == "function") {
-            // get the prototype of the superclass
-            parent = arguments[i].prototype;
-        } else {
-            // in this case we're extending with the prototype
-            parent = arguments[i];
-        }
-        OpenLayers.Util.extend(extended, parent);
-    }
-    Class.prototype = extended;
-    return Class;
-}
-
-/**
- * Property: isPrototype
- * *Deprecated*.  This is no longer needed and will be removed at 3.0.
- */
-OpenLayers.Class.isPrototype = function () {};
-
-/**
- * APIFunction: OpenLayers.create
- * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
- *     <OpenLayers.Class> constructor instead.
- *
- * Returns:
- * An OpenLayers class
- */
-OpenLayers.Class.create = function() {
-    return function() {
-        if (arguments && arguments[0] != OpenLayers.Class.isPrototype)
-            this.initialize.apply(this, arguments);
-    }
-}
-
-
-/**
- * APIFunction: inherit
- * *Deprecated*.  Old method to inherit from one or more OpenLayers style
- *     classes.  Use the <OpenLayers.Class> constructor instead.
- *
- * Parameters:
- * class - One or more classes can be provided as arguments
- *
- * Returns:
- * An object prototype
- */
-OpenLayers.Class.inherit = function () {
-    var superClass = arguments[0];
-    var proto = new superClass(OpenLayers.Class.isPrototype);
-    for (var i = 1; i < arguments.length; i++) {
-        if (typeof arguments[i] == "function") {
-            var mixin = arguments[i];
-            arguments[i] = new mixin(OpenLayers.Class.isPrototype);
-        }
-        OpenLayers.Util.extend(proto, arguments[i]);
-    }
-    return proto;
-}
-/* ======================================================================
-    OpenLayers/BaseTypes/Size.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Size
- * Instances of this class represent a width/height pair
- */
-OpenLayers.Size = OpenLayers.Class({
-
-    /**
-     * APIProperty: w
-     * {Number} width
-     */
-    w: 0.0,
-    
-    /**
-     * APIProperty: h
-     * {Number} height
-     */
-    h: 0.0,
-
-
-    /**
-     * Constructor: OpenLayers.Size
-     * Create an instance of OpenLayers.Size
-     *
-     * Parameters:
-     * w - {Number} width
-     * h - {Number} height
-     */
-    initialize: function(w, h) {
-        this.w = parseFloat(w);
-        this.h = parseFloat(h);
-    },
-
-    /**
-     * Method: toString
-     * Return the string representation of a size object
-     *
-     * Returns:
-     * {String} The string representation of OpenLayers.Size object. 
-     * (ex. <i>"w=55,h=66"</i>)
-     */
-    toString:function() {
-        return ("w=" + this.w + ",h=" + this.h);
-    },
-
-    /**
-     * APIMethod: clone
-     * Create a clone of this size object
-     *
-     * Returns:
-     * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
-     * values
-     */
-    clone:function() {
-        return new OpenLayers.Size(this.w, this.h);
-    },
-
-    /**
-     *
-     * APIMethod: equals
-     * Determine where this size is equal to another
-     *
-     * Parameters:
-     * sz - {<OpenLayers.Size>}
-     *
-     * Returns: 
-     * {Boolean} The passed in size has the same h and w properties as this one.
-     * Note that if sz passed in is null, returns false.
-     *
-     */
-    equals:function(sz) {
-        var equals = false;
-        if (sz != null) {
-            equals = ((this.w == sz.w && this.h == sz.h) ||
-                      (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
-        }
-        return equals;
-    },
-
-    CLASS_NAME: "OpenLayers.Size"
-});
-/* ======================================================================
-    OpenLayers/BaseTypes/Bounds.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Bounds
- * Instances of this class represent bounding boxes.  Data stored as left,
- * bottom, right, top floats. All values are initialized to null, however,
- * you should make sure you set them before using the bounds for anything.
- * 
- * Possible use case:
- * > bounds = new OpenLayers.Bounds();
- * > bounds.extend(new OpenLayers.LonLat(4,5));
- * > bounds.extend(new OpenLayers.LonLat(5,6));
- * > bounds.toBBOX(); // returns 4,5,5,6
- */
-OpenLayers.Bounds = OpenLayers.Class({
-
-    /**
-     * Property: left
-     * {Number}
-     */
-    left: null,
-
-    /**
-     * Property: bottom
-     * {Number}
-     */
-    bottom: null,
-
-    /**
-     * Property: right
-     * {Number}
-     */
-    right: null,
-
-    /**
-     * Property: top
-     * {Number}
-     */
-    top: null,    
-
-    /**
-     * Constructor: OpenLayers.Bounds
-     * Construct a new bounds object.
-     *
-     * Parameters:
-     * left - {Number} The left bounds of the box.  Note that for width
-     *        calculations, this is assumed to be less than the right value.
-     * bottom - {Number} The bottom bounds of the box.  Note that for height
-     *          calculations, this is assumed to be more than the top value.
-     * right - {Number} The right bounds.
-     * top - {Number} The top bounds.
-     */
-    initialize: function(left, bottom, right, top) {
-        if (left != null) {
-            this.left = parseFloat(left);
-        }
-        if (bottom != null) {
-            this.bottom = parseFloat(bottom);
-        }
-        if (right != null) {
-            this.right = parseFloat(right);
-        }
-        if (top != null) {
-            this.top = parseFloat(top);
-        }
-    },
-
-    /**
-     * Method: clone
-     * Create a cloned instance of this bounds.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} A fresh copy of the bounds
-     */
-    clone:function() {
-        return new OpenLayers.Bounds(this.left, this.bottom, 
-                                     this.right, this.top);
-    },
-
-    /**
-     * Method: equals
-     * Test a two bounds for equivalence.
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {Boolean} The passed-in bounds object has the same left,
-     *           right, top, bottom components as this.  Note that if bounds 
-     *           passed in is null, returns false.
-     */
-    equals:function(bounds) {
-        var equals = false;
-        if (bounds != null) {
-            equals = ((this.left == bounds.left) && 
-                      (this.right == bounds.right) &&
-                      (this.top == bounds.top) && 
-                      (this.bottom == bounds.bottom));
-        }
-        return equals;
-    },
-
-    /** 
-     * APIMethod: toString
-     * 
-     * Returns:
-     * {String} String representation of bounds object. 
-     *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
-     */
-    toString:function() {
-        return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
-                 + " right-top=(" + this.right + "," + this.top + ")" );
-    },
-
-    /**
-     * APIMethod: toArray
-     *
-     * Returns:
-     * {Array} array of left, bottom, right, top
-     */
-    toArray: function() {
-        return [this.left, this.bottom, this.right, this.top];
-    },    
-
-    /** 
-     * APIMethod: toBBOX
-     * 
-     * Parameters:
-     * decimal - {Integer} How many significant digits in the bbox coords?
-     *                     Default is 6
-     * 
-     * Returns:
-     * {String} Simple String representation of bounds object.
-     *          (ex. <i>"5,42,10,45"</i>)
-     */
-    toBBOX:function(decimal) {
-        if (decimal== null) {
-            decimal = 6; 
-        }
-        var mult = Math.pow(10, decimal);
-        var bbox = Math.round(this.left * mult) / mult + "," + 
-                   Math.round(this.bottom * mult) / mult + "," + 
-                   Math.round(this.right * mult) / mult + "," + 
-                   Math.round(this.top * mult) / mult;
-
-        return bbox;
-    },
-    
-    /**
-     * APIMethod: getWidth
-     * 
-     * Returns:
-     * {Float} The width of the bounds
-     */
-    getWidth:function() {
-        return (this.right - this.left);
-    },
-
-    /**
-     * APIMethod: getHeight
-     * 
-     * Returns:
-     * {Float} The height of the bounds (top minus bottom).
-     */
-    getHeight:function() {
-        return (this.top - this.bottom);
-    },
-
-    /**
-     * APIMethod: getSize
-     * 
-     * Returns:
-     * {<OpenLayers.Size>} The size of the box.
-     */
-    getSize:function() {
-        return new OpenLayers.Size(this.getWidth(), this.getHeight());
-    },
-
-    /**
-     * APIMethod: getCenterPixel
-     * 
-     * Returns:
-     * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
-     */
-    getCenterPixel:function() {
-        return new OpenLayers.Pixel( (this.left + this.right) / 2,
-                                     (this.bottom + this.top) / 2);
-    },
-
-    /**
-     * APIMethod: getCenterLonLat
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} The center of the bounds in map space.
-     */
-    getCenterLonLat:function() {
-        return new OpenLayers.LonLat( (this.left + this.right) / 2,
-                                      (this.bottom + this.top) / 2);
-    },
-
-    /**
-     * APIMethod: add
-     * 
-     * Parameters:
-     * x - {Float}
-     * y - {Float}
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
-     *     this, but shifted by the passed-in x and y values.
-     */
-    add:function(x, y) {
-        if ( (x == null) || (y == null) ) {
-            var msg = OpenLayers.String.translate("boundsAddError");
-            OpenLayers.Console.error(msg);
-            return null;
-        }
-        return new OpenLayers.Bounds(this.left + x, this.bottom + y,
-                                     this.right + x, this.top + y);
-    },
-    
-    /**
-     * APIMethod: extend
-     * Extend the bounds to include the point, lonlat, or bounds specified.
-     *     Note, this function assumes that left < right and bottom < top.
-     * 
-     * Parameters: 
-     * object - {Object} Can be LonLat, Point, or Bounds
-     */
-    extend:function(object) {
-        var bounds = null;
-        if (object) {
-            switch(object.CLASS_NAME) {
-                case "OpenLayers.LonLat":    
-                    bounds = new OpenLayers.Bounds(object.lon, object.lat,
-                                                    object.lon, object.lat);
-                    break;
-                case "OpenLayers.Geometry.Point":
-                    bounds = new OpenLayers.Bounds(object.x, object.y,
-                                                    object.x, object.y);
-                    break;
-                    
-                case "OpenLayers.Bounds":    
-                    bounds = object;
-                    break;
-            }
-    
-            if (bounds) {
-                if ( (this.left == null) || (bounds.left < this.left)) {
-                    this.left = bounds.left;
-                }
-                if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
-                    this.bottom = bounds.bottom;
-                } 
-                if ( (this.right == null) || (bounds.right > this.right) ) {
-                    this.right = bounds.right;
-                }
-                if ( (this.top == null) || (bounds.top > this.top) ) { 
-                    this.top = bounds.top;
-                }
-            }
-        }
-    },
-
-    /**
-     * APIMethod: containsLonLat
-     * 
-     * Parameters:
-     * ll - {<OpenLayers.LonLat>}
-     * inclusive - {Boolean} Whether or not to include the border.
-     *     Default is true.
-     *
-     * Returns:
-     * {Boolean} The passed-in lonlat is within this bounds.
-     */
-    containsLonLat:function(ll, inclusive) {
-        return this.contains(ll.lon, ll.lat, inclusive);
-    },
-
-    /**
-     * APIMethod: containsPixel
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     * inclusive - {Boolean} Whether or not to include the border. Default is
-     *     true.
-     *
-     * Returns:
-     * {Boolean} The passed-in pixel is within this bounds.
-     */
-    containsPixel:function(px, inclusive) {
-        return this.contains(px.x, px.y, inclusive);
-    },
-    
-    /**
-     * APIMethod: contains
-     * 
-     * Parameters:
-     * x - {Float}
-     * y - {Float}
-     * inclusive - {Boolean} Whether or not to include the border. Default is
-     *     true.
-     *
-     * Returns:
-     * {Boolean} Whether or not the passed-in coordinates are within this
-     *     bounds.
-     */
-    contains:function(x, y, inclusive) {
-    
-        //set default
-        if (inclusive == null) {
-            inclusive = true;
-        }
-        
-        var contains = false;
-        if (inclusive) {
-            contains = ((x >= this.left) && (x <= this.right) && 
-                        (y >= this.bottom) && (y <= this.top));
-        } else {
-            contains = ((x > this.left) && (x < this.right) && 
-                        (y > this.bottom) && (y < this.top));
-        }              
-        return contains;
-    },
-
-    /**
-     * APIMethod: intersectsBounds
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * inclusive - {<Boolean>} Whether or not to include the border.  Default
-     *     is true.
-     *
-     * Returns:
-     * {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
-     *     Simple math just check if either contains the other, allowing for
-     *     partial.
-     */
-    intersectsBounds:function(bounds, inclusive) {
-
-        if (inclusive == null) {
-            inclusive = true;
-        }
-        var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
-                    true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) || 
-                           ((this.bottom > bounds.bottom) && (this.bottom < bounds.top))); 
-        var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
-                    true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
-                           ((this.top > bounds.bottom) && (this.top < bounds.top))); 
-        var inRight = (bounds.right == this.right && bounds.left == this.left) ?
-                    true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
-                           ((this.right > bounds.left) && (this.right < bounds.right))); 
-        var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
-                    true : (((bounds.left > this.left) && (bounds.left < this.right)) || 
-                           ((this.left > bounds.left) && (this.left < bounds.right))); 
-
-        return (this.containsBounds(bounds, true, inclusive) ||
-                bounds.containsBounds(this, true, inclusive) ||
-                ((inTop || inBottom ) && (inLeft || inRight )));
-    },
-    
-    /**
-     * APIMethod: containsBounds
-     * 
-     * bounds - {<OpenLayers.Bounds>}
-     * partial - {<Boolean>} If true, only part of passed-in bounds needs be
-     *     within this bounds.  If false, the entire passed-in bounds must be
-     *     within. Default is false
-     * inclusive - {<Boolean>} Whether or not to include the border. Default is
-     *     true.
-     *
-     * Returns:
-     * {Boolean} The passed-in bounds object is contained within this bounds. 
-     */
-    containsBounds:function(bounds, partial, inclusive) {
-
-        //set defaults
-        if (partial == null) {
-            partial = false;
-        }
-        if (inclusive == null) {
-            inclusive = true;
-        }
-
-        var inLeft;
-        var inTop;
-        var inRight;
-        var inBottom;
-        
-        if (inclusive) {
-            inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
-            inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
-            inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
-            inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
-        } else {
-            inLeft = (bounds.left > this.left) && (bounds.left < this.right);
-            inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
-            inRight= (bounds.right > this.left) && (bounds.right < this.right);
-            inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
-        }
-        
-        return (partial) ? (inTop || inBottom ) && (inLeft || inRight ) 
-                         : (inTop && inLeft && inBottom && inRight);
-    },
-
-    /** 
-     * APIMethod: determineQuadrant
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     * 
-     * Returns:
-     * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
-     *     coordinate lies.
-     */
-    determineQuadrant: function(lonlat) {
-    
-        var quadrant = "";
-        var center = this.getCenterLonLat();
-        
-        quadrant += (lonlat.lat < center.lat) ? "b" : "t";
-        quadrant += (lonlat.lon < center.lon) ? "l" : "r";
-    
-        return quadrant; 
-    },
-
-    /**
-     * APIMethod: wrapDateLine
-     *  
-     * Parameters:
-     * maxExtent - {<OpenLayers.Bounds>}
-     * options - {Object} Some possible options are:
-     *                    leftTolerance - {float} Allow for a margin of error 
-     *                                            with the 'left' value of this 
-     *                                            bound.
-     *                                            Default is 0.
-     *                    rightTolerance - {float} Allow for a margin of error 
-     *                                             with the 'right' value of 
-     *                                             this bound.
-     *                                             Default is 0.
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
-     *                       "dateline" (as specified by the borders of 
-     *                       maxExtent). Note that this function only returns 
-     *                       a different bounds value if this bounds is 
-     *                       *entirely* outside of the maxExtent. If this 
-     *                       bounds straddles the dateline (is part in/part 
-     *                       out of maxExtent), the returned bounds will be 
-     *                       merely a copy of this one.
-     */
-    wrapDateLine: function(maxExtent, options) {    
-        options = options || {};
-        
-        var leftTolerance = options.leftTolerance || 0;
-        var rightTolerance = options.rightTolerance || 0;
-
-        var newBounds = this.clone();
-    
-        if (maxExtent) {
-
-           //shift right?
-           while ( newBounds.left < maxExtent.left && 
-                   (newBounds.right - rightTolerance) <= maxExtent.left ) { 
-                newBounds = newBounds.add(maxExtent.getWidth(), 0);
-           }
-
-           //shift left?
-           while ( (newBounds.left + leftTolerance) >= maxExtent.right && 
-                   newBounds.right > maxExtent.right ) { 
-                newBounds = newBounds.add(-maxExtent.getWidth(), 0);
-           }
-        }
-                
-        return newBounds;
-    },
-
-    CLASS_NAME: "OpenLayers.Bounds"
-});
-
-/** 
- * APIFunction: fromString
- * Alternative constructor that builds a new OpenLayers.Bounds from a 
- *     parameter string
- * 
- * Parameters: 
- * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
- * 
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the 
- *                       passed-in String.
- */
-OpenLayers.Bounds.fromString = function(str) {
-    var bounds = str.split(",");
-    return OpenLayers.Bounds.fromArray(bounds);
-};
-
-/** 
- * APIFunction: fromArray
- * Alternative constructor that builds a new OpenLayers.Bounds
- *     from an array
- * 
- * Parameters:
- * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
- */
-OpenLayers.Bounds.fromArray = function(bbox) {
-    return new OpenLayers.Bounds(parseFloat(bbox[0]),
-                                 parseFloat(bbox[1]),
-                                 parseFloat(bbox[2]),
-                                 parseFloat(bbox[3]));
-};
-
-/** 
- * APIFunction: fromSize
- * Alternative constructor that builds a new OpenLayers.Bounds
- *     from a size
- * 
- * Parameters:
- * size - {<OpenLayers.Size>} 
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
- */
-OpenLayers.Bounds.fromSize = function(size) {
-    return new OpenLayers.Bounds(0,
-                                 size.h,
-                                 size.w,
-                                 0);
-};
-
-/**
- * Function: oppositeQuadrant
- * Get the opposite quadrant for a given quadrant string.
- *
- * Parameters:
- * quadrant - {String} two character quadrant shortstring
- *
- * Returns:
- * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
- *          you pass in "bl" it returns "tr", if you pass in "br" it 
- *          returns "tl", etc.
- */
-OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
-    var opp = "";
-    
-    opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
-    opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
-    
-    return opp;
-};
-/* ======================================================================
-    OpenLayers/BaseTypes/Element.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Namespace: OpenLayers.Element
- */
-OpenLayers.Element = {
-
-    /**
-     * APIFunction: visible
-     * 
-     * Parameters: 
-     * element - {DOMElement}
-     * 
-     * Returns:
-     * {Boolean} Is the element visible?
-     */
-    visible: function(element) {
-        return OpenLayers.Util.getElement(element).style.display != 'none';
-    },
-
-    /**
-     * APIFunction: toggle
-     * Toggle the visibility of element(s) passed in
-     * 
-     * Parameters:
-     * element - {DOMElement} Actually user can pass any number of elements
-     */
-    toggle: function() {
-        for (var i = 0; i < arguments.length; i++) {
-            var element = OpenLayers.Util.getElement(arguments[i]);
-            var display = OpenLayers.Element.visible(element) ? 'hide' 
-                                                              : 'show';
-            OpenLayers.Element[display](element);
-        }
-    },
-
-
-    /**
-     * APIFunction: hide
-     * Hide element(s) passed in
-     * 
-     * Parameters:
-     * element - {DOMElement} Actually user can pass any number of elements
-     */
-    hide: function() {
-        for (var i = 0; i < arguments.length; i++) {
-            var element = OpenLayers.Util.getElement(arguments[i]);
-            element.style.display = 'none';
-        }
-    },
-
-    /**
-     * APIFunction: show
-     * Show element(s) passed in
-     * 
-     * Parameters:
-     * element - {DOMElement} Actually user can pass any number of elements
-     */
-    show: function() {
-        for (var i = 0; i < arguments.length; i++) {
-            var element = OpenLayers.Util.getElement(arguments[i]);
-            element.style.display = '';
-        }
-    },
-
-    /**
-     * APIFunction: remove
-     * Remove the specified element from the DOM.
-     * 
-     * Parameters:
-     * element - {DOMElement}
-     */
-    remove: function(element) {
-        element = OpenLayers.Util.getElement(element);
-        element.parentNode.removeChild(element);
-    },
-
-    /**
-     * APIFunction: getHeight
-     *  
-     * Parameters:
-     * element - {DOMElement}
-     * 
-     * Returns:
-     * {Integer} The offset height of the element passed in
-     */
-    getHeight: function(element) {
-        element = OpenLayers.Util.getElement(element);
-        return element.offsetHeight;
-    },
-
-    /**
-     * APIFunction: getDimensions
-     *  
-     * Parameters:
-     * element - {DOMElement}
-     * 
-     * Returns:
-     * {Object} Object with 'width' and 'height' properties which are the 
-     *          dimensions of the element passed in.
-     */
-    getDimensions: function(element) {
-        element = OpenLayers.Util.getElement(element);
-        if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
-            return {width: element.offsetWidth, height: element.offsetHeight};
-        }
-    
-        // All *Width and *Height properties give 0 on elements with display none,
-        // so enable the element temporarily
-        var els = element.style;
-        var originalVisibility = els.visibility;
-        var originalPosition = els.position;
-        els.visibility = 'hidden';
-        els.position = 'absolute';
-        els.display = '';
-        var originalWidth = element.clientWidth;
-        var originalHeight = element.clientHeight;
-        els.display = 'none';
-        els.position = originalPosition;
-        els.visibility = originalVisibility;
-        return {width: originalWidth, height: originalHeight};
-    },
-
-    /**
-     * APIFunction: getStyle
-     * 
-     * Parameters:
-     * element - {DOMElement}
-     * style - {?}
-     * 
-     * Returns:
-     * {?}
-     */
-    getStyle: function(element, style) {
-        element = OpenLayers.Util.getElement(element);
-        var value = element.style[OpenLayers.String.camelize(style)];
-        if (!value) {
-            if (document.defaultView && 
-                document.defaultView.getComputedStyle) {
-                
-                var css = document.defaultView.getComputedStyle(element, null);
-                value = css ? css.getPropertyValue(style) : null;
-            } else if (element.currentStyle) {
-                value = element.currentStyle[OpenLayers.String.camelize(style)];
-            }
-        }
-    
-        var positions = ['left', 'top', 'right', 'bottom'];
-        if (window.opera &&
-            (OpenLayers.Util.indexOf(positions,style) != -1) &&
-            (OpenLayers.Element.getStyle(element, 'position') == 'static')) { 
-            value = 'auto';
-        }
-    
-        return value == 'auto' ? null : value;
-    }
-
-};
-/* ======================================================================
-    OpenLayers/BaseTypes/LonLat.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.LonLat
- * This class represents a longitude and latitude pair
- */
-OpenLayers.LonLat = OpenLayers.Class({
-
-    /** 
-     * APIProperty: lon
-     * {Float} The x-axis coodinate in map units
-     */
-    lon: 0.0,
-    
-    /** 
-     * APIProperty: lat
-     * {Float} The y-axis coordinate in map units
-     */
-    lat: 0.0,
-
-    /**
-     * Constructor: OpenLayers.LonLat
-     * Create a new map location.
-     *
-     * Parameters:
-     * lon - {Number} The x-axis coordinate in map units.  If your map is in
-     *     a geographic projection, this will be the Longitude.  Otherwise,
-     *     it will be the x coordinate of the map location in your map units.
-     * lat - {Number} The y-axis coordinate in map units.  If your map is in
-     *     a geographic projection, this will be the Latitude.  Otherwise,
-     *     it will be the y coordinate of the map location in your map units.
-     */
-    initialize: function(lon, lat) {
-        this.lon = parseFloat(lon);
-        this.lat = parseFloat(lat);
-    },
-    
-    /**
-     * Method: toString
-     * Return a readable string version of the lonlat
-     *
-     * Returns:
-     * {String} String representation of OpenLayers.LonLat object. 
-     *           (ex. <i>"lon=5,lat=42"</i>)
-     */
-    toString:function() {
-        return ("lon=" + this.lon + ",lat=" + this.lat);
-    },
-
-    /** 
-     * APIMethod: toShortString
-     * 
-     * Returns:
-     * {String} Shortened String representation of OpenLayers.LonLat object. 
-     *         (ex. <i>"5, 42"</i>)
-     */
-    toShortString:function() {
-        return (this.lon + ", " + this.lat);
-    },
-
-    /** 
-     * APIMethod: clone
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
-     *                       and lat values
-     */
-    clone:function() {
-        return new OpenLayers.LonLat(this.lon, this.lat);
-    },
-
-    /** 
-     * APIMethod: add
-     * 
-     * Parameters:
-     * lon - {Float}
-     * lat - {Float}
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
-     *                       lat passed-in added to this's. 
-     */
-    add:function(lon, lat) {
-        if ( (lon == null) || (lat == null) ) {
-            var msg = OpenLayers.String.translate("lonlatAddError");
-            OpenLayers.Console.error(msg);
-            return null;
-        }
-        return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
-    },
-
-    /** 
-     * APIMethod: equals
-     * 
-     * Parameters:
-     * ll - {<OpenLayers.LonLat>}
-     * 
-     * Returns:
-     * {Boolean} Boolean value indicating whether the passed-in 
-     *           <OpenLayers.LonLat> object has the same lon and lat 
-     *           components as this.
-     *           Note: if ll passed in is null, returns false
-     */
-    equals:function(ll) {
-        var equals = false;
-        if (ll != null) {
-            equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
-                      (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
-        }
-        return equals;
-    },
-    
-    /**
-     * APIMethod: wrapDateLine
-     * 
-     * Parameters:
-     * maxExtent - {<OpenLayers.Bounds>}
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
-     *                       "dateline" (as specified by the borders of 
-     *                       maxExtent)
-     */
-    wrapDateLine: function(maxExtent) {    
-
-        var newLonLat = this.clone();
-    
-        if (maxExtent) {
-            //shift right?
-            while (newLonLat.lon < maxExtent.left) {
-                newLonLat.lon +=  maxExtent.getWidth();
-            }    
-           
-            //shift left?
-            while (newLonLat.lon > maxExtent.right) {
-                newLonLat.lon -= maxExtent.getWidth();
-            }    
-        }
-                
-        return newLonLat;
-    },
-
-    CLASS_NAME: "OpenLayers.LonLat"
-});
-
-/** 
- * Function: fromString
- * Alternative constructor that builds a new <OpenLayers.LonLat> from a 
- *     parameter string
- * 
- * Parameters:
- * str - {String} Comma-separated Lon,Lat coordinate string. 
- *                 (ex. <i>"5,40"</i>)
- * 
- * Returns:
- * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
- *                       passed-in String.
- */
-OpenLayers.LonLat.fromString = function(str) {
-    var pair = str.split(",");
-    return new OpenLayers.LonLat(parseFloat(pair[0]), 
-                                 parseFloat(pair[1]));
-};
-/* ======================================================================
-    OpenLayers/BaseTypes/Pixel.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Pixel
- * This class represents a screen coordinate, in x and y coordinates
- */
-OpenLayers.Pixel = OpenLayers.Class({
-    
-    /**
-     * APIProperty: x
-     * {Number} The x coordinate
-     */
-    x: 0.0,
-
-    /**
-     * APIProperty: y
-     * {Number} The y coordinate
-     */
-    y: 0.0,
-    
-    /**
-     * Constructor: OpenLayers.Pixel
-     * Create a new OpenLayers.Pixel instance
-     *
-     * Parameters:
-     * x - {Number} The x coordinate
-     * y - {Number} The y coordinate
-     *
-     * Returns:
-     * An instance of OpenLayers.Pixel
-     */
-    initialize: function(x, y) {
-        this.x = parseFloat(x);
-        this.y = parseFloat(y);
-    },
-    
-    /**
-     * Method: toString
-     * Cast this object into a string
-     *
-     * Returns:
-     * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
-     */
-    toString:function() {
-        return ("x=" + this.x + ",y=" + this.y);
-    },
-
-    /**
-     * APIMethod: clone
-     * Return a clone of this pixel object
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} A clone pixel
-     */
-    clone:function() {
-        return new OpenLayers.Pixel(this.x, this.y); 
-    },
-    
-    /**
-     * APIMethod: equals
-     * Determine whether one pixel is equivalent to another
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {Boolean} The point passed in as parameter is equal to this. Note that
-     * if px passed in is null, returns false.
-     */
-    equals:function(px) {
-        var equals = false;
-        if (px != null) {
-            equals = ((this.x == px.x && this.y == px.y) ||
-                      (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
-        }
-        return equals;
-    },
-
-    /**
-     * APIMethod: add
-     *
-     * Parameters:
-     * x - {Integer}
-     * y - {Integer}
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
-     * values passed in.
-     */
-    add:function(x, y) {
-        if ( (x == null) || (y == null) ) {
-            var msg = OpenLayers.String.translate("pixelAddError");
-            OpenLayers.Console.error(msg);
-            return null;
-        }
-        return new OpenLayers.Pixel(this.x + x, this.y + y);
-    },
-
-    /**
-    * APIMethod: offset
-    * 
-    * Parameters
-    * px - {<OpenLayers.Pixel>}
-    * 
-    * Returns:
-    * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
-    *                      x&y values of the pixel passed in.
-    */
-    offset:function(px) {
-        var newPx = this.clone();
-        if (px) {
-            newPx = this.add(px.x, px.y);
-        }
-        return newPx;
-    },
-
-    CLASS_NAME: "OpenLayers.Pixel"
-});
-/* ======================================================================
-    OpenLayers/Ajax.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-OpenLayers.ProxyHost = "";
-//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
-
-/**
- * Ajax reader for OpenLayers
- *
- *  @uri url to do remote XML http get
- *  @param {String} 'get' format params (x=y&a=b...)
- *  @who object to handle callbacks for this request
- *  @complete  the function to be called on success 
- *  @failure  the function to be called on failure
- *  
- *   example usage from a caller:
- *  
- *     caps: function(request) {
- *      -blah-  
- *     },
- *  
- *     OpenLayers.loadURL(url,params,this,caps);
- *
- * Notice the above example does not provide an error handler; a default empty
- * handler is provided which merely logs the error if a failure handler is not 
- * supplied
- *
- */
-
-
-/** 
-* @param {} request
-*/
-OpenLayers.nullHandler = function(request) {
-    alert(OpenLayers.String.translate("unhandledRequest", request.statusText));
-};
-
-/** 
- * Function: loadURL
- * Background load a document.
- *
- * Parameters:
- * uri - {String} URI of source doc
- * params - {String} Params on get (doesnt seem to work)
- * caller - {Object} object which gets callbacks
- * onComplete - {Function} callback for success
- * onFailure - {Function} callback for failure
- *
- * Both callbacks optional (though silly)
- */
-OpenLayers.loadURL = function(uri, params, caller,
-                                  onComplete, onFailure) {
-
-    if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(uri, "http")) {
-        uri = OpenLayers.ProxyHost + escape(uri);
-    }
-
-    var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
-                                : OpenLayers.nullHandler;
-
-    var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
-                           : OpenLayers.nullHandler;
-
-    // from prototype.js
-    new OpenLayers.Ajax.Request(uri, 
-                     {   method: 'get', 
-                         parameters: params,
-                         onComplete: success, 
-                         onFailure: failure
-                      }
-                     );
-};
-
-/** 
- * Function: parseXMLString
- * Parse XML into a doc structure
- * 
- * Parameters:
- * text - {String} 
- * 
- * Returns:
- * {?} Parsed AJAX Responsev
- */
-OpenLayers.parseXMLString = function(text) {
-
-    //MS sucks, if the server is bad it dies
-    var index = text.indexOf('<');
-    if (index > 0) {
-        text = text.substring(index);
-    }
-
-    var ajaxResponse = OpenLayers.Util.Try(
-        function() {
-            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
-            xmldom.loadXML(text);
-            return xmldom;
-        },
-        function() {
-            return new DOMParser().parseFromString(text, 'text/xml');
-        },
-        function() {
-            var req = new XMLHttpRequest();
-            req.open("GET", "data:" + "text/xml" +
-                     ";charset=utf-8," + encodeURIComponent(text), false);
-            if (req.overrideMimeType) {
-                req.overrideMimeType("text/xml");
-            }
-            req.send(null);
-            return req.responseXML;
-        }
-    );
-
-    return ajaxResponse;
-};
-
-
-/**
- * Namespace: OpenLayers.Ajax
- */
-OpenLayers.Ajax = {
-
-    /**
-     * Method: emptyFunction
-     */
-    emptyFunction: function () {},
-
-    /**
-     * Method: getTransport
-     * 
-     * Returns: 
-     * {Object} Transport mechanism for whichever browser we're in, or false if
-     *          none available.
-     */
-    getTransport: function() {
-        return OpenLayers.Util.Try(
-            function() {return new ActiveXObject('Msxml2.XMLHTTP')},
-            function() {return new ActiveXObject('Microsoft.XMLHTTP')},
-            function() {return new XMLHttpRequest()}
-        ) || false;
-    },
-
-    /**
-     * Property: activeRequestCount
-     * {Integer}
-     */
-    activeRequestCount: 0
-};
-
-/**
- * Namespace: OpenLayers.Ajax.Responders
- * {Object}
- */
-OpenLayers.Ajax.Responders = {
-  
-    /**
-     * Property: responders
-     * {Array}
-     */
-    responders: [],
-
-    /**
-     * Method: register
-     *  
-     * Parameters:
-     * responderToAdd - {?}
-     */
-    register: function(responderToAdd) {
-      for (var i = 0; i < this.responders.length; i++)
-          if (responderToAdd == this.responders[i])
-              return;
-      this.responders.push(responderToAdd);
-    },
-
-    /**
-     * Method: dispatch
-     * 
-     * Parameters:
-     * callback - {?}
-     * request - {?}
-     * transport - {?}
-     * json - {?}
-     */
-    dispatch: function(callback, request, transport, json) {
-        var responder;
-        for (var i = 0; i < this.responders.length; i++) {
-            responder = this.responders[i];
-     
-            if (responder[callback] && 
-                typeof responder[callback] == 'function') {
-                try {
-                    responder[callback].apply(responder, 
-                                              [request, transport, json]);
-                } catch (e) {}
-            }
-        }
-    }
-};
-
-OpenLayers.Ajax.Responders.register({
-    /** 
-     * Function: onCreate
-     */
-    onCreate: function() {
-        OpenLayers.Ajax.activeRequestCount++;
-    },
-
-    /**
-     * Function: onComplete
-     */
-     onComplete: function() {
-         OpenLayers.Ajax.activeRequestCount--;
-     }
-});
-
-/**
- * Namespace: OpenLayers.Ajax.Base
- * {Object}
- */
-OpenLayers.Ajax.Base = function() {};
-OpenLayers.Ajax.Base.prototype = {
-
-    /**
-     * Function: setOptions
-     * 
-     * Parameters:
-     * options - {Object}
-     */
-    setOptions: function(options) {
-        this.options = {
-            'method': 'post',
-            'asynchronous': true,
-            'parameters': ''
-        };
-        OpenLayers.Util.extend(this.options, options || {});
-    },
-
-    /**
-     * Function: responseIsSuccess
-     * 
-     * Returns:
-     * {Boolean}
-     */
-    responseIsSuccess: function() {
-        return this.transport.status == undefined || 
-               this.transport.status == 0 || 
-               (this.transport.status >= 200 && this.transport.status < 300);
-    },
-
-    /**
-     * Function: responseIsFailure
-     * 
-     * Returns:
-     * {Boolean}
-     */
-    responseIsFailure: function() {
-        return !this.responseIsSuccess();
-    }
-};
-
-
-/**
- * Class: OpenLayers.Ajax.Request
- *
- * Inherit:
- *  - <OpenLayers.Ajax.Base>
- */
-OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
-      
-      /**
-       * Constructor: OpenLayers.Ajax.Request
-       * 
-       * Parameters: 
-       * url - {String}
-       * options - {Object}
-       */
-    initialize: function(url, options) {
-        this.transport = OpenLayers.Ajax.getTransport();
-        this.setOptions(options);
-        this.request(url);
-    },
-
-    /**
-     * Method: request
-     * 
-     * Parameters:
-     * url - {String}
-     */
-    request: function(url) {
-        var parameters = this.options.parameters || '';
-        if (parameters.length > 0) parameters += '&_=';
-    
-        try {
-            this.url = url;
-            if (this.options.method == 'get' && parameters.length > 0) {
-               this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
-            }
-            
-            OpenLayers.Ajax.Responders.dispatch('onCreate', 
-                                                this, 
-                                                this.transport);
-    
-            this.transport.open(this.options.method, 
-                                this.url,
-                                this.options.asynchronous);
-    
-            if (this.options.asynchronous) {
-                this.transport.onreadystatechange = 
-                    OpenLayers.Function.bind(this.onStateChange, this);
-                
-                setTimeout(OpenLayers.Function.bind(
-                    (function() {this.respondToReadyState(1)}),this), 10
-                );
-            }
-    
-            this.setRequestHeaders();
-    
-            var body = this.options.postBody ? this.options.postBody 
-                                             : parameters;
-            this.transport.send(this.options.method == 'post' ? body : null);
-    
-            // Force Firefox to handle ready state 4 for synchronous requests
-            if (!this.options.asynchronous && 
-                this.transport.overrideMimeType) {
-                
-                this.onStateChange();
-            }
-    
-        } catch (e) {
-            this.dispatchException(e);
-        }
-    },
-     
-    /**
-     * Method: setRequestHeaders
-     */
-    setRequestHeaders: function() {
-        var requestHeaders = [
-            'X-Requested-With',
-            'XMLHttpRequest',
-            'X-Prototype-Version',
-            'OpenLayers'
-        ];
-    
-        if (this.options.method == 'post' && !this.options.postBody) {
-            requestHeaders.push('Content-type',
-                                'application/x-www-form-urlencoded');
-    
-            // Force "Connection: close" for Mozilla browsers to work around
-            // a bug where XMLHttpReqeuest sends an incorrect Content-length
-            // header. See Mozilla Bugzilla #246651.
-            if (this.transport.overrideMimeType) {
-                requestHeaders.push('Connection', 'close');
-            }
-        }
-    
-        if (this.options.requestHeaders) {
-            requestHeaders.push.apply(requestHeaders, 
-                                      this.options.requestHeaders);
-        }
-          
-        for (var i = 0; i < requestHeaders.length; i += 2) {
-            this.transport.setRequestHeader(requestHeaders[i], 
-                                            requestHeaders[i+1]);
-        }
-    },
-
-    /**
-     * Method: onStateChange
-     */
-    onStateChange: function() {
-        var readyState = this.transport.readyState;
-        if (readyState != 1) {
-          this.respondToReadyState(this.transport.readyState);
-        }
-    },
-
-    /** 
-     * Method: header
-     * 
-     * Returns:
-     * {?}
-     */
-    header: function(name) {
-        try {
-            return this.transport.getResponseHeader(name);
-        } catch (e) {}
-    },
-
-    /** 
-     * Method: evalJSON
-     * 
-     * Returns:
-     * {?}
-     */
-    evalJSON: function() {
-        try {
-            return eval(this.header('X-JSON'));
-        } catch (e) {}
-    },
-
-    /**
-     * Method: evalResponse
-     * 
-     * Returns: 
-     * {?}
-     */
-    evalResponse: function() {
-        try {
-            return eval(this.transport.responseText);
-        } catch (e) {
-            this.dispatchException(e);
-        }
-    },
-
-    /**
-     * Method: respondToReadyState
-     *
-     * Parameters:
-     * readyState - {?}
-     */
-    respondToReadyState: function(readyState) {
-        var event = OpenLayers.Ajax.Request.Events[readyState];
-        var transport = this.transport, json = this.evalJSON();
-    
-        if (event == 'Complete') {
-            try {
-                var responseSuccess = this.responseIsSuccess() ? 'Success'
-                                                                : 'Failure';
-                                                                 
-                (this.options['on' + this.transport.status] ||
-                 this.options['on' + responseSuccess] ||
-                 OpenLayers.Ajax.emptyFunction)(transport, json);
-            } catch (e) {
-                this.dispatchException(e);
-            }
-    
-            var contentType = this.header('Content-type') || '';
-            if (contentType.match(/^text\/javascript/i)) {
-                this.evalResponse();
-            }
-        }
-    
-        try {
-            (this.options['on' + event] || 
-             OpenLayers.Ajax.emptyFunction)(transport, json);
-             OpenLayers.Ajax.Responders.dispatch('on' + event, 
-                                                 this, 
-                                                 transport, 
-                                                 json);
-        } catch (e) {
-            this.dispatchException(e);
-        }
-    
-        // Avoid memory leak in MSIE: clean up the oncomplete event handler
-        if (event == 'Complete') {
-            this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
-        }
-    },
-
-    /**
-     * Method: dispatchException
-     * 
-     * Parameters:
-     * exception - {?}
-     */
-    dispatchException: function(exception) {
-        if (this.options.onException) {
-            this.options.onException(this, exception);
-        } else {
-            // if we get here, Responders.dispatch('onException') will never
-            // be called. too bad. we should probably take out the Responders
-            // stuff anyway.
-            throw exception;
-        }
-        OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
-    }
-    
-});
-
-/** 
- * Property: Events
- * {Array(String)}
- */
-OpenLayers.Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-/**
- * Function: getElementsByTagNameNS
- * 
- * Parameters:
- * parentnode - {?}
- * nsuri - {?}
- * nsprefix - {?}
- * tagname - {?}
- * 
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
-                                                   nsprefix, tagname) {
-    var elem = null;
-    if (parentnode.getElementsByTagNameNS) {
-        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
-    } else {
-        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
-    }
-    return elem;
-};
-
-
-/**
- * Function: serializeXMLToString
- * Wrapper function around XMLSerializer, which doesn't exist/work in
- *     IE/Safari. We need to come up with a way to serialize in those browser:
- *     for now, these browsers will just fail. #535, #536
- *
- * Parameters: 
- * xmldom {XMLNode} xml dom to serialize
- * 
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
-    var serializer = new XMLSerializer();
-    data = serializer.serializeToString(xmldom);
-    return data;
-}
-/* ======================================================================
-    OpenLayers/Control.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Control
- * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by 
- * default are added to the map they are contained within however it is
- * possible to add a control to an external div by passing the div in the
- * options parameter.
- * 
- * Example:
- * The following example shows how to add many of the common controls
- * to a map.
- * 
- * > var map = new OpenLayers.Map('map', { controls: [] });
- * >
- * > map.addControl(new OpenLayers.Control.PanZoomBar());
- * > map.addControl(new OpenLayers.Control.MouseToolbar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
- *
- * The next code fragment is a quick example of how to intercept 
- * shift-mouse click to display the extent of the bounding box
- * dragged out by the user.  Usually controls are not created
- * in exactly this manner.  See the source for a more complete 
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * >     draw: function () {
- * >         // this Handler.Box will intercept the shift-mousedown
- * >         // before Control.MouseDefault gets to see it
- * >         this.box = new OpenLayers.Handler.Box( control, 
- * >             {"done": this.notice},
- * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * >         this.box.activate();
- * >     },
- * >
- * >     notice: function (bounds) {
- * >         alert(bounds);
- * >     }
- * > }); 
- * > map.addControl(control);
- * 
- */
-OpenLayers.Control = OpenLayers.Class({
-
-    /** 
-     * Property: id 
-     * {String} 
-     */
-    id: null,
-    
-    /** 
-     * Property: map 
-     * {<OpenLayers.Map>} this gets set in the addControl() function in
-     * OpenLayers.Map 
-     */
-    map: null,
-
-    /** 
-     * Property: div 
-     * {DOMElement} 
-     */
-    div: null,
-
-    /** 
-     * Property: type 
-     * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
-     * determines the type of interactions which are possible with them when
-     * they are placed into a toolbar. 
-     */
-    type: null, 
-
-    /** 
-     * Property: displayClass 
-     * {string}  This property is used for CSS related to the drawing of the
-     * Control. 
-     */
-    displayClass: "",
-
-    /** 
-     * Property: active 
-     * {boolean} null
-     */
-    active: null,
-
-    /** 
-     * Property: handler 
-     * {<OpenLayers.Handler>} null
-     */
-    handler: null,
-
-    /**
-     * Constructor: OpenLayers.Control
-     * Create an OpenLayers Control.  The options passed as a parameter
-     * directly extend the control.  For example passing the following:
-     * 
-     * > var control = new OpenLayers.Control({div: myDiv});
-     *
-     * Overrides the default div attribute value of null.
-     * 
-     * Parameters:
-     * options - {Object} 
-     */
-    initialize: function (options) {
-        // We do this before the extend so that instances can override
-        // className in options.
-        this.displayClass = 
-            this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-        
-        OpenLayers.Util.extend(this, options);
-        
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-    },
-
-    /**
-     * Method: destroy
-     * The destroy method is used to perform any clean up before the control
-     * is dereferenced.  Typically this is where event listeners are removed
-     * to prevent memory leaks.
-     */
-    destroy: function () {
-        // eliminate circular references
-        if (this.handler) {
-            this.handler.destroy();
-        }    
-        this.map = null;
-    },
-
-    /** 
-     * Method: setMap
-     * Set the map property for the control. This is done through an accessor
-     * so that subclasses can override this and take special action once 
-     * they have their map variable set. 
-     *
-     * Parameters:
-     * map - {<OpenLayers.Map>} 
-     */
-    setMap: function(map) {
-        this.map = map;
-        if (this.handler) {
-            this.handler.setMap(map);
-        }
-    },
-  
-    /**
-     * Method: draw
-     * The draw method is called when the control is ready to be displayed
-     * on the page.  If a div has not been created one is created.  Controls
-     * with a visual component will almost always want to override this method 
-     * to customize the look of control. 
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
-     *      or null.
-     *
-     * Returns:
-     * {DOMElement} A reference to the DIV DOMElement containing the control
-     */
-    draw: function (px) {
-        if (this.div == null) {
-            this.div = OpenLayers.Util.createDiv();
-            this.div.id = this.id;
-            this.div.className = this.displayClass;
-        }
-        if (px != null) {
-            this.position = px.clone();
-        }
-        this.moveTo(this.position);        
-        return this.div;
-    },
-
-    /**
-     * Method: moveTo
-     * Sets the left and top style attributes to the passed in pixel 
-     * coordinates.
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     */
-    moveTo: function (px) {
-        if ((px != null) && (this.div != null)) {
-            this.div.style.left = px.x + "px";
-            this.div.style.top = px.y + "px";
-        }
-    },
-
-    /**
-     * Method: activate
-     * Explicitly activates a control and it's associated
-     * handler if one has been set.  Controls can be
-     * deactivated by calling the deactivate() method.
-     * 
-     * Returns:
-     * {Boolean}  True if the control was successfully activated or
-     *            false if the control was already active.
-     */
-    activate: function () {
-        if (this.active) {
-            return false;
-        }
-        if (this.handler) {
-            this.handler.activate();
-        }
-        this.active = true;
-        return true;
-    },
-    
-    /**
-     * Method: deactivate
-     * Deactivates a control and it's associated handler if any.  The exact
-     * effect of this depends on the control itself.
-     * 
-     * Returns:
-     * {Boolean} True if the control was effectively deactivated or false
-     *           if the control was already inactive.
-     */
-    deactivate: function () {
-        if (this.active) {
-            if (this.handler) {
-                this.handler.deactivate();
-            }
-            this.active = false;
-            return true;
-        }
-        return false;
-    },
-
-    CLASS_NAME: "OpenLayers.Control"
-});
-
-OpenLayers.Control.TYPE_BUTTON = 1;
-OpenLayers.Control.TYPE_TOGGLE = 2;
-OpenLayers.Control.TYPE_TOOL   = 3;
-/* ======================================================================
-    OpenLayers/Icon.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * Class: OpenLayers.Icon
- * 
- * The icon represents a graphical icon on the screen.  Typically used in
- * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
- *
- * An icon has a url, size and position.  It also contains an offset which 
- * allows the center point to be represented correctly.  This can be
- * provided either as a fixed offset or a function provided to calculate
- * the desired offset. 
- * 
- */
-OpenLayers.Icon = OpenLayers.Class({
-    
-    /** 
-     * Property: url 
-     * {String}  image url
-     */
-    url: null,
-    
-    /** 
-     * Property: size 
-     * {<OpenLayers.Size>} 
-     */
-    size: null,
-
-    /** 
-     * Property: offset 
-     * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
-     */
-    offset: null,    
-    
-    /** 
-     * Property: calculateOffset 
-     * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size) 
-     */
-    calculateOffset: null,    
-    
-    /** 
-     * Property: imageDiv 
-     * {DOMElement} 
-     */
-    imageDiv: null,
-
-    /** 
-     * Property: px 
-     * {<OpenLayers.Pixel>} 
-     */
-    px: null,
-    
-    /** 
-     * Constructor: OpenLayers.Icon
-     * Creates an icon, which is an image tag in a div.  
-     *
-     * url - {String} 
-     * size - {<OpenLayers.Size>} 
-     * calculateOffset - {Function} 
-     */
-    initialize: function(url, size, offset, calculateOffset) {
-        this.url = url;
-        this.size = (size) ? size : new OpenLayers.Size(20,20);
-        this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
-        this.calculateOffset = calculateOffset;
-
-        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
-        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
-    },
-    
-    /** 
-     * Method: destroy
-     * Nullify references and remove event listeners to prevent circular 
-     * references and memory leaks
-     */
-    destroy: function() {
-        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); 
-        this.imageDiv.innerHTML = "";
-        this.imageDiv = null;
-    },
-
-    /** 
-     * Method: clone
-     * 
-     * Returns:
-     * {<OpenLayers.Icon>} A fresh copy of the icon.
-     */
-    clone: function() {
-        return new OpenLayers.Icon(this.url, 
-                                   this.size, 
-                                   this.offset, 
-                                   this.calculateOffset);
-    },
-    
-    /**
-     * Method: setSize
-     * 
-     * size - {<OpenLayers.Size>} 
-     */
-    setSize: function(size) {
-        if (size != null) {
-            this.size = size;
-        }
-        this.draw();
-    },
-
-    /** 
-     * Method: draw
-     * Move the div to the given pixel.
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} 
-     * 
-     * Returns:
-     * {DOMElement} A new DOM Image of this icon set at the location passed-in
-     */
-    draw: function(px) {
-        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, 
-                                            null, 
-                                            null, 
-                                            this.size, 
-                                            this.url, 
-                                            "absolute");
-        this.moveTo(px);
-        return this.imageDiv;
-    }, 
-
-    
-    /** 
-     * Method: setOpacity
-     * Change the icon's opacity
-     *
-     * Parameters:
-     * opacity - {float} 
-     */
-    setOpacity: function(opacity) {
-        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
-                                            null, null, null, null, opacity);
-
-    },
-    
-    /**
-     * Method: moveTo
-     * move icon to passed in px.
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} 
-     */
-    moveTo: function (px) {
-        //if no px passed in, use stored location
-        if (px != null) {
-            this.px = px;
-        }
-
-        if (this.imageDiv != null) {
-            if (this.px == null) {
-                this.display(false);
-            } else {
-                if (this.calculateOffset) {
-                    this.offset = this.calculateOffset(this.size);  
-                }
-                var offsetPx = this.px.offset(this.offset);
-                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
-            }
-        }
-    },
-    
-    /** 
-     * Method: display
-     * Hide or show the icon
-     *
-     * Parameters:
-     * display - {Boolean} 
-     */
-    display: function(display) {
-        this.imageDiv.style.display = (display) ? "" : "none"; 
-    },
-
-    CLASS_NAME: "OpenLayers.Icon"
-});
-/* ======================================================================
-    OpenLayers/Strings/en.js
-   ====================================================================== */
-
-OpenLayers.Strings.en = {
-'test1': 'this is a test',
-'test2': 'and another test',
-'test3': 'arg one:{0} arg two: {1}',
-'unhandledRequest': "Unhandled request return {0}",
-'permalink': "Permalink",
-'overlays': "Overlays",
-'baseLayer': "Base Layer",
-'sameProjection': "The overview map only works when it is in the same projection as the main map",
-'readNotImplemented': "Read not implemented.",
-'writeNotImplemented': "Write not implemented.",
-'noFID': "Can't update a feature for which there is no FID.",
-'errorLoadingGML': "Error in loading GML file {0}",
-'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
-'componentShouldBe': "addFeatures : component should be an {0}",
-'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
-                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
-'minZoomLevelError': "The minZoomLevel property is only intended for use " +
-                    "with the FixedZoomLevels-descendent layers. That this " +
-                    "wfs layer checks for minZoomLevel is a relic of the" +
-                    "past. We cannot, however, remove it without possibly " +
-                    "breaking OL based applications that may depend on it." +
-                    " Therefore we are deprecating it -- the minZoomLevel " +
-                    "check below will be removed at 3.0. Please instead " +
-                    "use min/max resolution setting as described here: " +
-                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
-'commitSuccess': "WFS Transaction: SUCCESS {0}",
-'commitFailed': "WFS Transaction: FAILED {0}",
-'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the Google Maps library " +
-                "script was either not included, or does not contain the " +
-                "correct API key for your site.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/Google' " +
-                "target='_blank'>click here</a>",
-'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the {0} library " +
-                "script was either not correctly included.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/{1}' " +
-                "target='_blank'>click here</a>",
-'scale': "Scale = 1 : {0}",
-'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
-'reprojectDeprecated': "You are using the 'reproject' option " +
-                "on the {0} layer. This option is deprecated: " +
-                "its use was designed to support displaying data over commercial " + 
-                "basemaps, but that functionality should now be achieved by using " +
-                "Spherical Mercator support. More information is available from " +
-                "http://trac.openlayers.org/wiki/SphericalMercator.",
-'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
-                "Please use {0} instead.",
-'boundsAddError': "You must pass both x and y values to the add function.",
-'lonlatAddError': "You must pass both lon and lat values to the add function.",
-'pixelAddError': "You must pass both x and y values to the add function.",
-'unsupportedGeometryType': "Unsupported geometry type: {0}",
-'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
-                " Please use 'array.length = 0' instead.",
-'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
-                "with the 3.0 version of OpenLayers. Please instead use " +
-                "OpenLayers.Util.getParameters().",
-'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
-                
-'end': ''
-};
-/* ======================================================================
-    OpenLayers/Control/ArgParser.js
-   ====================================================================== */
-
-/* Cpyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- *
- * Class: OpenLayers.Control.ArgParser
- * 
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
-
-    /**
-     * Parameter: center
-     * {<OpenLayers.LonLat>}
-     */
-    center: null,
-    
-    /**
-     * Parameter: zoom
-     * {int}
-     */
-    zoom: null,
-
-    /**
-     * Parameter: layers 
-     * {Array(<OpenLayers.Layer>)}
-     */
-    layers: null,
-
-    /**
-     * Constructor: OpenLayers.Control.ArgParser
-     *
-     * Parameters:
-     * options - {Object}
-     */
-    initialize: function(options) {
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * Method: setMap
-     * Set the map property for the control. 
-     * 
-     * Parameters:
-     * map - {<OpenLayers.Map>} 
-     */
-    setMap: function(map) {
-        OpenLayers.Control.prototype.setMap.apply(this, arguments);
-
-        //make sure we dont already have an arg parser attached
-        for(var i=0; i< this.map.controls.length; i++) {
-            var control = this.map.controls[i];
-            if ( (control != this) &&
-                 (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
-                break;
-            }
-        }
-        if (i == this.map.controls.length) {
-
-            var args = OpenLayers.Util.getParameters();
-            if (args.lat && args.lon) {
-                this.center = new OpenLayers.LonLat(parseFloat(args.lon),
-                                                    parseFloat(args.lat));
-                if (args.zoom) {
-                    this.zoom = parseInt(args.zoom);
-                }
-    
-                // when we add a new baselayer to see when we can set the center
-                this.map.events.register('changebaselayer', this, 
-                                         this.setCenter);
-                this.setCenter();
-            }
-    
-            if (args.layers) {
-                this.layers = args.layers;
-    
-                // when we add a new layer, set its visibility 
-                this.map.events.register('addlayer', this, 
-                                         this.configureLayers);
-                this.configureLayers();
-            }
-        }
-    },
-   
-    /** 
-     * Method: setCenter
-     * As soon as a baseLayer has been loaded, we center and zoom
-     *   ...and remove the handler.
-     */
-    setCenter: function() {
-        
-        if (this.map.baseLayer) {
-            //dont need to listen for this one anymore
-            this.map.events.unregister('changebaselayer', this, 
-                                       this.setCenter);
-                                       
-            this.map.setCenter(this.center, this.zoom);
-        }
-    },
-
-    /** 
-     * Method: configureLayers
-     * As soon as all the layers are loaded, cycle through them and 
-     *   hide or show them. 
-     */
-    configureLayers: function() {
-
-        if (this.layers.length == this.map.layers.length) { 
-            this.map.events.unregister('addlayer', this, this.configureLayers);
-
-            for(var i=0; i < this.layers.length; i++) {
-                
-                var layer = this.map.layers[i];
-                var c = this.layers.charAt(i);
-                
-                if (c == "B") {
-                    this.map.setBaseLayer(layer);
-                } else if ( (c == "T") || (c == "F") ) {
-                    layer.setVisibility(c == "T");
-                }
-            }
-        }
-    },     
-
-    CLASS_NAME: "OpenLayers.Control.ArgParser"
-});
-/* ======================================================================
-    OpenLayers/Control/PanZoom.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- *
- * Class: OpenLayers.PanZoom
- * 
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
-
-    /** 
-     * APIProperty: slideFactor
-     * {Integer}
-     */
-    slideFactor: 50,
-
-    /** 
-     * Property: buttons
-     * {Array(DOMElement)} Array of Button Divs 
-     */
-    buttons: null,
-
-    /** 
-     * Property: position
-     * {<OpenLayers.Pixel>} 
-     */
-    position: null,
-
-    /**
-     * Constructor: OpenLayers.Control.PanZoom
-     * 
-     * Parameters:
-     * options - {Object}
-     */
-    initialize: function(options) {
-        this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
-                                             OpenLayers.Control.PanZoom.Y);
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    destroy: function() {
-        OpenLayers.Control.prototype.destroy.apply(this, arguments);
-        while(this.buttons.length) {
-            var btn = this.buttons.shift();
-            btn.map = null;
-            OpenLayers.Event.stopObservingElement(btn);
-        }
-        this.buttons = null;
-        this.position = null;
-    },
-
-    /**
-     * Method: draw
-     *
-     * Parameters:
-     * px - {<OpenLayers.Pixel>} 
-     * 
-     * Returns:
-     * {DOMElement} A reference to the container div for the PanZoom control.
-     */
-    draw: function(px) {
-        // initialize our internal div
-        OpenLayers.Control.prototype.draw.apply(this, arguments);
-        px = this.position;
-
-        // place the controls
-        this.buttons = [];
-
-        var sz = new OpenLayers.Size(18,18);
-        var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
-
-        this._addButton("panup", "north-mini.png", centered, sz);
-        px.y = centered.y+sz.h;
-        this._addButton("panleft", "west-mini.png", px, sz);
-        this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
-        this._addButton("pandown", "south-mini.png", 
-                        centered.add(0, sz.h*2), sz);
-        this._addButton("zoomin", "zoom-plus-mini.png", 
-                        centered.add(0, sz.h*3+5), sz);
-        this._addButton("zoomworld", "zoom-world-mini.png", 
-                        centered.add(0, sz.h*4+5), sz);
-        this._addButton("zoomout", "zoom-minus-mini.png", 
-                        centered.add(0, sz.h*5+5), sz);
-        return this.div;
-    },
-    
-    /**
-     * Method: _addButton
-     * 
-     * Parameters:
-     * id - {String} 
-     * img - {String} 
-     * xy - {<OpenLayers.Pixel>} 
-     * sz - {<OpenLayers.Size>} 
-     * 
-     * Returns:
-     * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
-     *     image of the button, and has all the proper event handlers set.
-     */
-    _addButton:function(id, img, xy, sz) {
-        var imgLocation = OpenLayers.Util.getImagesLocation() + img;
-        var btn = OpenLayers.Util.createAlphaImageDiv(
-                                    "OpenLayers_Control_PanZoom_" + id, 
-                                    xy, sz, imgLocation, "absolute");
-
-        //we want to add the outer div
-        this.div.appendChild(btn);
-
-        OpenLayers.Event.observe(btn, "mousedown", 
-            OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
-        OpenLayers.Event.observe(btn, "dblclick", 
-            OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
-        OpenLayers.Event.observe(btn, "click", 
-            OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
-        btn.action = id;
-        btn.map = this.map;
-        btn.slideFactor = this.slideFactor;
-
-        //we want to remember/reference the outer div
-        this.buttons.push(btn);
-        return btn;
-    },
-    
-    /**
-     * Method: doubleClick
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean}
-     */
-    doubleClick: function (evt) {
-        OpenLayers.Event.stop(evt);
-        return false;
-    },
-    
-    /**
-     * Method: buttonDown
-     *
-     * Parameters:
-     * evt - {Event} 
-     */
-    buttonDown: function (evt) {
-        if (!OpenLayers.Event.isLeftClick(evt)) return;
-
-        switch (this.action) {
-            case "panup": 
-                this.map.pan(0, -50);
-                break;
-            case "pandown": 
-                this.map.pan(0, 50);
-                break;
-            case "panleft": 
-                this.map.pan(-50, 0);
-                break;
-            case "panright": 
-                this.map.pan(50, 0);
-                break;
-            case "zoomin": 
-                this.map.zoomIn(); 
-                break;
-            case "zoomout": 
-                this.map.zoomOut(); 
-                break;
-            case "zoomworld": 
-                this.map.zoomToMaxExtent(); 
-                break;
-        }
-
-        OpenLayers.Event.stop(evt);
-    },
-
-    CLASS_NAME: "OpenLayers.Control.PanZoom"
-});
-
-/**
- * Constant: X
- * {Integer}
- */
-OpenLayers.Control.PanZoom.X = 4;
-
-/**
- * Constant: Y
- * {Integer}
- */
-OpenLayers.Control.PanZoom.Y = 4;
-/* ======================================================================
-    OpenLayers/Events.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- *
- * Namespace: OpenLayers.Event
- * Utility functions for event handling.
- */
-OpenLayers.Event = {
-
-    /** 
-     * Property: observers 
-     * {Object} A hashtable cache of the event observers. Keyed by
-     * element._eventCacheID 
-     */
-    observers: false,
-    
-    /** 
-     * Constant: KEY_BACKSPACE 
-     * {int} 
-     */
-    KEY_BACKSPACE: 8,
-
-    /** 
-     * Constant: KEY_TAB 
-     * {int} 
-     */
-    KEY_TAB: 9,
-
-    /** 
-     * Constant: KEY_RETURN 
-     * {int} 
-     */
-    KEY_RETURN: 13,
-
-    /** 
-     * Constant: KEY_ESC 
-     * {int} 
-     */
-    KEY_ESC: 27,
-
-    /** 
-     * Constant: KEY_LEFT 
-     * {int} 
-     */
-    KEY_LEFT: 37,
-
-    /** 
-     * Constant: KEY_UP 
-     * {int} 
-     */
-    KEY_UP: 38,
-
-    /** 
-     * Constant: KEY_RIGHT 
-     * {int} 
-     */
-    KEY_RIGHT: 39,
-
-    /** 
-     * Constant: KEY_DOWN 
-     * {int} 
-     */
-    KEY_DOWN: 40,
-
-    /** 
-     * Constant: KEY_DELETE 
-     * {int} 
-     */
-    KEY_DELETE: 46,
-
-
-    /**
-     * Method: element
-     * Cross browser event element detection.
-     * 
-     * Parameters:
-     * event - {Event} 
-     * 
-     * Returns:
-     * {DOMElement} The element that caused the event 
-     */
-    element: function(event) {
-        return event.target || event.srcElement;
-    },
-
-    /**
-     * Method: isLeftClick
-     * Determine whether event was caused by a left click. 
-     *
-     * Parameters:
-     * event - {Event} 
-     * 
-     * Returns:
-     * {Boolean}
-     */
-    isLeftClick: function(event) {
-        return (((event.which) && (event.which == 1)) ||
-                ((event.button) && (event.button == 1)));
-    },
-
-    /**
-     * Method: stop
-     * Stops an event from propagating. 
-     *
-     * Parameters: 
-     * event - {Event} 
-     * allowDefault - {Boolean} If true, we stop the event chain but 
-     *                               still allow the default browser 
-     *                               behaviour (text selection, radio-button 
-     *                               clicking, etc)
-     *                               Default false
-     */
-    stop: function(event, allowDefault) {
-        
-        if (!allowDefault) { 
-            if (event.preventDefault) {
-                event.preventDefault();
-            } else {
-                event.returnValue = false;
-            }
-        }
-                
-        if (event.stopPropagation) {
-            event.stopPropagation();
-        } else {
-            event.cancelBubble = true;
-        }
-    },
-
-    /** 
-     * Method: findElement
-     * 
-     * Parameters:
-     * event - {Event} 
-     * tagName - {String} 
-     * 
-     * Returns:
-     * {DOMElement} The first node with the given tagName, starting from the
-     * node the event was triggered on and traversing the DOM upwards
-     */
-    findElement: function(event, tagName) {
-        var element = OpenLayers.Event.element(event);
-        while (element.parentNode && (!element.tagName ||
-              (element.tagName.toUpperCase() != tagName.toUpperCase())))
-            element = element.parentNode;
-        return element;
-    },
-
-    /** 
-     * Method: observe
-     * 
-     * Parameters:
-     * elementParam - {DOMElement || String} 
-     * name - {String} 
-     * observer - {function} 
-     * useCapture - {Boolean} 
-     */
-    observe: function(elementParam, name, observer, useCapture) {
-        var element = OpenLayers.Util.getElement(elementParam);
-        useCapture = useCapture || false;
-
-        if (name == 'keypress' &&
-           (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-           || element.attachEvent)) {
-            name = 'keydown';
-        }
-
-        //if observers cache has not yet been created, create it
-        if (!this.observers) {
-            this.observers = {};
-        }
-
-        //if not already assigned, make a new unique cache ID
-        if (!element._eventCacheID) {
-            var idPrefix = "eventCacheID_";
-            if (element.id) {
-                idPrefix = element.id + "_" + idPrefix;
-            }
-            element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
-        }
-
-        var cacheID = element._eventCacheID;
-
-        //if there is not yet a hash entry for this element, add one
-        if (!this.observers[cacheID]) {
-            this.observers[cacheID] = [];
-        }
-
-        //add a new observer to this element's list
-        this.observers[cacheID].push({
-            'element': element,
-            'name': name,
-            'observer': observer,
-            'useCapture': useCapture
-        });
-
-        //add the actual browser event listener
-        if (element.addEventListener) {
-            element.addEventListener(name, observer, useCapture);
-        } else if (element.attachEvent) {
-            element.attachEvent('on' + name, observer);
-        }
-    },
-
-    /** 
-     * Method: stopObservingElement
-     * Given the id of an element to stop observing, cycle through the 
-     *   element's cached observers, calling stopObserving on each one, 
-     *   skipping those entries which can no longer be removed.
-     * 
-     * parameters:
-     * elementParam - {DOMElement || String} 
-     */
-    stopObservingElement: function(elementParam) {
-        var element = OpenLayers.Util.getElement(elementParam);
-        var cacheID = element._eventCacheID;
-
-        this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
-    },
-
-    /**
-     * Method: _removeElementObservers
-     *
-     * Parameters:
-     * elementObservers - {Array(Object)} Array of (element, name, 
-     *                                         observer, usecapture) objects, 
-     *                                         taken directly from hashtable
-     */
-    _removeElementObservers: function(elementObservers) {
-        if (elementObservers) {
-            for(var i = elementObservers.length-1; i >= 0; i--) {
-                var entry = elementObservers[i];
-                var args = new Array(entry.element,
-                                     entry.name,
-                                     entry.observer,
-                                     entry.useCapture);
-                var removed = OpenLayers.Event.stopObserving.apply(this, args);
-            }
-        }
-    },
-
-    /**
-     * Method: stopObserving
-     * 
-     * Parameters:
-     * elementParam - {DOMElement || String} 
-     * name - {String} 
-     * observer - {function} 
-     * useCapture - {Boolean} 
-     *  
-     * Returns:
-     * {Boolean} Whether or not the event observer was removed
-     */
-    stopObserving: function(elementParam, name, observer, useCapture) {
-        useCapture = useCapture || false;
-    
-        var element = OpenLayers.Util.getElement(elementParam);
-        var cacheID = element._eventCacheID;
-
-        if (name == 'keypress') {
-            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || 
-                 element.detachEvent) {
-              name = 'keydown';
-            }
-        }
-
-        // find element's entry in this.observers cache and remove it
-        var foundEntry = false;
-        var elementObservers = OpenLayers.Event.observers[cacheID];
-        if (elementObservers) {
-    
-            // find the specific event type in the element's list
-            var i=0;
-            while(!foundEntry && i < elementObservers.length) {
-                var cacheEntry = elementObservers[i];
-    
-                if ((cacheEntry.name == name) &&
-                    (cacheEntry.observer == observer) &&
-                    (cacheEntry.useCapture == useCapture)) {
-    
-                    elementObservers.splice(i, 1);
-                    if (elementObservers.length == 0) {
-                        delete OpenLayers.Event.observers[cacheID];
-                    }
-                    foundEntry = true;
-                    break; 
-                }
-                i++;           
-            }
-        }
-    
-        //actually remove the event listener from browser
-        if (element.removeEventListener) {
-            element.removeEventListener(name, observer, useCapture);
-        } else if (element && element.detachEvent) {
-            element.detachEvent('on' + name, observer);
-        }
-        return foundEntry;
-    },
-    
-    /** 
-     * Method: unloadCache
-     * Cycle through all the element entries in the events cache and call
-     *   stopObservingElement on each. 
-     */
-    unloadCache: function() {
-        if (OpenLayers.Event.observers) {
-            for (var cacheID in OpenLayers.Event.observers) {
-                var elementObservers = OpenLayers.Event.observers[cacheID];
-                OpenLayers.Event._removeElementObservers.apply(this, 
-                                                           [elementObservers]);
-            }
-            OpenLayers.Event.observers = false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Event"
-};
-
-/* prevent memory leaks in IE */
-OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
-
-// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
-// by OpenLayers.
-if (window.Event) {
-    OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
-} else {
-    var Event = OpenLayers.Event;
-}
-
-/**
- * Class: OpenLayers.Events
- */
-OpenLayers.Events = OpenLayers.Class({
-
-    /** 
-     * Constant: BROWSER_EVENTS
-     * {Array(String)} supported events 
-     */
-    BROWSER_EVENTS: [
-        "mouseover", "mouseout",
-        "mousedown", "mouseup", "mousemove", 
-        "click", "dblclick",
-        "resize", "focus", "blur"
-    ],
-
-    /** 
-     * Property: listeners 
-     * {Object} Hashtable of Array(Function): events listener functions  
-     */
-    listeners: null,
-
-    /** 
-     * Property: object 
-     * {Object}  the code object issuing application events 
-     */
-    object: null,
-
-    /** 
-     * Property: element 
-     * {DOMElement}  the DOM element receiving browser events 
-     */
-    element: null,
-
-    /** 
-     * Property: eventTypes 
-     * {Array(String)}  list of support application events 
-     */
-    eventTypes: null,
-
-    /** 
-     * Property: eventHandler 
-     * {Function}  bound event handler attached to elements 
-     */
-    eventHandler: null,
-
-    /** 
-     * APIProperty: fallThrough 
-     * {Boolean} 
-     */
-    fallThrough: null,
-
-    /**
-     * Constructor: OpenLayers.Events
-     * Construct an OpenLayers.Events object.
-     *
-     * Parameters:
-     * object - {Object} The js object to which this Events object  is being
-     * added element - {DOMElement} A dom element to respond to browser events
-     * eventTypes - {Array(String)} Array of custom application events 
-     * fallThrough - {Boolean} Allow events to fall through after these have
-     *                         been handled?
-     */
-    initialize: function (object, element, eventTypes, fallThrough) {
-        this.object     = object;
-        this.element    = element;
-        this.eventTypes = eventTypes;
-        this.fallThrough = fallThrough;
-        this.listeners  = {};
-
-        // keep a bound copy of handleBrowserEvent() so that we can
-        // pass the same function to both Event.observe() and .stopObserving()
-        this.eventHandler = OpenLayers.Function.bindAsEventListener(
-            this.handleBrowserEvent, this
-        );
-
-        // if eventTypes is specified, create a listeners list for each 
-        // custom application event.
-        if (this.eventTypes != null) {
-            for (var i = 0; i < this.eventTypes.length; i++) {
-                this.addEventType(this.eventTypes[i]);
-            }
-        }
-        
-        // if a dom element is specified, add a listeners list 
-        // for browser events on the element and register them
-        if (this.element != null) {
-            this.attachToElement(element);
-        }
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    destroy: function () {
-        if (this.element) {
-            OpenLayers.Event.stopObservingElement(this.element);
-        }
-        this.element = null;
-
-        this.listeners = null;
-        this.object = null;
-        this.eventTypes = null;
-        this.fallThrough = null;
-        this.eventHandler = null;
-    },
-
-    /**
-     * APIMethod: addEventType
-     * Add a new event type to this events object.
-     * If the event type has already been added, do nothing.
-     * 
-     * Parameters:
-     * eventName - {String}
-     */
-    addEventType: function(eventName) {
-        if (!this.listeners[eventName]) {
-            this.listeners[eventName] = [];
-        }
-    },
-
-    /**
-     * Method: attachToElement
-     *
-     * Parameters:
-     * element - {HTMLDOMElement} a DOM element to attach browser events to
-     */
-    attachToElement: function (element) {
-        for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
-            var eventType = this.BROWSER_EVENTS[i];
-
-            // every browser event has a corresponding application event 
-            // (whether it's listened for or not).
-            this.addEventType(eventType);
-            
-            // use Prototype to register the event cross-browser
-            OpenLayers.Event.observe(element, eventType, this.eventHandler);
-        }
-        // disable dragstart in IE so that mousedown/move/up works normally
-        OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
-    },
-
-    /**
-     * APIMethod: register
-     * Register an event on the events object.
-     *
-     * When the event is triggered, the 'func' function will be called, in the
-     * context of 'obj'. Imagine we were to register an event, specifying an 
-     * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the 
-     * context in the callback function will be our Bounds object. This means
-     * that within our callback function, we can access the properties and 
-     * methods of the Bounds object through the "this" variable. So our 
-     * callback could execute something like: 
-     * :    leftStr = "Left: " + this.left;
-     *   
-     *                   or
-     *  
-     * :    centerStr = "Center: " + this.getCenterLonLat();
-     *
-     * Parameters:
-     * type - {String} Name of the event to register
-     * obj - {Object} The object to bind the context to for the callback#.
-     *                     If no object is specified, default is the Events's 
-     *                     'object' property.
-     * func - {Function} The callback function. If no callback is 
-     *                        specified, this function does nothing.
-     * 
-     * 
-     */
-    register: function (type, obj, func) {
-
-        if (func != null) {
-            if (obj == null)  {
-                obj = this.object;
-            }
-            var listeners = this.listeners[type];
-            if (listeners != null) {
-                listeners.push( {obj: obj, func: func} );
-            }
-        }
-    },
-
-    /**
-     * APIMethod: registerPriority
-     * Same as register() but adds the new listener to the *front* of the
-     *     events queue instead of to the end.
-     *    
-     *     TODO: get rid of this in 3.0 - Decide whether listeners should be 
-     *     called in the order they were registered or in reverse order.
-     *
-     *
-     * Parameters:
-     * type - {String} Name of the event to register
-     * obj - {Object} The object to bind the context to for the callback#.
-     *                If no object is specified, default is the Events's 
-     *                'object' property.
-     * func - {Function} The callback function. If no callback is 
-     *                   specified, this function does nothing.
-     */
-    registerPriority: function (type, obj, func) {
-
-        if (func != null) {
-            if (obj == null)  {
-                obj = this.object;
-            }
-            var listeners = this.listeners[type];
-            if (listeners != null) {
-                listeners.unshift( {obj: obj, func: func} );
-            }
-        }
-    },
-    
-    /**
-     * APIMethod: unregister
-     *
-     * Parameters:
-     * type - {String} 
-     * obj - {Object} If none specified, defaults to this.object
-     * func - {Function} 
-     */
-    unregister: function (type, obj, func) {
-        if (obj == null)  {
-            obj = this.object;
-        }
-        var listeners = this.listeners[type];
-        if (listeners != null) {
-            for (var i = 0; i < listeners.length; i++) {
-                if (listeners[i].obj == obj && listeners[i].func == func) {
-                    listeners.splice(i, 1);
-                    break;
-                }
-            }
-        }
-    },
-
-    /** 
-     * Method: remove
-     * Remove all listeners for a given event type. If type is not registered,
-     *     does nothing.
-     *
-     * Parameters:
-     * type - {String} 
-     */
-    remove: function(type) {
-        if (this.listeners[type] != null) {
-            this.listeners[type] = [];
-        }
-    },
-
-    /**
-     * APIMethod: triggerEvent
-     * Trigger a specified registered event
-     * 
-     * Parameters:
-     * type - {String} 
-     * evt - {Event} 
-     */
-    triggerEvent: function (type, evt) {
-
-        // prep evt object with object & div references
-        if (evt == null) {
-            evt = {};
-        }
-        evt.object = this.object;
-        evt.element = this.element;
-
-        // execute all callbacks registered for specified type
-        // get a clone of the listeners array to
-        // allow for splicing during callbacks
-        var listeners = (this.listeners[type]) ?
-                            this.listeners[type].slice() : null;
-        if ((listeners != null) && (listeners.length > 0)) {
-            for (var i = 0; i < listeners.length; i++) {
-                var callback = listeners[i];
-                var continueChain;
-                if (callback.obj != null) {
-                    // use the 'call' method to bind the context to callback.obj
-                    continueChain = callback.func.call(callback.obj, evt);
-                } else {
-                    continueChain = callback.func(evt);
-                }
-    
-                if ((continueChain != null) && (continueChain == false)) {
-                    // if callback returns false, execute no more callbacks.
-                    break;
-                }
-            }
-            // don't fall through to other DOM elements
-            if (!this.fallThrough) {           
-                OpenLayers.Event.stop(evt, true);
-            }
-        }
-    },
-
-    /**
-     * Method: handleBrowserEvent
-     * Basically just a wrapper to the triggerEvent() function, but takes 
-     *     care to set a property 'xy' on the event with the current mouse 
-     *     position.
-     *
-     * Parameters:
-     * evt - {Event} 
-     */
-    handleBrowserEvent: function (evt) {
-        evt.xy = this.getMousePosition(evt); 
-        this.triggerEvent(evt.type, evt)
-    },
-
-    /**
-     * Method: getMousePosition
-     * 
-     * Parameters:
-     * evt - {Event} 
-     * 
-     * Returns 
-     * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
-     *                      for offsets
-     */
-    getMousePosition: function (evt) {
-        if (!this.element.offsets) {
-            this.element.offsets = OpenLayers.Util.pagePosition(this.element);
-            this.element.offsets[0] += (document.documentElement.scrollLeft
-                         || document.body.scrollLeft);
-            this.element.offsets[1] += (document.documentElement.scrollTop
-                         || document.body.scrollTop);
-        }
-        return new OpenLayers.Pixel(
-            (evt.clientX + (document.documentElement.scrollLeft
-                         || document.body.scrollLeft)) - this.element.offsets[0]
-                         - (document.documentElement.clientLeft || 0), 
-            (evt.clientY + (document.documentElement.scrollTop
-                         || document.body.scrollTop)) - this.element.offsets[1]
-                         - (document.documentElement.clientTop || 0)
-        ); 
-    },
-
-    CLASS_NAME: "OpenLayers.Events"
-});
-/* ======================================================================
-    OpenLayers/Projection.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Util.js
- * 
- * Class: OpenLayers.Projection
- * Class for coordinate transformations between coordinate systems.
- * Depends on the proj4js library. If proj4js is not available, 
- * then this is just an empty stub.
- */
-OpenLayers.Projection = OpenLayers.Class({
-    
-    /**
-     * Constructor: OpenLayers.Projection
-     * This class offers several methods for interacting with a wrapped 
-     * pro4js projection object. 
-     *
-     * Parameters:
-     * options - {Object} An optional object with properties to set on the
-     *           format
-     *
-     * Returns:
-     * An instance of OpenLayers.Projection
-     */
-    initialize: function(projCode, options) {
-        OpenLayers.Util.extend(this, options);
-        this.projCode = projCode;
-        if (window.Proj4js) {
-            this.proj = new Proj4js.Proj(projCode);
-        }
-        
-    },
-    
-    /**
-     * APIMethod: getCode
-     * Get the string SRS code.
-     */
-    getCode: function() {
-        return this.proj ? this.proj.srsCode : this.projCode;
-    },
-    
-    /**
-     * APIMethod: getUnits
-     * Get the units string for the projection -- returns null if 
-     * proj4js is not available..
-     */
-    getUnits: function() {
-        return this.proj ? this.proj.units : null;
-    },
-
-    CLASS_NAME: "OpenLayers.Projection" 
-
-});     
-
-/**
- * APIMethod: transform
- * Read data from a string, and return an object whose type depends on the
- * subclass. 
- * 
- * Parameters:
- * point - {object} input horizontal coodinate
- * sourceProj - {OpenLayers.Projection} source map coordinate system
- * destProj - {OpenLayers.Projection} destination map coordinate system
- *
- * Returns:
- * point - {object} trasnformed coordinate
- */
-OpenLayers.Projection.transform = function(point, source, dest) {
-    if (source.proj && dest.proj) {
-        point = Proj4js.transform(source.proj, dest.proj, point);
-    }
-    return point;
-};
-/* ======================================================================
-    OpenLayers/Tile.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/*
- * @requires OpenLayers/Util.js
- *
- * Class: OpenLayers.Tile 
- * This is a class designed to designate a single tile, however
- *     it is explicitly designed to do relatively little. Tiles store 
- *     information about themselves -- such as the URL that they are related
- *     to, and their size - but do not add themselves to the layer div 
- *     automatically, for example. Create a new tile with the 
- *     <OpenLayers.Tile> constructor, or a subclass. 
- * 
- * TBD 3.0 - remove reference to url in above paragraph
- * 
- */
-OpenLayers.Tile = OpenLayers.Class({
-    
-    /** 
-     * Constant: EVENT_TYPES
-     * {Array(String)} Supported application event types
-     */
-    EVENT_TYPES: [ "loadstart", "loadend", "reload"],
-    
-    /**
-     * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all 
-     *                       events on the tile.
-     */
-    events: null,
-
-    /**
-     * Property: id 
-     * {String} null
-     */
-    id: null,
-    
-    /** 
-     * Property: layer 
-     * {<OpenLayers.Layer>} layer the tile is attached to 
-     */
-    layer: null,
-    
-    /**
-     * Property: url
-     * {String} url of the request.
-     *
-     * TBD 3.0 
-     * Deprecated. The base tile class does not need an url. This should be 
-     * handled in subclasses. Does not belong here.
-     */
-    url: null,
-
-    /** 
-     * APIProperty: bounds 
-     * {<OpenLayers.Bounds>} null
-     */
-    bounds: null,
-    
-    /** 
-     * Property: size 
-     * {<OpenLayers.Size>} null
-     */
-    size: null,
-    
-    /** 
-     * Property: position 
-     * {<OpenLayers.Pixel>} Top Left pixel of the tile
-     */    
-    position: null,
-
-    /**
-     * Property: isLoading
-     * {Boolean} Is the tile loading?
-     */
-    isLoading: false,
-    
-    /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
-     *             there is no need for the base tile class to have a url.
-     * 
-     * Constructor: OpenLayers.Tile
-     * Constructor for a new <OpenLayers.Tile> instance.
-     * 
-     * Parameters:
-     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
-     * position - {<OpenLayers.Pixel>}
-     * bounds - {<OpenLayers.Bounds>}
-     * url - {<String>}
-     * size - {<OpenLayers.Size>}
-     */   
-    initialize: function(layer, position, bounds, url, size) {
-        this.layer = layer;
-        this.position = position.clone();
-        this.bounds = bounds.clone();
-        this.url = url;
-        this.size = size.clone();
-
-        //give the tile a unique id based on its BBOX.
-        this.id = OpenLayers.Util.createUniqueID("Tile_");
-        
-        this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
-    },
-    
-    /** 
-     * APIMethod: destroy
-     * Nullify references to prevent circular references and memory leaks.
-     */
-    destroy:function() {
-        this.layer  = null;
-        this.bounds = null;
-        this.size = null;
-        this.position = null;
-        
-        this.events.destroy();
-        this.events = null;
-    },
-
-    /**
-     * Method: draw
-     * Clear whatever is currently in the tile, then return whether or not 
-     *     it should actually be re-drawn.
-     * 
-     * Returns:
-     * {Boolean} Whether or not the tile should actually be drawn. Note that 
-     *     this is not really the best way of doing things, but such is 
-     *     the way the code has been developed. Subclasses call this and
-     *     depend on the return to know if they should draw or not.
-     */
-    draw: function() {
-        
-        //clear tile's contents and mark as not drawn
-        this.clear();
-        
-        var maxExtent = this.layer.maxExtent;
-        var withinMaxExtent = true;
-        if (this.layer.restrictedExtent) {
-          withinMaxExtent = (maxExtent &&
-                               this.bounds.intersectsBounds(maxExtent, false));
-        }
- 
-        // The only case where we *wouldn't* want to draw the tile is if the 
-        // tile is outside its layer's maxExtent.
-        return (withinMaxExtent || this.layer.displayOutsideMaxExtent);
-    },
-    
-    /** 
-     * Method: moveTo
-     * Reposition the tile.
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * position - {<OpenLayers.Pixel>}
-     * redraw - {Boolean} Call draw method on tile after moving.
-     *     Default is true
-     */
-    moveTo: function (bounds, position, redraw) {
-        if (redraw == null) {
-            redraw = true;
-        }
-
-        this.bounds = bounds.clone();
-        this.position = position.clone();
-        if (redraw) {
-            this.draw();
-        }
-    },
-
-    /** 
-     * Method: clear
-     * Clear the tile of any bounds/position-related data so that it can 
-     *     be reused in a new location. To be implemented by subclasses.
-     */
-    clear: function() {
-        // to be implemented by subclasses
-    },
-    
-    /**   
-     * Method: getBoundsFromBaseLayer
-     * Take the pixel locations of the corner of the tile, and pass them to 
-     *     the base layer and ask for the location of those pixels, so that 
-     *     displaying tiles over Google works fine.
-     *
-     * Parameters:
-     * position - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * bounds - {<OpenLayers.Bounds>} 
-     */
-    getBoundsFromBaseLayer: function(position) {
-        OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded", 
-                                                            this.layer.name)); 
-        var topLeft = this.layer.map.getLonLatFromLayerPx(position); 
-        var bottomRightPx = position.clone();
-        bottomRightPx.x += this.size.w;
-        bottomRightPx.y += this.size.h;
-        var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx); 
-        // Handle the case where the base layer wraps around the date line.
-        // Google does this, and it breaks WMS servers to request bounds in 
-        // that fashion.  
-        if (topLeft.lon > bottomRight.lon) {
-            if (topLeft.lon < 0) {
-                topLeft.lon = -180 - (topLeft.lon+180);
-            } else {
-                bottomRight.lon = 180+bottomRight.lon+180;
-            }        
-        }
-        bounds = new OpenLayers.Bounds(topLeft.lon, 
-                                       bottomRight.lat, 
-                                       bottomRight.lon, 
-                                       topLeft.lat);  
-        return bounds;
-    },        
-
-    CLASS_NAME: "OpenLayers.Tile"
-});
-/* ======================================================================
-    OpenLayers/Control/OverviewMap.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/** 
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Events.js
- *
- * Class: OpenLayers.Control.OverviewMap
- * Create an overview map to display the extent of your main map and provide
- * additional navigation control.  Create a new overview map with the
- * <OpenLayers.Control.OverviewMap> constructor.
- *
- * Inerits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
-
-    /**
-     * Property: id
-     * {String} For div.id
-     */
-    id:  "OverviewMap",
-
-    /**
-     * Property: element
-     * {DOMElement} The DOM element that contains the overview map
-     */
-    element: null,
-    
-    /**
-     * APIProperty: ovmap
-     * {<OpenLayers.Map>} A reference to the overvew map itself.
-     */
-    ovmap: null,
-        
-    /**
-     * APIProperty: size
-     * {<OpenLayers.Size>} The overvew map size in pixels.  Note that this is
-     * the size of the map itself - the element that contains the map (default
-     * class name olControlOverviewMapElement) may have padding or other style
-     * attributes added via CSS.
-     */
-    size: new OpenLayers.Size(180, 90),
-
-    /**
-     * APIProperty: layers
-     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
-     * If none are sent at construction, the base layer for the main map is used.
-     */
-    layers: null,
-
-    /**
-     * APIProperty: minRatio
-     * {Float} The ratio of the overview map resolution to the main map
-     * resolution at which to zoom farther out on the overview map.
-     */
-    minRatio: 8,
-
-    /**
-     * APIProperty: maxRatio
-     * {Float} The ratio of the overview map resolution to the main map
-     * resolution at which to zoom farther in on the overview map.
-     */
-    maxRatio: 32,
-
-    /**
-     * APIProperty: mapOptions
-     * {Object} An object containing any non-default properties to be sent to
-     * the overview map's map constructor.  These should include any non-default
-     * options that the main map was constructed with.
-     */
-    mapOptions: null,
-
-    /**
-     * Constructor: OpenLayers.Control.OverviewMap
-     * Create a new overview map
-     *
-     * Parameters:
-     * object - {Object} Properties of this object will be set on the overview
-     * map object.  Note, to set options on the map object contained in this
-     * control, set <mapOptions> as one of the options properties.
-     */
-    initialize: function(options) {
-        this.layers = [];
-        OpenLayers.Control.prototype.initialize.apply(this, [options]);
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Deconstruct the control
-     */
-    destroy: function() {
-        if (!this.mapDiv) { // we've already been destroyed
-            return;
-        }
-        this.mapDiv.removeChild(this.extentRectangle);
-        this.extentRectangle = null;
-        this.rectEvents.destroy();
-        this.rectEvents = null;
-
-        this.ovmap.destroy();
-        this.ovmap = null;
-        
-        this.element.removeChild(this.mapDiv);
-        this.mapDiv = null;
-        this.mapDivEvents.destroy(); 
-        this.mapDivEvents = null;
-
-        this.div.removeChild(this.element);
-        this.element = null;
-        this.elementEvents.destroy();
-        this.elementEvents = null;
-
-        if (this.maximizeDiv) {
-            OpenLayers.Event.stopObservingElement(this.maximizeDiv);
-            this.div.removeChild(this.maximizeDiv);
-            this.maximizeDiv = null;
-        }
-        
-        if (this.minimizeDiv) {
-            OpenLayers.Event.stopObservingElement(this.minimizeDiv);
-            this.div.removeChild(this.minimizeDiv);
-            this.minimizeDiv = null;
-        }
-        
-        this.map.events.unregister('moveend', this, this.update);
-        this.map.events.unregister("changebaselayer", this, 
-                                    this.baseLayerDraw);
-
-        OpenLayers.Control.prototype.destroy.apply(this, arguments);    
-    },
-
-    /**
-     * Method: draw
-     * Render the control in the browser.
-     */    
-    draw: function() {
-        OpenLayers.Control.prototype.draw.apply(this, arguments);
-        if(!(this.layers.length > 0)) {
-            if (this.map.baseLayer) {
-                var layer = this.map.baseLayer.clone();
-                this.layers = [layer];
-            } else {
-                this.map.events.register("changebaselayer", this, this.baseLayerDraw);
-                return this.div;
-            }
-        }
-
-        // create overview map DOM elements
-        this.element = document.createElement('div');
-        this.element.className = this.displayClass + 'Element';
-        this.element.style.display = 'none';
-
-        this.mapDiv = document.createElement('div');
-        this.mapDiv.style.width = this.size.w + 'px';
-        this.mapDiv.style.height = this.size.h + 'px';
-        this.mapDiv.style.position = 'relative';
-        this.mapDiv.style.overflow = 'hidden';
-        this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
-        
-        this.extentRectangle = document.createElement('div');
-        this.extentRectangle.style.position = 'absolute';
-        this.extentRectangle.style.zIndex = 1000;  //HACK
-        this.extentRectangle.style.overflow = 'hidden';
-        this.extentRectangle.style.backgroundImage = 'url(' +
-                                        OpenLayers.Util.getImagesLocation() +
-                                        'blank.gif)';
-        this.extentRectangle.className = this.displayClass+'ExtentRectangle';
-        this.mapDiv.appendChild(this.extentRectangle);
-                
-        this.element.appendChild(this.mapDiv);  
-
-        this.div.appendChild(this.element);
-
-        this.map.events.register('moveend', this, this.update);
-        
-        // Set up events.  The image div recenters the map on click.
-        // The extent rectangle can be dragged to recenter the map.
-        // If the mousedown happened elsewhere, then mousemove and mouseup
-        // should slip through.
-        this.elementEvents = new OpenLayers.Events(this, this.element);
-        this.elementEvents.register('mousedown', this, function(e) {
-            OpenLayers.Event.stop(e);
-        });
-        this.elementEvents.register('click', this, function(e) {
-            OpenLayers.Event.stop(e);
-        });
-        this.elementEvents.register('dblclick', this, function(e) {
-            OpenLayers.Event.stop(e);
-        });
-        this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
-                                                null, true);
-        this.rectEvents.register('mouseout', this, this.rectMouseOut);
-        this.rectEvents.register('mousedown', this, this.rectMouseDown);
-        this.rectEvents.register('mousemove', this, this.rectMouseMove);
-        this.rectEvents.register('mouseup', this, this.rectMouseUp);
-        this.rectEvents.register('click', this, function(e) {
-            OpenLayers.Event.stop(e);
-        });
-        this.rectEvents.register('dblclick', this, this.rectDblClick );
-        this.mapDivEvents = new OpenLayers.Events(this, this.mapDiv);
-        this.mapDivEvents.register('click', this, this.mapDivClick);
-
-        // Optionally add min/max buttons if the control will go in the
-        // map viewport.
-        if(!this.outsideViewport) {
-            this.div.className = this.displayClass + 'Container';
-            var imgLocation = OpenLayers.Util.getImagesLocation();
-            // maximize button div
-            var img = imgLocation + 'layer-switcher-maximize.png';
-            this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
-                                        this.displayClass + 'MaximizeButton', 
-                                        null, 
-                                        new OpenLayers.Size(18,18), 
-                                        img, 
-                                        'absolute');
-            this.maximizeDiv.style.display = 'none';
-            this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
-            OpenLayers.Event.observe(this.maximizeDiv, 'click', 
-                OpenLayers.Function.bindAsEventListener(this.maximizeControl,
-                                                        this)
-            );
-            this.div.appendChild(this.maximizeDiv);
-    
-            // minimize button div
-            var img = imgLocation + 'layer-switcher-minimize.png';
-            this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
-                                        'OpenLayers_Control_minimizeDiv', 
-                                        null, 
-                                        new OpenLayers.Size(18,18), 
-                                        img, 
-                                        'absolute');
-            this.minimizeDiv.style.display = 'none';
-            this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
-            OpenLayers.Event.observe(this.minimizeDiv, 'click', 
-                OpenLayers.Function.bindAsEventListener(this.minimizeControl,
-                                                        this)
-            );
-            this.div.appendChild(this.minimizeDiv);
-            
-            var eventsToStop = ['dblclick','mousedown'];
-            
-            for (var i = 0; i < eventsToStop.length; i++) {
-
-                OpenLayers.Event.observe(this.maximizeDiv, 
-                                         eventsToStop[i], 
-                                         OpenLayers.Event.stop);
-
-                OpenLayers.Event.observe(this.minimizeDiv,
-                                         eventsToStop[i], 
-                                         OpenLayers.Event.stop);
-            }
-            
-            this.minimizeControl();
-        } else {
-            // show the overview map
-            this.element.style.display = '';
-        }
-        if(this.map.getExtent()) {
-            this.update();
-        }
-        return this.div;
-    },
-    
-    /**
-     * Method: baseLayerDraw
-     * Draw the base layer - called if unable to complete in the initial draw
-     */
-    baseLayerDraw: function() {
-        this.draw();
-        this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
-    },
-
-    /**
-     * Method: rectMouseOut
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    rectMouseOut: function (evt) {
-        if(this.rectDragStart != null) {
-            if(this.performedRectDrag) {
-                this.rectMouseMove(evt);
-                var rectPxBounds = this.getRectPxBounds(); 
-                // if we're off of the overview map, update the main map
-                // otherwise, keep moving the rect
-                if((rectPxBounds.top <= 0) || (rectPxBounds.left <= 0) || 
-                   (rectPxBounds.bottom >= this.size.h - this.hComp) || 
-                   (rectPxBounds.right >= this.size.w - this.wComp)) {
-                    this.updateMapToRect();
-                } else {
-                    return; 
-                }
-            }
-            document.onselectstart = null;
-            this.rectDragStart = null;
-        }
-    },
-
-    /**
-     * Method: rectMouseDown
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    rectMouseDown: function (evt) {
-        if(!OpenLayers.Event.isLeftClick(evt)) return;
-        this.rectDragStart = evt.xy.clone();
-        this.performedRectDrag = false;
-        OpenLayers.Event.stop(evt);
-    },
-
-    /**
-     * Method: rectMouseMove
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    rectMouseMove: function(evt) {
-        if(this.rectDragStart != null) {
-            var deltaX = this.rectDragStart.x - evt.xy.x;
-            var deltaY = this.rectDragStart.y - evt.xy.y;
-            var rectPxBounds = this.getRectPxBounds();
-            var rectTop = rectPxBounds.top;
-            var rectLeft = rectPxBounds.left;
-            var rectHeight = Math.abs(rectPxBounds.getHeight());
-            var rectWidth = rectPxBounds.getWidth();
-            // don't allow dragging off of parent element
-            var newTop = Math.max(0, (rectTop - deltaY));
-            newTop = Math.min(newTop,
-                              this.ovmap.size.h - this.hComp - rectHeight);
-            var newLeft = Math.max(0, (rectLeft - deltaX));
-            newLeft = Math.min(newLeft,
-                               this.ovmap.size.w - this.wComp - rectWidth);
-            this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
-                                                       newTop + rectHeight,
-                                                       newLeft + rectWidth,
-                                                       newTop));
-            this.rectDragStart = evt.xy.clone();
-            this.performedRectDrag = true;
-            OpenLayers.Event.stop(evt);
-        }
-    },
-
-    /**
-     * Method: rectMouseUp
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    rectMouseUp: function(evt) {
-        if(!OpenLayers.Event.isLeftClick(evt)) return;
-        if(this.performedRectDrag) {
-            this.updateMapToRect();
-            OpenLayers.Event.stop(evt);
-        }        
-        document.onselectstart = null;
-        this.rectDragStart = null;
-    },
-    
-    /**
-     * Method: rectDblClick
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    rectDblClick: function(evt) {
-        this.performedRectDrag = false;
-        OpenLayers.Event.stop(evt);
-        this.updateOverview();
-    },
-
-    /**
-     * Method: mapDivClick
-     * Handle browser events
-     *
-     * Parameters:
-     * evt - {<OpenLayers.Event>} evt
-     */
-    mapDivClick: function(evt) {
-        var pxBounds = this.getRectPxBounds();
-        var pxCenter = pxBounds.getCenterPixel();
-        var deltaX = evt.xy.x - pxCenter.x;
-        var deltaY = evt.xy.y - pxCenter.y;
-        var top = pxBounds.top;
-        var left = pxBounds.left;
-        var height = Math.abs(pxBounds.getHeight());
-        var width = pxBounds.getWidth();
-        var newTop = Math.max(0, (top + deltaY));
-        newTop = Math.min(newTop, this.ovmap.size.h - height);
-        var newLeft = Math.max(0, (left + deltaX));
-        newLeft = Math.min(newLeft, this.ovmap.size.w - width);
-        this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
-                                                   newTop + height,
-                                                   newLeft + width,
-                                                   newTop));
-        this.updateMapToRect();
-        OpenLayers.Event.stop(evt);
-    },
-
-    /**
-     * Method: maximizeControl
-     * Unhide the control.  Called when the control is in the map viewport.
-     *
-     * Parameters:
-     * e - {<OpenLayers.Event>}
-     */
-    maximizeControl: function(e) {
-        this.element.style.display = '';
-        this.showToggle(false);
-        if (e != null) {
-            OpenLayers.Event.stop(e);                                            
-        }
-    },
-
-    /**
-     * Method: minimizeControl
-     * Hide all the contents of the control, shrink the size, 
-     * add the maximize icon
-     * 
-     * Parameters:
-     * e - {<OpenLayers.Event>}
-     */
-    minimizeControl: function(e) {
-        this.element.style.display = 'none';
-        this.showToggle(true);
-        if (e != null) {
-            OpenLayers.Event.stop(e);                                            
-        }
-    },
-
-    /**
-     * Method: showToggle
-     * Hide/Show the toggle depending on whether the control is minimized
-     *
-     * Parameters:
-     * minimize - {Boolean} 
-     */
-    showToggle: function(minimize) {
-        this.maximizeDiv.style.display = minimize ? '' : 'none';
-        this.minimizeDiv.style.display = minimize ? 'none' : '';
-    },
-
-    /**
-     * Method: update
-     * Update the overview map after layers move.
-     */
-    update: function() {
-        if(this.ovmap == null) {
-            this.createMap();
-        }
-        
-        if(!this.isSuitableOverview()) {
-            this.updateOverview();
-        }
-        
-        // update extent rectangle
-        this.updateRectToMap();
-    },
-    
-    /**
-     * Method: isSuitableOverview
-     * Determines if the overview map is suitable given the extent and
-     * resolution of the main map.
-     */
-    isSuitableOverview: function() {
-        var mapExtent = this.map.getExtent();
-        var maxExtent = this.map.maxExtent;
-        var testExtent = new OpenLayers.Bounds(
-                                Math.max(mapExtent.left, maxExtent.left),
-                                Math.max(mapExtent.bottom, maxExtent.bottom),
-                                Math.min(mapExtent.right, maxExtent.right),
-                                Math.min(mapExtent.top, maxExtent.top));        
-        var resRatio = this.ovmap.getResolution() / this.map.getResolution();
-        return ((resRatio > this.minRatio) &&
-                (resRatio <= this.maxRatio) &&
-                (this.ovmap.getExtent().containsBounds(testExtent)));
-    },
-    
-    /**
-     * Method updateOverview
-     * Called by <update> if <isSuitableOverview> returns true
-     */
-    updateOverview: function() {
-        var mapRes = this.map.getResolution();
-        var targetRes = this.ovmap.getResolution();
-        var resRatio = targetRes / mapRes;
-        if(resRatio > this.maxRatio) {
-            // zoom in overview map
-            targetRes = this.minRatio * mapRes;            
-        } else if(resRatio <= this.minRatio) {
-            // zoom out overview map
-            targetRes = this.maxRatio * mapRes;
-        }
-        this.ovmap.setCenter(this.map.center,
-                            this.ovmap.getZoomForResolution(targetRes));
-        this.updateRectToMap();
-    },
-    
-    /**
-     * Method: createMap
-     * Construct the map that this control contains
-     */
-    createMap: function() {
-        // create the overview map
-        var options = OpenLayers.Util.extend(
-                        {controls: [], maxResolution: 'auto'}, this.mapOptions);
-        this.ovmap = new OpenLayers.Map(this.mapDiv, options);
-        this.ovmap.addLayers(this.layers);
-        this.ovmap.zoomToMaxExtent();
-        // check extent rectangle border width
-        this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-left-width')) +
-                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-right-width'));
-        this.wComp = (this.wComp) ? this.wComp : 2;
-        this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-top-width')) +
-                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-                                               'border-bottom-width'));
-        this.hComp = (this.hComp) ? this.hComp : 2;
-    },
-        
-    /**
-     * Method: updateRectToMap
-     * Updates the extent rectangle position and size to match the map extent
-     */
-    updateRectToMap: function() {
-        // The base layer for overview map needs to be in the same projection
-        // as the base layer for the main map.  This should be made more robust.
-        //if(this.map.units != 'degrees') {
-            if(this.ovmap.getProjection() && (this.map.getProjection() != this.ovmap.getProjection())) {
-                alert(OpenLayers.String.translate("sameProjection"));
-            }
-        //}
-        var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
-        if (pxBounds) {
-          this.setRectPxBounds(pxBounds);
-        }
-    },
-    
-    /**
-     * Method: updateMapToRect
-     * Updates the map extent to match the extent rectangle position and size
-     */
-    updateMapToRect: function() {
-        var pxBounds = this.getRectPxBounds();
-        var lonLatBounds = this.getMapBoundsFromRectBounds(pxBounds);
-        this.map.setCenter(lonLatBounds.getCenterLonLat(), this.map.zoom);
-    },
-    
-    /**
-     * Method: getRectPxBounds
-     * Get extent rectangle pixel bounds
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} A bounds which is the extent rectangle's pixel
-     * bounds (relative to the parent element)
-     */
-    getRectPxBounds: function() {
-        var top = parseInt(this.extentRectangle.style.top);
-        var left = parseInt(this.extentRectangle.style.left);
-        var height = parseInt(this.extentRectangle.style.height);
-        var width = parseInt(this.extentRectangle.style.width);
-        return new OpenLayers.Bounds(left, top + height, left + width, top);
-    },
-
-    /**
-     * Method: setRectPxBounds
-     * Set extent rectangle pixel bounds.
-     *
-     * Parameters:
-     * pxBounds - {<OpenLayers.Bounds>}
-     */
-    setRectPxBounds: function(pxBounds) {
-        var top = Math.max(pxBounds.top, 0);
-        var left = Math.max(pxBounds.left, 0);
-        var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
-                              this.ovmap.size.h - this.hComp);
-        var right = Math.min(pxBounds.left + pxBounds.getWidth(),
-                             this.ovmap.size.w - this.wComp);
-        this.extentRectangle.style.top = parseInt(top) + 'px';
-        this.extentRectangle.style.left = parseInt(left) + 'px';
-        this.extentRectangle.style.height = parseInt(Math.max(bottom - top, 0))+ 'px';
-        this.extentRectangle.style.width = parseInt(Math.max(right - left, 0)) + 'px';
-    },
-
-    /**
-     * Method: getRectBoundsFromMapBounds
-     * Get the rect bounds from the map bounds.
-     *
-     * Parameters:
-     * lonLatBounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
-     * translated into pixel bounds for the overview map
-     */
-    getRectBoundsFromMapBounds: function(lonLatBounds) {
-        var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
-                                                     lonLatBounds.bottom);
-        var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
-                                                   lonLatBounds.top);
-        var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
-        var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
-        var bounds = null;
-        if (leftBottomPx && rightTopPx) {
-            bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
-                                           rightTopPx.x, rightTopPx.y);
-        }
-        return bounds;
-    },
-
-    /**
-     * Method: getMapBoundsFromRectBounds
-     * Get the map bounds from the rect bounds.
-     *
-     * Parameters:
-     * pxBounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
-     * translated into lon/lat bounds for the overview map
-     */
-    getMapBoundsFromRectBounds: function(pxBounds) {
-        var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
-                                                pxBounds.bottom);
-        var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
-                                              pxBounds.top);
-        var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
-        var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
-        return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
-                                     rightTopLonLat.lon, rightTopLonLat.lat);
-    },
-
-    /**
-     * Method: getLonLatFromOverviewPx
-     * Get a map location from a pixel location
-     *
-     * Parameters:
-     * overviewMapPx - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>} Location which is the passed-in overview map
-     * OpenLayers.Pixel, translated into lon/lat by the overview map
-     */
-    getLonLatFromOverviewPx: function(overviewMapPx) {
-        var size = this.ovmap.size;
-        var res  = this.ovmap.getResolution();
-        var center = this.ovmap.getExtent().getCenterLonLat();
-    
-        var delta_x = overviewMapPx.x - (size.w / 2);
-        var delta_y = overviewMapPx.y - (size.h / 2);
-        
-        return new OpenLayers.LonLat(center.lon + delta_x * res ,
-                                     center.lat - delta_y * res); 
-    },
-
-    /**
-     * Method: getOverviewPxFromLonLat
-     * Get a pixel location from a map location
-     *
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
-     * translated into overview map pixels
-     */
-    getOverviewPxFromLonLat: function(lonlat) {
-        var res  = this.ovmap.getResolution();
-        var extent = this.ovmap.getExtent();
-        var px = null;
-        if (extent) {
-            px = new OpenLayers.Pixel(
-                        Math.round(1/res * (lonlat.lon - extent.left)),
-                        Math.round(1/res * (extent.top - lonlat.lat)));
-        } 
-        return px;
-    },
-
-    CLASS_NAME: 'OpenLayers.Control.OverviewMap'
-});
-/* ======================================================================
-    OpenLayers/Handler.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Events.js
- * 
- * Class: OpenLayers.Handler
- * Base class to construct a higher-level handler for event sequences.  All
- *     handlers have activate and deactivate methods.  In addition, they have
- *     methods named like browser events.  When a handler is activated, any
- *     additional methods named like a browser event is registered as a
- *     listener for the corresponding event.  When a handler is deactivated,
- *     those same methods are unregistered as event listeners.
- *
- * Handlers also typically have a callbacks object with keys named like
- *     the abstracted events or event sequences that they are in charge of
- *     handling.  The controls that wrap handlers define the methods that
- *     correspond to these abstract events - so instead of listening for
- *     individual browser events, they only listen for the abstract events
- *     defined by the handler.
- *     
- * Handlers are created by controls, which ultimately have the responsibility
- *     of making changes to the the state of the application.  Handlers
- *     themselves may make temporary changes, but in general are expected to
- *     return the application in the same state that they found it.
- */
-OpenLayers.Handler = OpenLayers.Class({
-
-    /**
-     * Property: id
-     * {String}
-     */
-    id: null,
-        
-    /**
-     * APIProperty: control
-     * {<OpenLayers.Control>}. The control that initialized this handler.  The
-     *     control is assumed to have a valid map property - that map is used
-     *     in the handler's own setMap method.
-     */
-    control: null,
-
-    /**
-     * Property: map
-     * {<OpenLayers.Map>}
-     */
-    map: null,
-
-    /**
-     * APIProperty: keyMask
-     * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
-     *     constants to construct a keyMask.  The keyMask is used by
-     *     <checkModifiers>.  If the keyMask matches the combination of keys
-     *     down on an event, checkModifiers returns true.
-     *
-     * Example:
-     * (code)
-     *     // handler only responds if the Shift key is down
-     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
-     *
-     *     // handler only responds if Ctrl-Shift is down
-     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
-     *                       OpenLayers.Handler.MOD_CTRL;
-     * (end)
-     */
-    keyMask: null,
-
-    /**
-     * Property: active
-     * {Boolean}
-     */
-    active: false,
-    
-    /**
-     * Property: evt
-     * {Event} This property references the last event handled by the handler.
-     *     Note that this property is not part of the stable API.  Use of the
-     *     evt property should be restricted to controls in the library
-     *     or other applications that are willing to update with changes to
-     *     the OpenLayers code.
-     */
-    evt: null,
-
-    /**
-     * Constructor: OpenLayers.Handler
-     * Construct a handler.
-     *
-     * Parameters:
-     * control - {<OpenLayers.Control>} The control that initialized this
-     *     handler.  The control is assumed to have a valid map property; that
-     *     map is used in the handler's own setMap method.
-     * callbacks - {Object} An object whose properties correspond to abstracted
-     *     events or sequences of browser events.  The values for these
-     *     properties are functions defined by the control that get called by
-     *     the handler.
-     * options - {Object} An optional object whose properties will be set on
-     *     the handler.
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Util.extend(this, options);
-        this.control = control;
-        this.callbacks = callbacks;
-        if (control.map) {
-            this.setMap(control.map); 
-        }
-
-        OpenLayers.Util.extend(this, options);
-        
-        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-    },
-    
-    /**
-     * Method: setMap
-     */
-    setMap: function (map) {
-        this.map = map;
-    },
-
-    /**
-     * Method: checkModifiers
-     * Check the keyMask on the handler.  If no <keyMask> is set, this always
-     *     returns true.  If a <keyMask> is set and it matches the combination
-     *     of keys down on an event, this returns true.
-     *
-     * Returns:
-     * {Boolean} The keyMask matches the keys down on an event.
-     */
-    checkModifiers: function (evt) {
-        if(this.keyMask == null) {
-            return true;
-        }
-        /* calculate the keyboard modifier mask for this event */
-        var keyModifiers =
-            (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
-            (evt.ctrlKey  ? OpenLayers.Handler.MOD_CTRL  : 0) |
-            (evt.altKey   ? OpenLayers.Handler.MOD_ALT   : 0);
-    
-        /* if it differs from the handler object's key mask,
-           bail out of the event handler */
-        return (keyModifiers == this.keyMask);
-    },
-
-    /**
-     * APIMethod: activate
-     * Turn on the handler.  Returns false if the handler was already active.
-     * 
-     * Returns: 
-     * {Boolean} The handler was activated.
-     */
-    activate: function() {
-        if(this.active) {
-            return false;
-        }
-        // register for event handlers defined on this class.
-        var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
-        for (var i = 0; i < events.length; i++) {
-            if (this[events[i]]) {
-                this.register(events[i], this[events[i]]); 
-            }
-        } 
-        this.active = true;
-        return true;
-    },
-    
-    /**
-     * APIMethod: deactivate
-     * Turn off the handler.  Returns false if the handler was already inactive.
-     * 
-     * Returns:
-     * {Boolean} The handler was deactivated.
-     */
-    deactivate: function() {
-        if(!this.active) {
-            return false;
-        }
-        // unregister event handlers defined on this class.
-        var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
-        for (var i = 0; i < events.length; i++) {
-            if (this[events[i]]) {
-                this.unregister(events[i], this[events[i]]); 
-            }
-        } 
-        this.active = false;
-        return true;
-    },
-
-    /**
-    * Method: callback
-    * Trigger the control's named callback with the given arguments
-    *
-    * Parameters:
-    * name - {String} The key for the callback that is one of the properties
-    *     of the handler's callbacks object.
-    * args - {Array(*)} An array of arguments (any type) with which to call 
-    *     the callback (defined by the control).
-    */
-    callback: function (name, args) {
-        if (this.callbacks[name]) {
-            this.callbacks[name].apply(this.control, args);
-        }
-    },
-
-    /**
-    * Method: register
-    * register an event on the map
-    */
-    register: function (name, method) {
-        // TODO: deal with registerPriority in 3.0
-        this.map.events.registerPriority(name, this, method);
-        this.map.events.registerPriority(name, this, this.setEvent);
-    },
-
-    /**
-    * Method: unregister
-    * unregister an event from the map
-    */
-    unregister: function (name, method) {
-        this.map.events.unregister(name, this, method);   
-        this.map.events.unregister(name, this, this.setEvent);
-    },
-    
-    /**
-     * Method: setEvent
-     * With each registered browser event, the handler sets its own evt
-     *     property.  This property can be accessed by controls if needed
-     *     to get more information about the event that the handler is
-     *     processing.
-     *
-     * This allows modifier keys on the event to be checked (alt, shift,
-     *     and ctrl cannot be checked with the keyboard handler).  For a
-     *     control to determine which modifier keys are associated with the
-     *     event that a handler is currently processing, it should access
-     *     (code)handler.evt.altKey || handler.evt.shiftKey ||
-     *     handler.evt.ctrlKey(end).
-     *
-     * Parameters:
-     * evt - {Event} The browser event.
-     */
-    setEvent: function(evt) {
-        this.evt = evt;
-        return true;
-    },
-
-    /**
-     * Method: destroy
-     * Deconstruct the handler.
-     */
-    destroy: function () {
-        // unregister event listeners
-        this.deactivate();
-        // eliminate circular references
-        this.control = this.map = null;        
-    },
-
-    CLASS_NAME: "OpenLayers.Handler"
-});
-
-/**
- * Constant: OpenLayers.Handler.MOD_NONE
- * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
- */
-OpenLayers.Handler.MOD_NONE  = 0;
-
-/**
- * Constant: OpenLayers.Handler.MOD_SHIFT
- * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
- */
-OpenLayers.Handler.MOD_SHIFT = 1;
-
-/**
- * Constant: OpenLayers.Handler.MOD_CTRL
- * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
- */
-OpenLayers.Handler.MOD_CTRL  = 2;
-
-/**
- * Constant: OpenLayers.Handler.MOD_ALT
- * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
- */
-OpenLayers.Handler.MOD_ALT   = 4;
-
-
-/* ======================================================================
-    OpenLayers/Map.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Events.js
- * 
- * Class: OpenLayers.Map
- * Instances of OpenLayers.Map are interactive maps embedded in a web page.
- * Create a new map with the <OpenLayers.Map> constructor.
- * 
- * On their own maps do not provide much functionality.  To extend a map
- * it's necessary to add controls (<OpenLayers.Control>) and 
- * layers (<OpenLayers.Layer>) to the map. 
- */
-OpenLayers.Map = OpenLayers.Class({
-    
-    /**
-     * Constant: Z_INDEX_BASE
-     * {Object} Base z-indexes for different classes of thing 
-     */
-    Z_INDEX_BASE: { BaseLayer: 100, Overlay: 325, Popup: 750, Control: 1000 },
-
-    /**
-     * Constant: EVENT_TYPES
-     * {Array(String)} supported application event types
-     */
-    EVENT_TYPES: [ 
-        "addlayer", "removelayer", "changelayer", "movestart", "move", 
-        "moveend", "zoomend", "popupopen", "popupclose",
-        "addmarker", "removemarker", "clearmarkers", "mouseover",
-        "mouseout", "mousemove", "dragstart", "drag", "dragend",
-        "changebaselayer"],
-
-    /**
-     * Property: id
-     * {String} Unique identifier for the map
-     */
-    id: null,
-    
-    /**
-     * APIProperty: events
-     * {<OpenLayers.Events>} An events object that handles all 
-     *                       events on the map
-     */
-    events: null,
-
-    /**
-     * APIProperty: div
-     * {DOMElement} The element that contains the map
-     */
-    div: null,
-
-    /**
-     * Property: size
-     * {<OpenLayers.Size>} Size of the main div (this.div)
-     */
-    size: null,
-    
-    /**
-     * Property: viewPortDiv
-     * {HTMLDivElement} The element that represents the map viewport
-     */
-    viewPortDiv: null,
-
-    /**
-     * Property: layerContainerOrigin
-     * {<OpenLayers.LonLat>} The lonlat at which the later container was
-     *                       re-initialized (on-zoom)
-     */
-    layerContainerOrigin: null,
-
-    /**
-     * Property: layerContainerDiv
-     * {HTMLDivElement} The element that contains the layers.
-     */
-    layerContainerDiv: null,
-
-    /**
-     * Property: layers
-     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
-     */
-    layers: null,
-
-    /**
-     * Property: controls
-     * {Array(<OpenLayers.Control>)} List of controls associated with the map
-     */
-    controls: null,
-
-    /**
-     * Property: popups
-     * {Array(<OpenLayers.Popup>)} List of popups associated with the map
-     */
-    popups: null,
-
-    /**
-     * APIProperty: baseLayer
-     * {<OpenLayers.Layer>} The currently selected base layer.  This determines
-     * min/max zoom level, projection, etc.
-     */
-    baseLayer: null,
-    
-    /**
-     * Property: center
-     * {<OpenLayers.LonLat>} The current center of the map
-     */
-    center: null,
-
-    /**
-     * Property: zoom
-     * {Integer} The current zoom level of the map
-     */
-    zoom: 0,    
-
-    /**
-     * Property: viewRequestID
-     * {String} Used to store a unique identifier that changes when the map 
-     *          view changes. viewRequestID should be used when adding data 
-     *          asynchronously to the map: viewRequestID is incremented when 
-     *          you initiate your request (right now during changing of 
-     *          baselayers and changing of zooms). It is stored here in the 
-     *          map and also in the data that will be coming back 
-     *          asynchronously. Before displaying this data on request 
-     *          completion, we check that the viewRequestID of the data is 
-     *          still the same as that of the map. Fix for #480
-     */
-    viewRequestID: 0,
-
-  // Options
-
-    /**
-     * APIProperty: tileSize
-     * {<OpenLayers.Size>} Set in the map options to override the default tile
-     *                     size for this map.
-     */
-    tileSize: null,
-
-    /**
-     * APIProperty: projection
-     * {String} Set in the map options to override the default projection 
-     *          string this map - also set maxExtent, maxResolution, and 
-     *          units if appropriate.
-     */
-    projection: "EPSG:4326",    
-        
-    /**
-     * APIProperty: units
-     * {String} The map units.  Defaults to 'degrees'.  Possible values are
-     *          'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
-     */
-    units: 'degrees',
-
-    /**
-     * APIProperty: resolutions
-     * {Array(Float)} A list of map resolutions (map units per pixel) in 
-     *     descending order.  If this is not set in the layer constructor, it 
-     *     will be set based on other resolution related properties 
-     *     (maxExtent, maxResolution, maxScale, etc.).
-     */
-    resolutions: null,
-
-    /**
-     * APIProperty: maxResolution
-     * {Float} Default max is 360 deg / 256 px, which corresponds to
-     *          zoom level 0 on gmaps.  Specify a different value in the map 
-     *          options if you are not using a geographic projection and 
-     *          displaying the whole world.
-     */
-    maxResolution: 1.40625,
-
-    /**
-     * APIProperty: minResolution
-     * {Float}
-     */
-    minResolution: null,
-
-    /**
-     * APIProperty: maxScale
-     * {Float}
-     */
-    maxScale: null,
-
-    /**
-     * APIProperty: minScale
-     * {Float}
-     */
-    minScale: null,
-
-    /**
-     * APIProperty: maxExtent
-     * {<OpenLayers.Bounds>} The maximum extent for the map.  Defaults to the
-     *                       whole world in decimal degrees 
-     *                       (-180, -90, 180, 90).  Specify a different
-     *                        extent in the map options if you are not using a 
-     *                        geographic projection and displaying the whole 
-     *                        world.
-     */
-    maxExtent: null,
-    
-    /**
-     * APIProperty: minExtent
-     * {<OpenLayers.Bounds>}
-     */
-    minExtent: null,
-    
-    /**
-     * APIProperty: restrictedExtent
-     * {<OpenLayers.Bounds>} Limit map navigation to this extent where possible.
-     *     If a non-null restrictedExtent is set, panning will be restricted
-     *     to the given bounds.  In addition, zooming to a resolution that
-     *     displays more than the restricted extent will center the map
-     *     on the restricted extent.  If you wish to limit the zoom level
-     *     or resolution, use maxResolution.
-     */
-    restrictedExtent: 'auto',
-
-    /**
-     * APIProperty: numZoomLevels
-     * {Integer} Number of zoom levels for the map.  Defaults to 16.  Set a
-     *           different value in the map options if needed.
-     */
-    numZoomLevels: 16,
-
-    /**
-     * APIProperty: theme
-     * {String} Relative path to a CSS file from which to load theme styles.
-     *          Specify null in the map options (e.g. {theme: null}) if you 
-     *          want to get cascading style declarations - by putting links to 
-     *          stylesheets or style declarations directly in your page.
-     */
-    theme: null,
-
-    /**
-     * APIProperty: fallThrough
-     * {Boolean} Should OpenLayers allow events on the map to fall through to
-     *           other elements on the page, or should it swallow them? (#457)
-     *           Default is to swallow them.
-     */
-    fallThrough: false,
-
-    /**
-     * Constructor: OpenLayers.Map
-     * Constructor for a new OpenLayers.Map instance.
-     *
-     * Parameters:
-     * div - {String} Id of an element in your page that will contain the map.
-     * options - {Object} Optional object with properties to tag onto the map.
-     *
-     * Examples:
-     * (code)
-     * // create a map with default options in an element with the id "map1"
-     * var map = new OpenLayers.Map("map1");
-     *
-     * // create a map with non-default options in an element with id "map2"
-     * var options = {
-     *     maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
-     *     maxResolution: 156543,
-     *     units: 'meters',
-     *     projection: "EPSG:41001"
-     * };
-     * var map = new OpenLayers.Map("map2", options);
-     * (end)
-     */    
-    initialize: function (div, options) {
-        
-        //set the default options
-        this.setOptions(options);
-
-        this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
-
-        this.div = OpenLayers.Util.getElement(div);
-
-        // the viewPortDiv is the outermost div we modify
-        var id = this.div.id + "_OpenLayers_ViewPort";
-        this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
-                                                     "relative", null,
-                                                     "hidden");
-        this.viewPortDiv.style.width = "100%";
-        this.viewPortDiv.style.height = "100%";
-        this.viewPortDiv.className = "olMapViewport";
-        this.div.appendChild(this.viewPortDiv);
-
-        // the layerContainerDiv is the one that holds all the layers
-        id = this.div.id + "_OpenLayers_Container";
-        this.layerContainerDiv = OpenLayers.Util.createDiv(id);
-        this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
-        
-        this.viewPortDiv.appendChild(this.layerContainerDiv);
-
-        this.events = new OpenLayers.Events(this, 
-                                            this.div, 
-                                            this.EVENT_TYPES, 
-                                            this.fallThrough);
-        this.updateSize();
- 
-        // update the map size and location before the map moves
-        this.events.register("movestart", this, this.updateSize);
-
-        // Because Mozilla does not support the "resize" event for elements 
-        // other than "window", we need to put a hack here. 
-        if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
-            // If IE, register the resize on the div
-            this.events.register("resize", this, this.updateSize);
-        } else {
-            // Else updateSize on catching the window's resize
-            //  Note that this is ok, as updateSize() does nothing if the 
-            //  map's size has not actually changed.
-            OpenLayers.Event.observe(window, 'resize',
-                            OpenLayers.Function.bind(this.updateSize, this));
-        }
-        
-        // only append link stylesheet if the theme property is set
-        if(this.theme) {
-            // check existing links for equivalent url
-            var addNode = true;
-            var nodes = document.getElementsByTagName('link');
-            for(var i=0; i<nodes.length; ++i) {
-                if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
-                                                   this.theme)) {
-                    addNode = false;
-                    break;
-                }
-            }
-            // only add a new node if one with an equivalent url hasn't already
-            // been added
-            if(addNode) {
-                var cssNode = document.createElement('link');
-                cssNode.setAttribute('rel', 'stylesheet');
-                cssNode.setAttribute('type', 'text/css');
-                cssNode.setAttribute('href', this.theme);
-                document.getElementsByTagName('head')[0].appendChild(cssNode);
-            }
-        }
-
-        this.layers = [];
-        
-        if (this.controls == null) {
-            if (OpenLayers.Control != null) { // running full or lite?
-                this.controls = [ new OpenLayers.Control.Navigation(),
-                                  new OpenLayers.Control.PanZoom(),
-                                  new OpenLayers.Control.ArgParser(),
-                                  new OpenLayers.Control.Attribution()
-                                ];
-            } else {
-                this.controls = [];
-            }
-        }
-
-        for(var i=0; i < this.controls.length; i++) {
-            this.addControlToMap(this.controls[i]);
-        }
-
-        this.popups = [];
-
-        this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
-        
-
-        // always call map.destroy()
-        OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
-
-    },
-
-    /**
-     * Method: unloadDestroy
-     * Function that is called to destroy the map on page unload. stored here
-     *     so that if map is manually destroyed, we can unregister this.
-     */
-    unloadDestroy: null,
-
-    /**
-     * APIMethod: destroy
-     * Destroy this map
-     */
-    destroy:function() {
-        // if unloadDestroy is null, we've already been destroyed
-        if (!this.unloadDestroy) {
-            return false;
-        }
-
-        // map has been destroyed. dont do it again!
-        OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
-        this.unloadDestroy = null;
-
-        if (this.layers != null) {
-            for (var i = this.layers.length - 1; i>=0; --i) {
-                //pass 'false' to destroy so that map wont try to set a new 
-                // baselayer after each baselayer is removed
-                this.layers[i].destroy(false);
-            } 
-            this.layers = null;
-        }
-        if (this.controls != null) {
-            for (var i = this.controls.length - 1; i>=0; --i) {
-                this.controls[i].destroy();
-            } 
-            this.controls = null;
-        }
-        if (this.viewPortDiv) {
-            this.div.removeChild(this.viewPortDiv);
-        }
-        this.viewPortDiv = null;
-
-        this.events.destroy();
-        this.events = null;
-
-    },
-
-    /**
-     * APIMethod: setOptions
-     * Change the map options
-     *
-     * Parameters:
-     * options - {Object} Hashtable of options to tag to the map
-     */
-    setOptions: function(options) {
-
-        // Simple-type defaults are set in class definition. 
-        //  Now set complex-type defaults 
-        this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
-                                            OpenLayers.Map.TILE_HEIGHT);
-        
-        this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
-
-        this.theme = OpenLayers._getScriptLocation() + 
-                             'theme/default/style.css'; 
-
-        // now add the options declared by the user
-        //  (these will override defaults)
-        OpenLayers.Util.extend(this, options);
-    },
-
-    /**
-     * APIMethod: getTileSize
-     * Get the tile size for the map
-     *
-     * Returns:
-     * {<OpenLayers.Size>}
-     */
-     getTileSize: function() {
-         return this.tileSize;
-     },
-
-  /********************************************************/
-  /*                                                      */
-  /*                  Layer Functions                     */
-  /*                                                      */
-  /*     The following functions deal with adding and     */
-  /*        removing Layers to and from the Map           */
-  /*                                                      */
-  /********************************************************/         
-
-    /**
-     * APIMethod: getLayer
-     * Get a layer based on its id
-     *
-     * Parameter:
-     * id - {String} A layer id
-     *
-     * Returns:
-     * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's 
-     *                      layer collection, or null if not found.
-     */
-    getLayer: function(id) {
-        var foundLayer = null;
-        for (var i = 0; i < this.layers.length; i++) {
-            var layer = this.layers[i];
-            if (layer.id == id) {
-                foundLayer = layer;
-            }
-        }
-        return foundLayer;
-    },
-
-    /**
-    * Method: setLayerZIndex
-    * 
-    * Parameters:
-    * layer - {<OpenLayers.Layer>} 
-    * zIdx - {int} 
-    */    
-    setLayerZIndex: function (layer, zIdx) {
-        layer.setZIndex(
-            this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
-            + zIdx * 5 );
-    },
-
-    /**
-    * APIMethod: addLayer
-    *
-    * Parameters:
-    * layer - {<OpenLayers.Layer>} 
-    */    
-    addLayer: function (layer) {
-        for(var i=0; i < this.layers.length; i++) {
-            if (this.layers[i] == layer) {
-                OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded", layer.name));
-                return false;
-            }
-        }    
-        
-        layer.div.style.overflow = "";
-        this.setLayerZIndex(layer, this.layers.length);
-
-        if (layer.isFixed) {
-            this.viewPortDiv.appendChild(layer.div);
-        } else {
-            this.layerContainerDiv.appendChild(layer.div);
-        }
-        this.layers.push(layer);
-        layer.setMap(this);
-
-        if (layer.isBaseLayer)  {
-            if (this.baseLayer == null) {
-                // set the first baselaye we add as the baselayer
-                this.setBaseLayer(layer);
-            } else {
-                layer.setVisibility(false);
-            }
-        } else {
-            layer.redraw();
-        }
-
-        this.events.triggerEvent("addlayer");
-    },
-
-    /**
-    * APIMethod: addLayers 
-    *
-    * Parameters:
-    * layers - Array({<OpenLayers.Layer>}) 
-    */    
-    addLayers: function (layers) {
-        for (var i = 0; i <  layers.length; i++) {
-            this.addLayer(layers[i]);
-        }
-    },
-
-    /** 
-     * APIMethod: removeLayer
-     * Removes a layer from the map by removing its visual element (the 
-     *   layer.div property), then removing it from the map's internal list 
-     *   of layers, setting the layer's map property to null. 
-     * 
-     *   a "removelayer" event is triggered.
-     * 
-     *   very worthy of mention is that simply removing a layer from a map
-     *   will not cause the removal of any popups which may have been created
-     *   by the layer. this is due to the fact that it was decided at some
-     *   point that popups would not belong to layers. thus there is no way 
-     *   for us to know here to which layer the popup belongs.
-     *    
-     *     A simple solution to this is simply to call destroy() on the layer.
-     *     the default OpenLayers.Layer class's destroy() function
-     *     automatically takes care to remove itself from whatever map it has
-     *     been attached to. 
-     * 
-     *     The correct solution is for the layer itself to register an 
-     *     event-handler on "removelayer" and when it is called, if it 
-     *     recognizes itself as the layer being removed, then it cycles through
-     *     its own personal list of popups, removing them from the map.
-     * 
-     * Parameters:
-     * layer - {<OpenLayers.Layer>} 
-     * setNewBaseLayer - {Boolean} Default is true
-     */
-    removeLayer: function(layer, setNewBaseLayer) {
-        if (setNewBaseLayer == null) {
-            setNewBaseLayer = true;
-        }
-
-        if (layer.isFixed) {
-            this.viewPortDiv.removeChild(layer.div);
-        } else {
-            this.layerContainerDiv.removeChild(layer.div);
-        }
-        OpenLayers.Util.removeItem(this.layers, layer);
-        layer.removeMap(this);
-        layer.map = null;
-
-        // if we removed the base layer, need to set a new one
-        if (setNewBaseLayer && (this.baseLayer == layer)) {
-            this.baseLayer = null;
-            for(i=0; i < this.layers.length; i++) {
-                var iLayer = this.layers[i];
-                if (iLayer.isBaseLayer) {
-                    this.setBaseLayer(iLayer);
-                    break;
-                }
-            }
-        }
-        this.events.triggerEvent("removelayer");
-    },
-
-    /**
-     * APIMethod: getNumLayers
-     * 
-     * Returns:
-     * {Int} The number of layers attached to the map.
-     */
-    getNumLayers: function () {
-        return this.layers.length;
-    },
-
-    /** 
-     * APIMethod: getLayerIndex
-     *
-     * Parameters:
-     * layer - {<OpenLayers.Layer>}
-     *
-     * Returns:
-     * {Integer} The current (zero-based) index of the given layer in the map's
-     *           layer stack. Returns -1 if the layer isn't on the map.
-     */
-    getLayerIndex: function (layer) {
-        return OpenLayers.Util.indexOf(this.layers, layer);
-    },
-    
-    /** 
-     * APIMethod: setLayerIndex
-     * Move the given layer to the specified (zero-based) index in the layer
-     *     list, changing its z-index in the map display. Use
-     *     map.getLayerIndex() to find out the current index of a layer. Note
-     *     that this cannot (or at least should not) be effectively used to
-     *     raise base layers above overlays.
-     *
-     * Parameters:
-     * layer - {<OpenLayers.Layer>} 
-     * idx - {int} 
-     */
-    setLayerIndex: function (layer, idx) {
-        var base = this.getLayerIndex(layer);
-        if (idx < 0) {
-            idx = 0;
-        } else if (idx > this.layers.length) {
-            idx = this.layers.length;
-        }
-        if (base != idx) {
-            this.layers.splice(base, 1);
-            this.layers.splice(idx, 0, layer);
-            for (var i = 0; i < this.layers.length; i++) {
-                this.setLayerZIndex(this.layers[i], i);
-            }
-            this.events.triggerEvent("changelayer");
-        }
-    },
-
-    /** 
-     * APIMethod: raiseLayer
-     * Change the index of the given layer by delta. If delta is positive, 
-     *     the layer is moved up the map's layer stack; if delta is negative,
-     *     the layer is moved down.  Again, note that this cannot (or at least
-     *     should not) be effectively used to raise base layers above overlays.
-     *
-     * Paremeters:
-     * layer - {<OpenLayers.Layer>} 
-     * idx - {int} 
-     */
-    raiseLayer: function (layer, delta) {
-        var idx = this.getLayerIndex(layer) + delta;
-        this.setLayerIndex(layer, idx);
-    },
-    
-    /** 
-     * APIMethod: setBaseLayer
-     * Allows user to specify one of the currently-loaded layers as the Map's
-     *     new base layer.
-     * 
-     * Parameters:
-     * newBaseLayer - {<OpenLayers.Layer>}
-     */
-    setBaseLayer: function(newBaseLayer) {
-        var oldExtent = null;
-        if(this.baseLayer) {
-            oldExtent = this.baseLayer.getExtent();
-        }
-
-        if (newBaseLayer != this.baseLayer) {
-          
-            // is newBaseLayer an already loaded layer?m
-            if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
-
-                // make the old base layer invisible 
-                if (this.baseLayer != null) {
-                    this.baseLayer.setVisibility(false);
-                }
-
-                // set new baselayer and make it visible
-                this.baseLayer = newBaseLayer;
-                
-                //copy over projection and extent information
-                this.maxExtent = newBaseLayer.maxExtent;
-                this.minExtent = newBaseLayer.minExtent;
-                this.maxScale = newBaseLayer.maxScale;
-                this.minScale = newBaseLayer.minScale;
-                this.maxResolution = newBaseLayer.maxResolution;
-                this.minResolution = newBaseLayer.minResolution;
-                this.units = newBaseLayer.units;
-                this.projection = newBaseLayer.projection;
-                
-                // Increment viewRequestID since the baseLayer is 
-                // changing. This is used by tiles to check if they should 
-                // draw themselves.
-                this.viewRequestID++;
-                this.baseLayer.visibility = true;
-
-                //redraw all layers
-                var center = this.getCenter();
-                if (center != null) {
-                    if (oldExtent == null) {
-                        // simply set center but force zoom change
-                        this.setCenter(center, this.getZoom(), false, true);
-                    } else {
-                        // zoom to oldExtent *and* force zoom change
-                        this.setCenter(oldExtent.getCenterLonLat(), 
-                                       this.getZoomForExtent(oldExtent),
-                                       false, true);
-                    }
-                }
-
-                this.events.triggerEvent("changebaselayer");
-            }        
-        }
-    },
-
-
-  /********************************************************/
-  /*                                                      */
-  /*                 Control Functions                    */
-  /*                                                      */
-  /*     The following functions deal with adding and     */
-  /*        removing Controls to and from the Map         */
-  /*                                                      */
-  /********************************************************/         
-
-    /**
-     * APIMethod: addControl
-     * 
-     * Parameters:
-     * control - {<OpenLayers.Control>}
-     * px - {<OpenLayers.Pixel>}
-     */    
-    addControl: function (control, px) {
-        this.controls.push(control);
-        this.addControlToMap(control, px);
-    },
-
-    /**
-     * Method: addControlToMap
-     * 
-     * Parameters:
-     * 
-     * control - {<OpenLayers.Control>}
-     * px - {<OpenLayers.Pixel>}
-     */    
-    addControlToMap: function (control, px) {
-        // If a control doesn't have a div at this point, it belongs in the
-        // viewport.
-        control.outsideViewport = (control.div != null);
-        control.setMap(this);
-        var div = control.draw(px);
-        if (div) {
-            if(!control.outsideViewport) {
-                div.style.zIndex = this.Z_INDEX_BASE['Control'] +
-                                    this.controls.length;
-                this.viewPortDiv.appendChild( div );
-            }
-        }
-    },
-    
-    /**
-     * APIMethod: getControl
-     * 
-     * Parameters:
-     * id - {String} ID of the control to return.
-     * 
-     * Returns:
-     * {<OpenLayers.Control>} The control from the map's list of controls 
-     *                        which has a matching 'id'. If none found, 
-     *                        returns null.
-     */    
-    getControl: function (id) {
-        var returnControl = null;
-        for(var i=0; i < this.controls.length; i++) {
-            var control = this.controls[i];
-            if (control.id == id) {
-                returnControl = control;
-                break;
-            }
-        }
-        return returnControl;
-    },
-    
-    /** 
-     * APIMethod: removeControl
-     * Remove a control from the map. Removes the control both from the map 
-     *     object's internal array of controls, as well as from the map's 
-     *     viewPort (assuming the control was not added outsideViewport)
-     * 
-     * Parameters:
-     * control - {<OpenLayers.Control>} The control to remove.
-     */    
-    removeControl: function (control) {
-        //make sure control is non-null and actually part of our map
-        if ( (control) && (control == this.getControl(control.id)) ) {
-            if (!control.outsideViewport) {
-                this.viewPortDiv.removeChild(control.div)
-            }
-            OpenLayers.Util.removeItem(this.controls, control);
-        }
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*                  Popup Functions                     */
-  /*                                                      */
-  /*     The following functions deal with adding and     */
-  /*        removing Popups to and from the Map           */
-  /*                                                      */
-  /********************************************************/         
-
-    /** 
-     * APIMethod: addPopup
-     * 
-     * Parameters:
-     * popup - {<OpenLayers.Popup>}
-     * exclusive - {Boolean} If true, closes all other popups first
-     */
-    addPopup: function(popup, exclusive) {
-
-        if (exclusive) {
-            //remove all other popups from screen
-            for(var i=0; i < this.popups.length; i++) {
-                this.removePopup(this.popups[i]);
-            }
-        }
-
-        popup.map = this;
-        this.popups.push(popup);
-        var popupDiv = popup.draw();
-        if (popupDiv) {
-            popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +
-                                    this.popups.length;
-            this.layerContainerDiv.appendChild(popupDiv);
-        }
-    },
-    
-    /** 
-    * APIMethod: removePopup
-    * 
-    * Parameters:
-    * popup - {<OpenLayers.Popup>}
-    */
-    removePopup: function(popup) {
-        OpenLayers.Util.removeItem(this.popups, popup);
-        if (popup.div) {
-            try { this.layerContainerDiv.removeChild(popup.div); }
-            catch (e) { } // Popups sometimes apparently get disconnected
-                      // from the layerContainerDiv, and cause complaints.
-        }
-        popup.map = null;
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*              Container Div Functions                 */
-  /*                                                      */
-  /*   The following functions deal with the access to    */
-  /*    and maintenance of the size of the container div  */
-  /*                                                      */
-  /********************************************************/     
-
-    /**
-     * APIMethod: getSize
-     * 
-     * Returns:
-     * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the 
-     *                     size, in pixels, of the div into which OpenLayers 
-     *                     has been loaded. 
-     *                     Note - A clone() of this locally cached variable is
-     *                     returned, so as not to allow users to modify it.
-     */
-    getSize: function () {
-        var size = null;
-        if (this.size != null) {
-            size = this.size.clone();
-        }
-        return size;
-    },
-
-    /**
-     * APIMethod: updateSize
-     * This function should be called by any external code which dynamically
-     *     changes the size of the map div (because mozilla wont let us catch 
-     *     the "onresize" for an element)
-     */
-    updateSize: function() {
-        // the div might have moved on the page, also
-        this.events.element.offsets = null;
-        var newSize = this.getCurrentSize();
-        var oldSize = this.getSize();
-        if (oldSize == null)
-            this.size = oldSize = newSize;
-        if (!newSize.equals(oldSize)) {
-            
-            // store the new size
-            this.size = newSize;
-
-            //notify layers of mapresize
-            for(var i=0; i < this.layers.length; i++) {
-                this.layers[i].onMapResize();                
-            }
-
-            if (this.baseLayer != null) {
-                var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
-                var centerLL = this.getLonLatFromViewPortPx(center);
-                var zoom = this.getZoom();
-                this.zoom = null;
-                this.setCenter(this.getCenter(), zoom);
-            }
-
-        }
-    },
-    
-    /**
-     * Method: getCurrentSize
-     * 
-     * Returns:
-     * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions 
-     *                     of the map div
-     */
-    getCurrentSize: function() {
-
-        var size = new OpenLayers.Size(this.div.clientWidth, 
-                                       this.div.clientHeight);
-
-        // Workaround for the fact that hidden elements return 0 for size.
-        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
-            var dim = OpenLayers.Element.getDimensions(this.div);
-            size.w = dim.width;
-            size.h = dim.height;
-        }
-        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
-            size.w = parseInt(this.div.style.width);
-            size.h = parseInt(this.div.style.height);
-        }
-        return size;
-    },
-
-    /** 
-     * Method: calculateBounds
-     * 
-     * Parameters:
-     * center - {<OpenLayers.LonLat>} Default is this.getCenter()
-     * resolution - {float} Default is this.getResolution() 
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A bounds based on resolution, center, and 
-     *                       current mapsize.
-     */
-    calculateBounds: function(center, resolution) {
-
-        var extent = null;
-        
-        if (center == null) {
-            center = this.getCenter();
-        }                
-        if (resolution == null) {
-            resolution = this.getResolution();
-        }
-    
-        if ((center != null) && (resolution != null)) {
-
-            var size = this.getSize();
-            var w_deg = size.w * resolution;
-            var h_deg = size.h * resolution;
-        
-            extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
-                                           center.lat - h_deg / 2,
-                                           center.lon + w_deg / 2,
-                                           center.lat + h_deg / 2);
-        
-        }
-
-        return extent;
-    },
-
-
-  /********************************************************/
-  /*                                                      */
-  /*            Zoom, Center, Pan Functions               */
-  /*                                                      */
-  /*    The following functions handle the validation,    */
-  /*   getting and setting of the Zoom Level and Center   */
-  /*       as well as the panning of the Map              */
-  /*                                                      */
-  /********************************************************/
-    /**
-     * APIMethod: getCenter
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>}
-     */
-    getCenter: function () {
-        return this.center;
-    },
-
-
-    /**
-     * APIMethod: getZoom
-     * 
-     * Returns:
-     * {Integer}
-     */
-    getZoom: function () {
-        return this.zoom;
-    },
-    
-    /** 
-     * APIMethod: pan
-     * Allows user to pan by a value of screen pixels
-     * 
-     * Parameters:
-     * dx - {Integer}
-     * dy - {Integer}
-     */
-    pan: function(dx, dy) {
-
-        // getCenter
-        var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
-
-        // adjust
-        var newCenterPx = centerPx.add(dx, dy);
-        
-        // only call setCenter if there has been a change
-        if (!newCenterPx.equals(centerPx)) {
-            var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
-            this.setCenter(newCenterLonLat);
-        }
-
-   },
-
-    /**
-     * APIMethod: setCenter
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     * zoom - {Integer}
-     * dragging - {Boolean} Specifies whether or not to trigger 
-     *                      movestart/end events
-     * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom 
-     *                             change events (needed on baseLayer change)
-     *
-     * TBD: reconsider forceZoomChange in 3.0
-     */
-    setCenter: function (lonlat, zoom, dragging, forceZoomChange) {
-
-        if (!this.center && !this.isValidLonLat(lonlat)) {
-            lonlat = this.maxExtent.getCenterLonLat();
-        }
-
-        if (this.restrictedExtent && this.restrictedExtent != 'auto') {
-            // In 3.0, decide if we want to change interpretation of maxExtent.
-            if(lonlat == null) { 
-                lonlat = this.getCenter(); 
-            }
-            if(zoom == null) { 
-                zoom = this.getZoom(); 
-            }
-            var resolution = null;
-            if(this.baseLayer != null) {
-                resolution = this.baseLayer.resolutions[zoom];
-            }
-            var extent = this.calculateBounds(lonlat, resolution); 
-            if(!this.restrictedExtent.containsBounds(extent)) {
-                var maxCenter = this.restrictedExtent.getCenterLonLat(); 
-                if(extent.getWidth() > this.restrictedExtent.getWidth()) { 
-                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); 
-                } else if(extent.left < this.restrictedExtent.left) {
-                    lonlat = lonlat.add(this.restrictedExtent.left -
-                                        extent.left, 0); 
-                } else if(extent.right > this.restrictedExtent.right) { 
-                    lonlat = lonlat.add(this.restrictedExtent.right -
-                                        extent.right, 0); 
-                } 
-                if(extent.getHeight() > this.restrictedExtent.getHeight()) { 
-                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); 
-                } else if(extent.bottom < this.restrictedExtent.bottom) { 
-                    lonlat = lonlat.add(0, this.restrictedExtent.bottom -
-                                        extent.bottom); 
-                } 
-                else if(extent.top > this.restrictedExtent.top) { 
-                    lonlat = lonlat.add(0, this.restrictedExtent.top -
-                                        extent.top); 
-                } 
-            }
-        }
-        
-        var zoomChanged = forceZoomChange || (
-                            (this.isValidZoomLevel(zoom)) && 
-                            (zoom != this.getZoom()) );
-
-        var centerChanged = !lonlat.equals(this.center);
-        if (this.restrictedExtent == 'auto') {
-          centerChanged = this.isValidLonLat(lonlat) && centerChanged;
-        }
-
-        // if neither center nor zoom will change, no need to do anything
-        if (zoomChanged || centerChanged || !dragging) {
-
-            if (!dragging) { this.events.triggerEvent("movestart"); }
-
-            if (centerChanged) {
-                if ((!zoomChanged) && (this.center)) { 
-                    // if zoom hasnt changed, just slide layerContainer
-                    //  (must be done before setting this.center to new value)
-                    this.centerLayerContainer(lonlat);
-                }
-                this.center = lonlat.clone();
-            }
-
-            // (re)set the layerContainerDiv's location
-            if ((zoomChanged) || (this.layerContainerOrigin == null)) {
-                this.layerContainerOrigin = this.center.clone();
-                this.layerContainerDiv.style.left = "0px";
-                this.layerContainerDiv.style.top  = "0px";
-            }
-
-            if (zoomChanged) {
-                this.zoom = zoom;
-                // zoom level has changed, increment viewRequestID.
-                this.viewRequestID++;
-            }    
-            
-            var bounds = this.getExtent();
-            
-            //send the move call to the baselayer and all the overlays    
-            this.baseLayer.moveTo(bounds, zoomChanged, dragging);
-            
-            bounds = this.baseLayer.getExtent();
-            
-            for (var i = 0; i < this.layers.length; i++) {
-                var layer = this.layers[i];
-                if (!layer.isBaseLayer) {
-                    
-                    var moveLayer;
-                    var inRange = layer.calculateInRange();
-                    if (layer.inRange != inRange) {
-                        // Layer property has changed. We are going 
-                        // to call moveLayer so that the layer can be turned
-                        // off or on.   
-                        layer.inRange = inRange;
-                        moveLayer = true;
-                        this.events.triggerEvent("changelayer");
-                    } else {
-                        // If nothing has changed, then we only move the layer
-                        // if it is visible and inrange.
-                        moveLayer = (layer.visibility && layer.inRange);
-                    }
-
-                    if (moveLayer) {
-                        layer.moveTo(bounds, zoomChanged, dragging);
-                    }
-                }                
-            }
-            
-            if (zoomChanged) {
-                //redraw popups
-                for (var i = 0; i < this.popups.length; i++) {
-                    this.popups[i].updatePosition();
-                }
-            }    
-            
-            this.events.triggerEvent("move");
-    
-            if (zoomChanged) { this.events.triggerEvent("zoomend"); }
-        }
-
-        // even if nothing was done, we want to notify of this
-        if (!dragging) { this.events.triggerEvent("moveend"); }
-    },
-
-    /** 
-     * Method: centerLayerContainer
-     * This function takes care to recenter the layerContainerDiv.
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     */
-    centerLayerContainer: function (lonlat) {
-
-        var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
-        var newPx = this.getViewPortPxFromLonLat(lonlat);
-
-        if ((originPx != null) && (newPx != null)) {
-            this.layerContainerDiv.style.left = (originPx.x - newPx.x) + "px";
-            this.layerContainerDiv.style.top  = (originPx.y - newPx.y) + "px";
-        }
-    },
-
-    /**
-     * Method: isValidZoomLevel
-     * 
-     * Parameters:
-     * zoomLevel - {Integer}
-     * 
-     * Returns:
-     * {Boolean} Whether or not the zoom level passed in is non-null and 
-     *           within the min/max range of zoom levels.
-     */
-    isValidZoomLevel: function(zoomLevel) {
-       return ( (zoomLevel != null) &&
-                (zoomLevel >= 0) && 
-                (zoomLevel < this.getNumZoomLevels()) );
-    },
-    
-    /**
-     * Method: isValidLonLat
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     * 
-     * Returns:
-     * {Boolean} Whether or not the lonlat passed in is non-null and within
-     *           the maxExtent bounds
-     */
-    isValidLonLat: function(lonlat) {
-        var valid = false;
-        if (lonlat != null) {
-            var maxExtent = this.getMaxExtent();
-            valid = maxExtent.containsLonLat(lonlat);        
-        }
-        return valid;
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*                 Layer Options                        */
-  /*                                                      */
-  /*    Accessor functions to Layer Options parameters    */
-  /*                                                      */
-  /********************************************************/
-    
-    /**
-     * APIMethod: getProjection
-     * 
-     * Returns:
-     * {String} The Projection of the base layer.
-     */
-    getProjection: function() {
-        var projection = null;
-        if (this.baseLayer != null) {
-            projection = this.baseLayer.projection;
-        }
-        return projection;
-    },
-    
-    /**
-     * APIMethod: getMaxResolution
-     * 
-     * Returns:
-     * {String} The Map's Maximum Resolution
-     */
-    getMaxResolution: function() {
-        var maxResolution = null;
-        if (this.baseLayer != null) {
-            maxResolution = this.baseLayer.maxResolution;
-        }
-        return maxResolution;
-    },
-        
-    /**
-     * APIMethod: getMaxExtent
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>}
-     */
-    getMaxExtent: function () {
-        var maxExtent = null;
-        if (this.baseLayer != null) {
-            maxExtent = this.baseLayer.maxExtent;
-        }        
-        return maxExtent;
-    },
-    
-    /**
-     * APIMethod: getNumZoomLevels
-     * 
-     * Returns:
-     * {Integer} The total number of zoom levels that can be displayed by the 
-     *           current baseLayer.
-     */
-    getNumZoomLevels: function() {
-        var numZoomLevels = null;
-        if (this.baseLayer != null) {
-            numZoomLevels = this.baseLayer.numZoomLevels;
-        }
-        return numZoomLevels;
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*                 Baselayer Functions                  */
-  /*                                                      */
-  /*    The following functions, all publicly exposed     */
-  /*       in the API?, are all merely wrappers to the    */
-  /*       the same calls on whatever layer is set as     */
-  /*                the current base layer                */
-  /*                                                      */
-  /********************************************************/
-
-    /**
-     * APIMethod: getExtent
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
-     *                       bounds of the current viewPort. 
-     *                       If no baselayer is set, returns null.
-     */
-    getExtent: function () {
-        var extent = null;
-        if (this.baseLayer != null) {
-            extent = this.baseLayer.getExtent();
-        }
-        return extent;
-    },
-    
-    /**
-     * APIMethod: getResolution
-     * 
-     * Returns:
-     * {Float} The current resolution of the map. 
-     *         If no baselayer is set, returns null.
-     */
-    getResolution: function () {
-        var resolution = null;
-        if (this.baseLayer != null) {
-            resolution = this.baseLayer.getResolution();
-        }
-        return resolution;
-    },
-
-     /**
-      * APIMethod: getScale
-      * 
-      * Returns:
-      * {Float} The current scale denominator of the map. 
-      *         If no baselayer is set, returns null.
-      */
-    getScale: function () {
-        var scale = null;
-        if (this.baseLayer != null) {
-            var res = this.getResolution();
-            var units = this.baseLayer.units;
-            scale = OpenLayers.Util.getScaleFromResolution(res, units);
-        }
-        return scale;
-    },
-
-
-    /**
-     * APIMethod: getZoomForExtent
-     * 
-     * Parameters: 
-     * bounds - {<OpenLayers.Bounds>}
-     * 
-     * Returns:
-     * {Integer} A suitable zoom level for the specified bounds.
-     *           If no baselayer is set, returns null.
-     */
-    getZoomForExtent: function (bounds) {
-        var zoom = null;
-        if (this.baseLayer != null) {
-            zoom = this.baseLayer.getZoomForExtent(bounds);
-        }
-        return zoom;
-    },
-
-    /**
-     * APIMethod: getZoomForResolution
-     * 
-     * Parameter:
-     * resolution - {Float}
-     * 
-     * Returns:
-     * {Integer} A suitable zoom level for the specified resolution.
-     *           If no baselayer is set, returns null.
-     */
-    getZoomForResolution: function(resolution) {
-        var zoom = null;
-        if (this.baseLayer != null) {
-            zoom = this.baseLayer.getZoomForResolution(resolution);
-        }
-        return zoom;
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*                  Zooming Functions                   */
-  /*                                                      */
-  /*    The following functions, all publicly exposed     */
-  /*       in the API, are all merely wrappers to the     */
-  /*               the setCenter() function               */
-  /*                                                      */
-  /********************************************************/
-  
-    /** 
-     * APIMethod: zoomTo
-     * Zoom to a specific zoom level
-     * 
-     * Parameters:
-     * zoom - {Integer}
-     */
-    zoomTo: function(zoom) {
-        if (this.isValidZoomLevel(zoom)) {
-            this.setCenter(null, zoom);
-        }
-    },
-    
-    /**
-     * APIMethod: zoomIn
-     * 
-     * Parameters:
-     * zoom - {int}
-     */
-    zoomIn: function() {
-        this.zoomTo(this.getZoom() + 1);
-    },
-    
-    /**
-     * APIMethod: zoomOut
-     * 
-     * Parameters:
-     * zoom - {int}
-     */
-    zoomOut: function() {
-        this.zoomTo(this.getZoom() - 1);
-    },
-
-    /**
-     * APIMethod: zoomToExtent
-     * Zoom to the passed in bounds, recenter
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    zoomToExtent: function(bounds) {
-        var center = bounds.getCenterLonLat();
-        if (this.baseLayer.wrapDateLine) {
-            var maxExtent = this.getMaxExtent();
-
-            //fix straddling bounds (in the case of a bbox that straddles the 
-            // dateline, it's left and right boundaries will appear backwards. 
-            // we fix this by allowing a right value that is greater than the
-            // max value at the dateline -- this allows us to pass a valid 
-            // bounds to calculate zoom)
-            //
-            bounds = bounds.clone();
-            while (bounds.right < bounds.left) {
-                bounds.right += maxExtent.getWidth();
-            }
-            //if the bounds was straddling (see above), then the center point 
-            // we got from it was wrong. So we take our new bounds and ask it
-            // for the center. Because our new bounds is at least partially 
-            // outside the bounds of maxExtent, the new calculated center 
-            // might also be. We don't want to pass a bad center value to 
-            // setCenter, so we have it wrap itself across the date line.
-            //
-            center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
-        }
-        this.setCenter(center, this.getZoomForExtent(bounds));
-    },
-
-    /** 
-     * APIMethod: zoomToMaxExtent
-     * Zoom to the full extent and recenter.
-     */
-    zoomToMaxExtent: function() {
-        this.zoomToExtent(this.getMaxExtent());
-    },
-
-    /** 
-     * APIMethod: zoomToScale
-     * Zoom to a specified scale 
-     * 
-     * Parameters:
-     * scale - {float}
-     */
-    zoomToScale: function(scale) {
-        var res = OpenLayers.Util.getResolutionFromScale(scale, 
-                                                         this.baseLayer.units);
-        var size = this.getSize();
-        var w_deg = size.w * res;
-        var h_deg = size.h * res;
-        var center = this.getCenter();
-
-        var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
-                                           center.lat - h_deg / 2,
-                                           center.lon + w_deg / 2,
-                                           center.lat + h_deg / 2);
-        this.zoomToExtent(extent);
-    },
-    
-  /********************************************************/
-  /*                                                      */
-  /*             Translation Functions                    */
-  /*                                                      */
-  /*      The following functions translate between       */
-  /*           LonLat, LayerPx, and ViewPortPx            */
-  /*                                                      */
-  /********************************************************/
-      
-  //
-  // TRANSLATION: LonLat <-> ViewPortPx
-  //
-
-    /**
-     * APIMethod: getLonLatFromViewPortPx
-     * 
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>}
-     * 
-     * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view 
-     *                       port <OpenLayers.Pixel>, translated into lon/lat
-     *                       by the current base layer.
-     */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        var lonlat = null; 
-        if (this.baseLayer != null) {
-            lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
-        }
-        return lonlat;
-    },
-
-    /**
-     * APIMethod: getViewPortPxFromLonLat
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     * 
-     * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
-     *                      <OpenLayers.LonLat>, translated into view port 
-     *                      pixels by the current base layer.
-     */
-    getViewPortPxFromLonLat: function (lonlat) {
-        var px = null; 
-        if (this.baseLayer != null) {
-            px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
-        }
-        return px;
-    },
-
-    
-  //
-  // CONVENIENCE TRANSLATION FUNCTIONS FOR API
-  //
-
-    /**
-     * APIMethod: getLonLatFromPixel
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
-     *                       OpenLayers.Pixel, translated into lon/lat by the 
-     *                       current base layer
-     */
-    getLonLatFromPixel: function (px) {
-        return this.getLonLatFromViewPortPx(px);
-    },
-
-    /**
-     * APIMethod: getPixelFromLonLat
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     * 
-     * Returns: 
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the 
-     *                      <OpenLayers.LonLat> translated into view port 
-     *                      pixels by the current base layer.
-     */
-    getPixelFromLonLat: function (lonlat) {
-        return this.getViewPortPxFromLonLat(lonlat);
-    },
-
-
-
-  //
-  // TRANSLATION: ViewPortPx <-> LayerPx
-  //
-
-    /**
-     * APIMethod: getViewPortPxFromLayerPx
-     * 
-     * Parameters:
-     * layerPx - {<OpenLayers.Pixel>}
-     * 
-     * Returns:
-     * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel 
-     *                      coordinates
-     */
-    getViewPortPxFromLayerPx:function(layerPx) {
-        var viewPortPx = null;
-        if (layerPx != null) {
-            var dX = parseInt(this.layerContainerDiv.style.left);
-            var dY = parseInt(this.layerContainerDiv.style.top);
-            viewPortPx = layerPx.add(dX, dY);            
-        }
-        return viewPortPx;
-    },
-    
-    /**
-     * APIMethod: getLayerPxFromViewPortPx
-     * 
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>}
-     * 
-     * Returns:
-     * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel 
-     *                      coordinates
-     */
-    getLayerPxFromViewPortPx:function(viewPortPx) {
-        var layerPx = null;
-        if (viewPortPx != null) {
-            var dX = -parseInt(this.layerContainerDiv.style.left);
-            var dY = -parseInt(this.layerContainerDiv.style.top);
-            layerPx = viewPortPx.add(dX, dY);
-            if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
-                layerPx = null;
-            }
-        }
-        return layerPx;
-    },
-    
-  //
-  // TRANSLATION: LonLat <-> LayerPx
-  //
-
-    /**
-     * APIMethod: getLonLatFromLayerPx
-     * 
-     * Parameters:
-     * px - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>}
-     */
-    getLonLatFromLayerPx: function (px) {
-       //adjust for displacement of layerContainerDiv
-       px = this.getViewPortPxFromLayerPx(px);
-       return this.getLonLatFromViewPortPx(px);         
-    },
-    
-    /**
-     * APIMethod: getLayerPxFromLonLat
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>} lonlat
-     *
-     * Returns:
-     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
-     *                      <OpenLayers.LonLat>, translated into layer pixels 
-     *                      by the current base layer
-     */
-    getLayerPxFromLonLat: function (lonlat) {
-       //adjust for displacement of layerContainerDiv
-       var px = this.getViewPortPxFromLonLat(lonlat);
-       return this.getLayerPxFromViewPortPx(px);         
-    },
-
-    CLASS_NAME: "OpenLayers.Map"
-});
-
-/**
- * Constant: TILE_WIDTH
- * {Integer} 256 Default tile width (unless otherwise specified)
- */
-OpenLayers.Map.TILE_WIDTH = 256;
-/**
- * Constant: TILE_HEIGHT
- * {Integer} 256 Default tile height (unless otherwise specified)
- */
-OpenLayers.Map.TILE_HEIGHT = 256;
-/* ======================================================================
-    OpenLayers/Marker.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Events.js
- * @requires OpenLayers/Icon.js
- * 
- * Class: OpenLayers.Marker
- * Instances of OpenLayers.Marker are a combination of a 
- * <OpenLayers.LonLat> and an <OpenLayers.Icon>.  
- *
- * Markers are generally added to a special layer called
- * <OpenLayers.Layer.Markers>.
- *
- * Example:
- * (code)
- * var markers = new OpenLayers.Layer.Markers( "Markers" );
- * map.addLayer(markers);
- *
- * var size = new OpenLayers.Size(10,17);
- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
- * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
- *
- * (end)
- *
- * Note that if you pass an icon into the Marker constructor, it will take
- * that icon and use it. This means that you should not share icons between
- * markers -- you use them once, but you should clone() for any additional
- * markers using that same icon.
- */
-OpenLayers.Marker = OpenLayers.Class({
-    
-    /** 
-     * Property: icon 
-     * {<OpenLayers.Icon>} The icon used by this marker.
-     */
-    icon: null,
-
-    /** 
-     * Property: lonlat 
-     * {<OpenLayers.LonLat>} location of object
-     */
-    lonlat: null,
-    
-    /** 
-     * Property: events 
-     * {<OpenLayers.Events>} the event handler.
-     */
-    events: null,
-    
-    /** 
-     * Property: map 
-     * {<OpenLayers.Map>} the map this marker is attached to
-     */
-    map: null,
-    
-    /** 
-     * Constructor: OpenLayers.Marker
-     * Paraemeters:
-     * icon - {<OpenLayers.Icon>}  the icon for this marker
-     * lonlat - {<OpenLayers.LonLat>} the position of this marker
-     */
-    initialize: function(lonlat, icon) {
-        this.lonlat = lonlat;
-        
-        var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
-        if (this.icon == null) {
-            this.icon = newIcon;
-        } else {
-            this.icon.url = newIcon.url;
-            this.icon.size = newIcon.size;
-            this.icon.offset = newIcon.offset;
-            this.icon.calculateOffset = newIcon.calculateOffset;
-        }
-        this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
-    },
-    
-    /**
-     * APIMethod: destroy
-     * Destroy the marker. You must first remove the marker from any 
-     * layer which it has been added to, or you will get buggy behavior.
-     * (This can not be done within the marker since the marker does not
-     * know which layer it is attached to.)
-     */
-    destroy: function() {
-        this.map = null;
-
-        this.events.destroy();
-        this.events = null;
-
-        if (this.icon != null) {
-            this.icon.destroy();
-            this.icon = null;
-        }
-    },
-    
-    /** 
-    * Method: draw
-    * Calls draw on the icon, and returns that output.
-    * 
-    * Parameters:
-    * px - {<OpenLayers.Pixel>}
-    * 
-    * Returns:
-    * {DOMElement} A new DOM Image with this marker's icon set at the 
-    * location passed-in
-    */
-    draw: function(px) {
-        return this.icon.draw(px);
-    }, 
-
-    /**
-    * Method: moveTo
-    * Move the marker to the new location.
-    *
-    * Parameters:
-    * px - {<OpenLayers.Pixel>} the pixel position to move to
-    */
-    moveTo: function (px) {
-        if ((px != null) && (this.icon != null)) {
-            this.icon.moveTo(px);
-        }           
-        this.lonlat = this.map.getLonLatFromLayerPx(px);
-    },
-
-    /**
-     * Method: onScreen
-     *
-     * Returns:
-     * {Boolean} Whether or not the marker is currently visible on screen.
-     */
-    onScreen:function() {
-        
-        var onScreen = false;
-        if (this.map) {
-            var screenBounds = this.map.getExtent();
-            onScreen = screenBounds.containsLonLat(this.lonlat);
-        }    
-        return onScreen;
-    },
-    
-    /**
-     * Method: inflate
-     * Englarges the markers icon by the specified ratio.
-     *
-     * Parameters:
-     * inflate - {float} the ratio to enlarge the marker by (passing 2
-     *                   will double the size).
-     */
-    inflate: function(inflate) {
-        if (this.icon) {
-            var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
-                                              this.icon.size.h * inflate);
-            this.icon.setSize(newSize);
-        }        
-    },
-    
-    /** 
-     * Method: setOpacity
-     * Change the opacity of the marker by changin the opacity of 
-     *   its icon
-     * 
-     * Parameters:
-     * opacity - {float}  Specified as fraction (0.4, etc)
-     */
-    setOpacity: function(opacity) {
-        this.icon.setOpacity(opacity);
-    },
-
-    /** 
-     * Method: display
-     * Hide or show the icon
-     * 
-     * display - {Boolean} 
-     */
-    display: function(display) {
-        this.icon.display(display);
-    },
-
-    CLASS_NAME: "OpenLayers.Marker"
-});
-
-
-/**
- * Function: defaultIcon
- * Creates a default <OpenLayers.Icon>.
- * 
- * Returns:
- * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
- */
-OpenLayers.Marker.defaultIcon = function() {
-    var url = OpenLayers.Util.getImagesLocation() + "marker.png";
-    var size = new OpenLayers.Size(21, 25);
-    var calculateOffset = function(size) {
-                    return new OpenLayers.Pixel(-(size.w/2), -size.h);
-                 };
-
-    return new OpenLayers.Icon(url, size, null, calculateOffset);        
-};
-    
-
-/* ======================================================================
-    OpenLayers/Tile/Image.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Tile.js
- * 
- * Class: OpenLayers.Tile.Image
- * Instances of OpenLayers.Tile.Image are used to manage the image tiles
- * used by various layers.  Create a new image tile with the
- * <OpenLayers.Tile.Image> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Tile>
- */
-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
-
-    /** 
-     * Property: url
-     * {String} The URL of the image being requested. No default. Filled in by
-     * layer.getURL() function. 
-     */
-    url: null,
-    
-    /** 
-     * Property: imgDiv
-     * {DOMElement} The div element which wraps the image.
-     */
-    imgDiv: null,
-
-    /**
-     * Property: frame
-     * {DOMElement} The image element is appended to the frame.  Any gutter on
-     * the image will be hidden behind the frame. 
-     */ 
-    frame: null, 
-
-    /** TBD 3.0 - reorder the parameters to the init function to remove 
-     *             URL. the getUrl() function on the layer gets called on 
-     *             each draw(), so no need to specify it here.
-     * 
-     * Constructor: OpenLayers.Tile.Image
-     * Constructor for a new <OpenLayers.Tile.Image> instance.
-     * 
-     * Parameters:
-     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
-     * position - {<OpenLayers.Pixel>}
-     * bounds - {<OpenLayers.Bounds>}
-     * url - {<String>} Deprecated. Remove me in 3.0.
-     * size - {<OpenLayers.Size>}
-     */   
-    initialize: function(layer, position, bounds, url, size) {
-        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
-        this.url = url; //deprecated remove me
-        
-        this.frame = document.createElement('div'); 
-        this.frame.style.overflow = 'hidden'; 
-        this.frame.style.position = 'absolute'; 
-    },
-
-    /** 
-     * APIMethod: destroy
-     * nullify references to prevent circular references and memory leaks
-     */
-    destroy: function() {
-        if (this.imgDiv != null)  {
-            OpenLayers.Event.stopObservingElement(this.imgDiv.id);
-            if (this.imgDiv.parentNode == this.frame) {
-                this.frame.removeChild(this.imgDiv);
-                this.imgDiv.map = null;
-            }
-        }
-        this.imgDiv = null;
-        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
-            this.layer.div.removeChild(this.frame); 
-        }
-        this.frame = null; 
-        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
-    },
-
-    /**
-     * Method: draw
-     * Check that a tile should be drawn, and draw it.
-     * 
-     * Returns:
-     * {Boolean} Always returns true.
-     */
-    draw:function() {
-        if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
-            this.bounds = this.getBoundsFromBaseLayer(this.position);
-        }
-        if (!OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
-            return false;    
-        }
-        
-        if (this.isLoading) {
-            //if we're already loading, send 'reload' instead of 'loadstart'.
-            this.events.triggerEvent("reload"); 
-        } else {
-            this.isLoading = true;
-            this.events.triggerEvent("loadstart");
-        }
-        
-        if (this.imgDiv == null) {
-            this.initImgDiv();
-        }
-
-        this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-        
-        this.url = this.layer.getURL(this.bounds);
-        // position the frame 
-        OpenLayers.Util.modifyDOMElement(this.frame, 
-                                         null, this.position, this.size);   
-
-        var imageSize = this.layer.getImageSize(); 
-        if (this.layer.alpha) {
-            OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
-                    null, null, imageSize, this.url);
-        } else {
-            this.imgDiv.src = this.url;
-            OpenLayers.Util.modifyDOMElement(this.imgDiv,
-                    null, null, imageSize) ;
-        }
-        return true;
-    },
-
-    /** 
-     * Method: clear
-     *  Clear the tile of any bounds/position-related data so that it can 
-     *   be reused in a new location.
-     */
-    clear: function() {
-        if(this.imgDiv) {
-            this.imgDiv.style.display = "none";
-        }
-    },
-
-    /**
-     * Method: initImgDiv
-     * Creates the imgDiv property on the tile.
-     */
-    initImgDiv: function() {
-        
-        var offset = this.layer.imageOffset; 
-        var size = this.layer.getImageSize(); 
-     
-        if (this.layer.alpha) {
-            this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
-                                                           offset,
-                                                           size,
-                                                           null,
-                                                           "relative",
-                                                           null,
-                                                           null,
-                                                           null,
-                                                           true);
-        } else {
-            this.imgDiv = OpenLayers.Util.createImage(null,
-                                                      offset,
-                                                      size,
-                                                      null,
-                                                      "relative",
-                                                      null,
-                                                      null,
-                                                      true);
-        }
-        
-        this.imgDiv.className = 'olTileImage';
-
-        /* checkImgURL used to be used to called as a work around, but it
-           ended up hiding problems instead of solving them and broke things
-           like relative URLs. See discussion on the dev list:
-           http://openlayers.org/pipermail/dev/2007-January/000205.html
-
-        OpenLayers.Event.observe( this.imgDiv, "load",
-            OpenLayers.Function.bind(this.checkImgURL, this) );
-        */
-        this.frame.appendChild(this.imgDiv); 
-        this.layer.div.appendChild(this.frame); 
-
-        if(this.layer.opacity != null) {
-            
-            OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
-                                             null, null, null, 
-                                             this.layer.opacity);
-        }
-
-        // we need this reference to check back the viewRequestID
-        this.imgDiv.map = this.layer.map;
-
-        //bind a listener to the onload of the image div so that we 
-        // can register when a tile has finished loading.
-        var onload = function() {
-            
-            //normally isLoading should always be true here but there are some 
-            // right funky conditions where loading and then reloading a tile
-            // with the same url *really*fast*. this check prevents sending 
-            // a 'loadend' if the msg has already been sent
-            //
-            if (this.isLoading) { 
-                this.isLoading = false; 
-                this.events.triggerEvent("loadend"); 
-            }
-        }
-        OpenLayers.Event.observe(this.imgDiv, 'load',
-                                 OpenLayers.Function.bind(onload, this));
-
-    },
-
-    /**
-     * Method: checkImgURL
-     * Make sure that the image that just loaded is the one this tile is meant
-     * to display, since panning/zooming might have changed the tile's URL in
-     * the meantime. If the tile URL did change before the image loaded, set
-     * the imgDiv display to 'none', as either (a) it will be reset to visible
-     * when the new URL loads in the image, or (b) we don't want to display
-     * this tile after all because its new bounds are outside our maxExtent.
-     * 
-     * This function should no longer  be neccesary with the improvements to
-     * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
-     * caused problems in 2.2, but it's possible that with the improved 
-     * isEquivilant URL function, this might be neccesary at some point.
-     * 
-     * See discussion in the thread at 
-     * http://openlayers.org/pipermail/dev/2007-January/000205.html
-     */
-    checkImgURL: function () {
-        // Sometimes our image will load after it has already been removed
-        // from the map, in which case this check is not needed.  
-        if (this.layer) {
-            var loaded = this.layer.alpha ? this.imgDiv.firstChild.src : this.imgDiv.src;
-            if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
-                this.imgDiv.style.display = "none";
-            }
-        }
-    },
-
-    /** @final @type String */
-    CLASS_NAME: "OpenLayers.Tile.Image"
-  }
-);
-/* ======================================================================
-    OpenLayers/Handler/Drag.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- * 
- * Class: OpenLayers.Handler.Drag
- * The drag handler is used to deal with sequences of browser events related
- *     to dragging.  The handler is used by controls that want to know when
- *     a drag sequence begins, when a drag is happening, and when it has
- *     finished.
- *
- * Controls that use the drag handler typically construct it with callbacks
- *     for 'down', 'move', and 'done'.  Callbacks for these keys are called
- *     when the drag begins, with each move, and when the drag is done.  In
- *     addition, controls can have callbacks keyed to 'up' and 'out' if they
- *     care to differentiate between the types of events that correspond with
- *     the end of a drag sequence.
- *
- * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
-  
-    /** 
-     * Property: started
-     * {Boolean} When a mousedown event is received, we want to record it, but
-     *     not set 'dragging' until the mouse moves after starting. 
-     */
-    started: false,
-    
-    /** 
-     * Property: dragging 
-     * {Boolean} 
-     */
-    dragging: false,
-
-    /** 
-     * Property: last
-     * {<OpenLayers.Pixel>} The last pixel location of the drag.
-     */
-    last: null,
-
-    /** 
-     * Property: start
-     * {<OpenLayers.Pixel>} The first pixel location of the drag.
-     */
-    start: null,
-
-    /**
-     * Property: oldOnselectstart
-     * {Function}
-     */
-    oldOnselectstart: null,
-
-    /**
-     * Constructor: OpenLayers.Handler.Drag
-     * Returns OpenLayers.Handler.Drag
-     * 
-     * Parameters:
-     * control - {<OpenLayers.Control>} The control that is making use of
-     *     this handler.  If a handler is being used without a control, the
-     *     handlers setMap method must be overridden to deal properly with
-     *     the map.
-     * callbacks - {Object} An object containing a single function to be
-     *     called when the drag operation is finished. The callback should
-     *     expect to recieve a single argument, the pixel location of the event.
-     *     Callbacks for 'move' and 'done' are supported. You can also speficy
-     *     callbacks for 'down', 'up', and 'out' to respond to those events.
-     * options - {Object} 
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-    },
-    
-    /**
-     * The four methods below (down, move, up, and out) are used by subclasses
-     *     to do their own processing related to these mouse events.
-     */
-    
-    /**
-     * Method: down
-     * This method is called during the handling of the mouse down event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse down event
-     */
-    down: function(evt) {
-    },
-    
-    /**
-     * Method: move
-     * This method is called during the handling of the mouse move event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse move event
-     *
-     */
-    move: function(evt) {
-    },
-
-    /**
-     * Method: up
-     * This method is called during the handling of the mouse up event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse up event
-     */
-    up: function(evt) {
-    },
-
-    /**
-     * Method: out
-     * This method is called during the handling of the mouse out event.
-     *     Subclasses can do their own processing here.
-     *
-     * Parameters:
-     * evt - {Event} The mouse out event
-     */
-    out: function(evt) {
-    },
-
-    /**
-     * The methods below are part of the magic of event handling.  Because
-     *     they are named like browser events, they are registered as listeners
-     *     for the events they represent.
-     */
-
-    /**
-     * Method: mousedown
-     * Handle mousedown events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mousedown: function (evt) {
-        var propagate = true;
-        this.dragging = false;
-        if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
-            this.started = true;
-            this.start = evt.xy;
-            this.last = evt.xy;
-            // TBD replace with CSS classes
-            this.map.div.style.cursor = "move";
-            this.down(evt);
-            this.callback("down", [evt.xy]);
-            OpenLayers.Event.stop(evt);
-            
-            if(!this.oldOnselectstart) {
-                this.oldOnselectstart = document.onselectstart;
-                document.onselectstart = function() {return false;}
-            }
-            
-            propagate = false;
-        } else {
-            this.started = false;
-            this.start = null;
-            this.last = null;
-        }
-        return propagate;
-    },
-
-    /**
-     * Method: mousemove
-     * Handle mousemove events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mousemove: function (evt) {
-        if (this.started) {
-            if(evt.xy.x != this.last.x || evt.xy.y != this.last.y) {
-                this.dragging = true;
-                this.move(evt);
-                this.callback("move", [evt.xy]);
-                if(!this.oldOnselectstart) {
-                    this.oldOnselectstart = document.onselectstart;
-                    document.onselectstart = function() {return false;}
-                }
-                this.last = evt.xy;
-            }
-        }
-        return true;
-    },
-
-    /**
-     * Method: mouseup
-     * Handle mouseup events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mouseup: function (evt) {
-        if (this.started) {
-            this.started = false;
-            this.dragging = false;
-            // TBD replace with CSS classes
-            this.map.div.style.cursor = "";
-            this.up(evt);
-            this.callback("up", [evt.xy]);
-            this.callback("done", [evt.xy]);
-            document.onselectstart = this.oldOnselectstart;
-        }
-        return true;
-    },
-
-    /**
-     * Method: mouseout
-     * Handle mouseout events
-     *
-     * Parameters:
-     * evt - {Event} 
-     *
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    mouseout: function (evt) {
-        if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
-            this.started = false; 
-            this.dragging = false;
-            // TBD replace with CSS classes
-            this.map.div.style.cursor = "";
-            this.out(evt);
-            this.callback("out", []);
-            if(document.onselectstart) {
-                document.onselectstart = this.oldOnselectstart;
-            }
-            this.callback("done", [evt.xy])
-        }
-        return true;
-    },
-
-    /**
-     * Method: click
-     * The drag handler captures the click event.  If something else registers
-     *     for clicks on the same element, its listener will not be called 
-     *     after a drag.
-     * 
-     * Parameters: 
-     * evt - {Event} 
-     * 
-     * Returns:
-     * {Boolean} Let the event propagate.
-     */
-    click: function (evt) {
-        // let the click event propagate only if the mouse moved
-        return (this.start == this.last);
-    },
-
-    /**
-     * Method: activate
-     * Activate the handler.
-     * 
-     * Returns:
-     * {Boolean} The handler was successfully activated.
-     */
-    activate: function() {
-        var activated = false;
-        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            this.dragging = false;
-            activated = true;
-        }
-        return activated;
-    },
-
-    /**
-     * Method: deactivate 
-     * Deactivate the handler.
-     * 
-     * Returns:
-     * {Boolean} The handler was successfully deactivated.
-     */
-    deactivate: function() {
-        var deactivated = false;
-        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.started = false;
-            this.dragging = false;
-            this.start = null;
-            this.last = null;
-            deactivated = true;
-        }
-        return deactivated;
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.Drag"
-});
-/* ======================================================================
-    OpenLayers/Handler/MouseWheel.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- *
- * Class: OpenLayers.Handler.MouseWheel
- * Handler for wheel up/down events.
- * 
- * Inherits from:
- *  - <OpenLayers.Handler>
- */
-OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
-    /** 
-     * Property: wheelListener 
-     * {function} 
-     */
-    wheelListener: null,
-
-    /** 
-     * Property: mousePosition
-     * {<OpenLayers.Pixel>} mousePosition is necessary because
-     * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
-     * value from the last mousemove.
-     */
-    mousePosition: null,
-
-    /**
-     * Constructor: OpenLayers.Handler.MouseWheel
-     *
-     * Parameters:
-     * control - {<OpenLayers.Control>} 
-     * callbacks - {Object} An object containing a single function to be
-     *                          called when the drag operation is finished.
-     *                          The callback should expect to recieve a single
-     *                          argument, the point geometry.
-     * options - {Object} 
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-        this.wheelListener = OpenLayers.Function.bindAsEventListener(
-            this.onWheelEvent, this
-        );
-    },
-
-    /**
-     * Method: destroy
-     */    
-    destroy: function() {
-        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
-        this.wheelListener = null;
-    },
-
-    /**
-     *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
-     */
-
-    /** 
-     * Method: onWheelEvent
-     * Catch the wheel event and handle it xbrowserly
-     * 
-     * Parameters:
-     * e - {Event} 
-     */
-    onWheelEvent: function(e){
-        // first check keyboard modifiers
-        if (!this.checkModifiers(e)) return;
-
-        // first determine whether or not the wheeling was inside the map
-        var inMap = false;
-        var elem = OpenLayers.Event.element(e);
-        while(elem != null) {
-            if (this.map && elem == this.map.div) {
-                inMap = true;
-                break;
-            }
-            elem = elem.parentNode;
-        }
-        
-        if (inMap) {
-            var delta = 0;
-            if (!e) {
-                e = window.event;
-            }
-            if (e.wheelDelta) {
-                delta = e.wheelDelta/120; 
-                if (window.opera) {
-                    delta = -delta;
-                }
-            } else if (e.detail) {
-                delta = -e.detail / 3;
-            }
-            if (delta) {
-                // add the mouse position to the event because mozilla has a bug
-                // with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
-                // getLonLatFromViewPortPx(e) returns wrong values
-                if (this.mousePosition) {
-                    e.xy = this.mousePosition;
-                } 
-                if (!e.xy) {
-                    // If the mouse hasn't moved over the map yet, then
-                    // we don't have a mouse position (in FF), so we just
-                    // act as if the mouse was at the center of the map.
-                    // Note that we can tell we are in the map -- and 
-                    // this.map is ensured to be true above.
-                    e.xy = this.map.getPixelFromLonLat(this.map.getCenter());
-                }
-                if (delta < 0) {
-                   this.callback("down", [e, delta]);
-                } else {
-                   this.callback("up", [e, delta]);
-                }
-            }
-            
-            //only wheel the map, not the window
-            OpenLayers.Event.stop(e);
-        }
-    },
-
-    /**
-     * Method: mousemove
-     * Update the stored mousePosition on every move.
-     * 
-     * Parameters:
-     * evt - {Event} The browser event
-     *
-     * Returns: 
-     * {Boolean} Allow event propagation
-     */
-    mousemove: function (evt) {
-        this.mousePosition = evt.xy;
-    },
-
-    /**
-     * Method: activate 
-     */
-    activate: function (evt) {
-        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            //register mousewheel events specifically on the window and document
-            var wheelListener = this.wheelListener;
-            OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
-            OpenLayers.Event.observe(window, "mousewheel", wheelListener);
-            OpenLayers.Event.observe(document, "mousewheel", wheelListener);
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    /**
-     * Method: deactivate 
-     */
-    deactivate: function (evt) {
-        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            // unregister mousewheel events specifically on the window and document
-            var wheelListener = this.wheelListener;
-            OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
-            OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
-            OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.MouseWheel"
-});
-/* ======================================================================
-    OpenLayers/Layer.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Map.js
- * 
- * Class: OpenLayers.Layer
- */
-OpenLayers.Layer = OpenLayers.Class({
-
-    /**
-     * APIProperty: id
-     * {String}
-     */
-    id: null,
-
-    /** 
-     * APIProperty: name
-     * {String}
-     */
-    name: null,
-
-    /** 
-     * APIProperty: div
-     * {DOMElement}
-     */
-    div: null,
-
-    /** 
-     * Constant: EVENT_TYPES
-     * {Array(String)} Supported application event types
-     */
-    EVENT_TYPES: [ "loadstart", "loadend", "loadcancel", "visibilitychanged"],
-        
-    /**
-     * APIProperty: events``
-     * {<OpenLayers.Events>}
-     */
-    events: null,
-
-    /**
-     * APIProperty: map
-     * {<OpenLayers.Map>} This variable is set when the layer is added to 
-     *     the map, via the accessor function setMap().
-     */
-    map: null,
-    
-    /**
-     * APIProperty: isBaseLayer
-     * {Boolean} Whether or not the layer is a base layer. This should be set 
-     *     individually by all subclasses. Default is false
-     */
-    isBaseLayer: false,
- 
-    /**
-     * Property: alpha
-     * {Boolean} The layer's images have an alpha channel.  Default is false. 
-     */
-    alpha: false,
-
-    /** 
-     * APIProperty: displayInLayerSwitcher
-     * {Boolean} Display the layer's name in the layer switcher.  Default is
-     *     true.
-     */
-    displayInLayerSwitcher: true,
-
-    /**
-     * APIProperty: visibility
-     * {Boolean} The layer should be displayed in the map.  Default is true.
-     */
-    visibility: true,
-
-    /**
-     * APIProperty: attribution
-     * {String} Attribution string, displayed when an 
-     *     <OpenLayers.Control.Attribution> has been added to the map.
-     */
-    attribution: null, 
-
-    /** 
-     * Property: inRange
-     * {Boolean} The current map resolution is within the layer's min/max 
-     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom 
-     *     changes.
-     */
-    inRange: false,
-    
-    /**
-     * Propery: imageSize
-     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than 
-     *     the tile by twice the gutter in each dimension.
-     */
-    imageSize: null,
-    
-    /**
-     * Property: imageOffset
-     * {<OpenLayers.Pixel>} For layers with a gutter, the image offset 
-     *     represents displacement due to the gutter.
-     */
-    imageOffset: null,
-
-  // OPTIONS
-
-    /** 
-     * Property: options
-     * {Object} An optional object whose properties will be set on the layer.
-     *     Any of the layer properties can be set as a property of the options
-     *     object and sent to the constructor when the layer is created.
-     */
-    options: null,
-
-    /**
-     * APIProperty: gutter
-     * {Integer} Determines the width (in pixels) of the gutter around image
-     *     tiles to ignore.  By setting this property to a non-zero value,
-     *     images will be requested that are wider and taller than the tile
-     *     size by a value of 2 x gutter.  This allows artifacts of rendering
-     *     at tile edges to be ignored.  Set a gutter value that is equal to
-     *     half the size of the widest symbol that needs to be displayed.
-     *     Defaults to zero.  Non-tiled layers always have zero gutter.
-     */ 
-    gutter: 0, 
-
-    /**
-     * APIProperty: projection
-     * {String} Set in the layer options to override the default projection
-     *     string this layer - also set maxExtent, maxResolution, and units if
-     *     appropriate.
-     */
-    projection: null,    
-    
-    /**
-     * APIProperty: units
-     * {String} The layer map units.  Defaults to 'degrees'.  Possible values
-     *     are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
-     */
-    units: null,
-
-    /**
-     * APIProperty: scales
-     * {Array}  An array of map scales in descending order.  The values in the
-     *     array correspond to the map scale denominator.  Note that these
-     *     values only make sense if the display (monitor) resolution of the
-     *     client is correctly guessed by whomever is configuring the
-     *     application.  In addition, the units property must also be set.
-     *     Use <resolutions> instead wherever possible.
-     */
-    scales: null,
-
-    /**
-     * APIProperty: resolutions
-     * {Array} A list of map resolutions (map units per pixel) in descending
-     *     order.  If this is not set in the layer constructor, it will be set
-     *     based on other resolution related properties (maxExtent,
-     *     maxResolution, maxScale, etc.).
-     */
-    resolutions: null,
-    
-    /**
-     * APIProperty: maxExtent
-     * {<OpenLayers.Bounds>}  The center of these bounds will not stray outside
-     *     of the viewport extent during panning.  In addition, if
-     *     <displayOutsideMaxExtent> is set to false, data will not be
-     *     requested that falls completely outside of these bounds.
-     */
-    maxExtent: null,
-    
-    /**
-     * APIProperty: minExtent
-     * {<OpenLayers.Bounds>}
-     */
-    minExtent: null,
-    
-    /**
-     * APIProperty: maxResolution
-     * {Float} Default max is 360 deg / 256 px, which corresponds to
-     *     zoom level 0 on gmaps.  Specify a different value in the layer 
-     *     options if you are not using a geographic projection and 
-     *     displaying the whole world.
-     */
-    maxResolution: null,
-
-    /**
-     * APIProperty: minResolution
-     * {Float}
-     */
-    minResolution: null,
-
-    /**
-     * APIProperty: numZoomLevels
-     * {Integer}
-     */
-    numZoomLevels: null,
-   
-    /**
-     * APIProperty: minScale
-     * {Float}
-     */
-    minScale: null,
-    
-    /**
-     * APIProperty: maxScale
-     * {Float}
-     */
-    maxScale: null,
-
-    /**
-     * APIProperty: displayOutsideMaxExtent
-     * {Boolean} Request map tiles that are completely outside of the max 
-     *     extent for this layer. Defaults to false.
-     */
-    displayOutsideMaxExtent: false,
-
-    /**
-     * APIProperty: wrapDateLine
-     * {Boolean} #487 for more info.   
-     */
-    wrapDateLine: false,
-    
-    
-    /**
-     * Constructor: OpenLayers.Layer
-     *
-     * Parameters:
-     * name - {String} The layer name
-     * options - {Object} Hashtable of extra options to tag onto the layer
-     */
-    initialize: function(name, options) {
-
-        this.addOptions(options);
-
-        this.name = name;
-        
-        if (this.id == null) {
-
-            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-
-            this.div = OpenLayers.Util.createDiv();
-            this.div.style.width = "100%";
-            this.div.style.height = "100%";
-            this.div.id = this.id;
-
-            this.events = new OpenLayers.Events(this, this.div, 
-                                                this.EVENT_TYPES);
-        }
-
-        if (this.wrapDateLine) {
-            this.displayOutsideMaxExtent = true;
-        }
-    },
-    
-    /**
-     * Method: destroy
-     * Destroy is a destructor: this is to alleviate cyclic references which
-     *     the Javascript garbage cleaner can not take care of on its own.
-     *
-     * Parameters:
-     * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
-     *     been destroyed.  Default is true.
-     */
-    destroy: function(setNewBaseLayer) {
-        if (setNewBaseLayer == null) {
-            setNewBaseLayer = true;
-        }
-        if (this.map != null) {
-            this.map.removeLayer(this, setNewBaseLayer);
-        }
-        this.map = null;
-        this.name = null;
-        this.div = null;
-        this.options = null;
-
-        if (this.events) {
-            this.events.destroy();
-        }
-        this.events = null;
-    },
-    
-   /**
-    * Method: clone
-    *
-    * Parameters:
-    * obj - {<OpenLayers.Layer>} The layer to be cloned
-    *
-    * Returns:
-    * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
-    */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer(this.name, this.options);
-        } 
-        
-        // catch any randomly tagged-on properties
-        OpenLayers.Util.applyDefaults(obj, this);
-        
-        // a cloned layer should never have its map property set
-        //  because it has not been added to a map yet. 
-        obj.map = null;
-        
-        return obj;
-    },
-    
-    /** 
-     * APIMethod: setName
-     * Sets the new layer name for this layer.  Can trigger a changelayer event
-     *     on the map.
-     *
-     * Parameters:
-     * newName - {String} The new name.
-     */
-    setName: function(newName) {
-        if (newName != this.name) {
-            this.name = newName;
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer");
-            }
-        }
-    },    
-    
-   /**
-    * APIMethod: addOptions
-    * 
-    * Parameters:
-    * newOptions - {Object}
-    */
-    addOptions: function (newOptions) {
-        
-        if (this.options == null) {
-            this.options = {};
-        }
-        
-        // update our copy for clone
-        OpenLayers.Util.extend(this.options, newOptions);
-
-        // add new options to this
-        OpenLayers.Util.extend(this, newOptions);
-    },
-    
-    /**
-     * APIMethod: onMapResize
-     * This function can be implemented by subclasses
-     */
-    onMapResize: function() {
-        //this function can be implemented by subclasses  
-    },
-
-    /**
-     * APIMethod: redraw
-     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
-     *
-     * Returns:
-     * {Boolean} The layer was redrawn.
-     */
-    redraw: function() {
-        var redrawn = false;
-        if (this.map) {
-
-            // min/max Range may have changed
-            this.inRange = this.calculateInRange();
-
-            // map's center might not yet be set
-            var extent = this.getExtent();
-
-            if (extent && this.inRange && this.visibility) {
-                this.moveTo(extent, true, false);
-                redrawn = true;
-            }
-        }
-        return redrawn;
-    },
-
-    /**
-     * Method: moveTo
-     * 
-     * Parameters:
-     * bound - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
-     *     do some init work in that case.
-     * dragging - {Boolean}
-     */
-    moveTo:function(bounds, zoomChanged, dragging) {
-        var display = this.visibility;
-        if (!this.isBaseLayer) {
-            display = display && this.inRange;
-        }
-        this.display(display);
-    },
-
-    /**
-     * Method: setMap
-     * Set the map property for the layer. This is done through an accessor
-     *     so that subclasses can override this and take special action once 
-     *     they have their map variable set. 
-     * 
-     *     Here we take care to bring over any of the necessary default 
-     *     properties from the map. 
-     * 
-     * Parameters:
-     * map - {<OpenLayers.Map>}
-     */
-    setMap: function(map) {
-        if (this.map == null) {
-        
-            this.map = map;
-            
-            // grab some essential layer data from the map if it hasn't already
-            //  been set
-            this.maxExtent = this.maxExtent || this.map.maxExtent;
-            this.projection = this.projection || this.map.projection;
-            
-            if (this.projection && typeof this.projection == "string") {
-                this.projection = new OpenLayers.Projection(this.projection);
-            }
-            
-            // Check the projection to see if we can get units -- if not, refer
-            // to properties.
-            this.units = this.projection.getUnits() ||
-                         this.units || this.map.units;
-            
-            this.initResolutions();
-            
-            if (!this.isBaseLayer) {
-                this.inRange = this.calculateInRange();
-                var show = ((this.visibility) && (this.inRange));
-                this.div.style.display = show ? "" : "none";
-            }
-            
-            // deal with gutters
-            this.setTileSize();
-        }
-    },
-    
-    /**
-     * APIMethod: removeMap
-     * Just as setMap() allows each layer the possibility to take a 
-     *     personalized action on being added to the map, removeMap() allows
-     *     each layer to take a personalized action on being removed from it. 
-     *     For now, this will be mostly unused, except for the EventPane layer,
-     *     which needs this hook so that it can remove the special invisible
-     *     pane. 
-     * 
-     * Parameters:
-     * map - {<OpenLayers.Map>}
-     */
-    removeMap: function(map) {
-        //to be overridden by subclasses
-    },
-    
-    /**
-     * APIMethod: getImageSize
-     * 
-     * Returns:
-     * {<OpenLayers.Size>} The size that the image should be, taking into 
-     *     account gutters.
-     */ 
-    getImageSize: function() { 
-        return (this.imageSize || this.tileSize); 
-    },    
-  
-    /**
-     * APIMethod: setTileSize
-     * Set the tile size based on the map size.  This also sets layer.imageSize
-     *     and layer.imageOffset for use by Tile.Image.
-     * 
-     * Parameters:
-     * size - {<OpenLayers.Size>}
-     */
-    setTileSize: function(size) {
-        var tileSize = (size) ? size :
-                                ((this.tileSize) ? this.tileSize :
-                                                   this.map.getTileSize());
-        this.tileSize = tileSize;
-        if(this.gutter) {
-          // layers with gutters need non-null tile sizes
-          //if(tileSize == null) {
-          //    OpenLayers.console.error("Error in layer.setMap() for " +
-          //                              this.name + ": layers with " +
-          //                              "gutters need non-null tile sizes");
-          //}
-            this.imageOffset = new OpenLayers.Pixel(-this.gutter, 
-                                                    -this.gutter); 
-            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), 
-                                                 tileSize.h + (2*this.gutter)); 
-        }
-    },
-
-    /**
-     * APIMethod: getVisibility
-     * 
-     * Returns:
-     * {Boolean} The layer should be displayed (if in range).
-     */
-    getVisibility: function() {
-        return this.visibility;
-    },
-
-    /** 
-     * APIMethod: setVisibility
-     * Set the visibility flag for the layer and hide/show & redraw 
-     *     accordingly. Fire event unless otherwise specified
-     * 
-     * Note that visibility is no longer simply whether or not the layer's
-     *     style.display is set to "block". Now we store a 'visibility' state 
-     *     property on the layer class, this allows us to remember whether or 
-     *     not we *desire* for a layer to be visible. In the case where the 
-     *     map's resolution is out of the layer's range, this desire may be 
-     *     subverted.
-     * 
-     * Parameters:
-     * visible - {Boolean} Whether or not to display the layer (if in range)
-     */
-    setVisibility: function(visibility) {
-        if (visibility != this.visibility) {
-            this.visibility = visibility;
-            this.display(visibility);
-            this.redraw();
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer");
-            }
-            this.events.triggerEvent("visibilitychanged");
-        }
-    },
-
-    /** 
-     * APIMethod: display
-     * Hide or show the Layer
-     * 
-     * Parameters:
-     * display - {Boolean}
-     */
-    display: function(display) {
-        if (display != (this.div.style.display != "none")) {
-            this.div.style.display = (display) ? "block" : "none";
-        }
-    },
-
-    /**
-     * Method: calculateInRange
-     * 
-     * Returns:
-     * {Boolean} The layer is displayable at the current map's current
-     *     resolution.
-     */
-    calculateInRange: function() {
-        var inRange = false;
-        if (this.map) {
-            var resolution = this.map.getResolution();
-            inRange = ( (resolution >= this.minResolution) &&
-                        (resolution <= this.maxResolution) );
-        }
-        return inRange;
-    },
-
-    /** 
-     * APIMethod: setIsBaseLayer
-     * 
-     * Parameters:
-     * isBaseLayer - {Boolean}
-     */
-    setIsBaseLayer: function(isBaseLayer) {
-        if (isBaseLayer != this.isBaseLayer) {
-            this.isBaseLayer = isBaseLayer;
-            if (this.map != null) {
-                this.map.events.triggerEvent("changelayer");
-            }
-        }
-    },
-
-  /********************************************************/
-  /*                                                      */
-  /*                 Baselayer Functions                  */
-  /*                                                      */
-  /********************************************************/
-  
-    /** 
-     * Method: initResolutions
-     * This method's responsibility is to set up the 'resolutions' array 
-     *     for the layer -- this array is what the layer will use to interface
-     *     between the zoom levels of the map and the resolution display 
-     *     of the layer.
-     * 
-     * The user has several options that determine how the array is set up.
-     *  
-     * For a detailed explanation, see the following wiki from the 
-     *     openlayers.org homepage:
-     *     http://trac.openlayers.org/wiki/SettingZoomLevels
-     */
-    initResolutions: function() {
-
-        // These are the relevant options which are used for calculating 
-        //  resolutions information.
-        //
-        var props = new Array(
-          'projection', 'units',
-          'scales', 'resolutions',
-          'maxScale', 'minScale', 
-          'maxResolution', 'minResolution', 
-          'minExtent', 'maxExtent',
-          'numZoomLevels', 'maxZoomLevel'
-        );
-
-        // First we create a new object where we will store all of the 
-        //  resolution-related properties that we find in either the layer's
-        //  'options' array or from the map.
-        //
-        var confProps = {};        
-        for(var i=0; i < props.length; i++) {
-            var property = props[i];
-            confProps[property] = this.options[property] || this.map[property];
-        }
-        
-        // If numZoomLevels hasn't been set and the maxZoomLevel *has*, 
-        //  then use maxZoomLevel to calculate numZoomLevels
-        //
-        if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
-            confProps.numZoomLevels = confProps.maxZoomLevel + 1;
-        }
-
-        // First off, we take whatever hodge-podge of values we have and 
-        //  calculate/distill them down into a resolutions[] array
-        //
-        if ((confProps.scales != null) || (confProps.resolutions != null)) {
-          //preset levels
-            if (confProps.scales != null) {
-                confProps.resolutions = [];
-                for(var i = 0; i < confProps.scales.length; i++) {
-                    var scale = confProps.scales[i];
-                    confProps.resolutions[i] = 
-                       OpenLayers.Util.getResolutionFromScale(scale, 
-                                                              confProps.units);
-                }
-            }
-            confProps.numZoomLevels = confProps.resolutions.length;
-
-        } else {
-          //maxResolution and numZoomLevels based calculation
-            
-            confProps.resolutions = [];
-            
-            // determine maxResolution
-            if (confProps.minScale) {
-                confProps.maxResolution = 
-                    OpenLayers.Util.getResolutionFromScale(confProps.minScale, 
-                                                           confProps.units);
-            } else if (confProps.maxResolution == "auto") {
-                var viewSize = this.map.getSize();
-                var wRes = confProps.maxExtent.getWidth() / viewSize.w;
-                var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
-                confProps.maxResolution = Math.max(wRes, hRes);
-            } 
-
-            // determine minResolution
-            if (confProps.maxScale != null) {           
-                confProps.minResolution = 
-                    OpenLayers.Util.getResolutionFromScale(confProps.maxScale);
-            } else if ( (confProps.minResolution == "auto") && 
-                        (confProps.minExtent != null) ) {
-                var viewSize = this.map.getSize();
-                var wRes = confProps.minExtent.getWidth() / viewSize.w;
-                var hRes = confProps.minExtent.getHeight()/ viewSize.h;
-                confProps.minResolution = Math.max(wRes, hRes);
-            } 
-
-            // determine numZoomLevels
-            if (confProps.minResolution != null) {
-                var ratio = confProps.maxResolution / confProps.minResolution;
-                confProps.numZoomLevels = 
-                    Math.floor(Math.log(ratio) / Math.log(2)) + 1;
-            }
-            
-            // now we have numZoomLevels and maxResolution, 
-            //  we can populate the resolutions array
-            for (var i=0; i < confProps.numZoomLevels; i++) {
-                var res = confProps.maxResolution / Math.pow(2, i)
-                confProps.resolutions.push(res);
-            }    
-        }
-        
-        //sort resolutions array ascendingly
-        //
-        confProps.resolutions.sort( function(a, b) { return(b-a); } );
-
-        // now set our newly calculated values back to the layer 
-        //  Note: We specifically do *not* set them to layer.options, which we 
-        //        will preserve as it was when we added this layer to the map. 
-        //        this way cloned layers reset themselves to new map div 
-        //        dimensions)
-        //
-
-        this.resolutions = confProps.resolutions;
-        this.maxResolution = confProps.resolutions[0];
-        var lastIndex = confProps.resolutions.length - 1;
-        this.minResolution = confProps.resolutions[lastIndex];
-        
-        this.scales = [];
-        for(var i = 0; i < confProps.resolutions.length; i++) {
-            this.scales[i] = 
-               OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i], 
-                                                      confProps.units);
-        }
-        this.minScale = this.scales[0];
-        this.maxScale = this.scales[this.scales.length - 1];
-        
-        this.numZoomLevels = confProps.numZoomLevels;
-    },
-
-    /**
-     * APIMethod: getResolution
-     * 
-     * Returns:
-     * {Float} The currently selected resolution of the map, taken from the
-     *     resolutions array, indexed by current zoom level.
-     */
-    getResolution: function() {
-        var zoom = this.map.getZoom();
-        return this.resolutions[zoom];
-    },
-
-    /** 
-     * APIMethod: getExtent
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
-     *     bounds of the current viewPort.
-     */
-    getExtent: function() {
-        // just use stock map calculateBounds function -- passing no arguments
-        //  means it will user map's current center & resolution
-        //
-        return this.map.calculateBounds();
-    },
-
-    /**
-     * APIMethod: getZoomForExtent
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
-     *     that still contains the passed-in extent. We do this by calculating
-     *     the ideal resolution for the given exteng (based on the map size)
-     *     and then find the closest resolution to this ideal resolution.
-     */
-    getZoomForExtent: function(extent) {
-        var viewSize = this.map.getSize();
-        var idealResolution = Math.max( extent.getWidth()  / viewSize.w,
-                                        extent.getHeight() / viewSize.h );
-
-        return this.getZoomForResolution(idealResolution);
-    },
-    
-    /** 
-     * Method: getDataExtent
-     * Calculates the max extent which includes all of the data for the layer.
-     *     This function is to be implemented by subclasses.
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>}
-     */
-    getDataExtent: function () {
-        //to be implemented by subclasses
-    },
-
-    /**
-     * APIMethod: getZoomForResolution
-     * Get the index for the closest resolution in the layers resolutions array.
-     * 
-     * Parameters:
-     * resolution - {Float} Map units per pixel.
-     * 
-     * Returns:
-     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
-     *     that is the closest to the passed-in resolution.
-     */
-    getZoomForResolution: function(resolution) {
-        var zoom, diff;
-        var minDiff = Number.POSITIVE_INFINITY;
-        for(var i=0; i < this.resolutions.length; i++) {
-            diff = Math.abs(this.resolutions[i] - resolution);
-            if(diff < minDiff) {
-                zoom = i;
-                minDiff = diff;
-            } else if(diff > minDiff) {
-                break;
-            }
-        }
-        return zoom;
-    },
-    
-    /**
-     * APIMethod: getLonLatFromViewPortPx
-     * 
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>}
-     *
-     * Returns:
-     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in 
-     *     view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
-     */
-    getLonLatFromViewPortPx: function (viewPortPx) {
-        var lonlat = null;
-        if (viewPortPx != null) {
-            var size = this.map.getSize();
-            var center = this.map.getCenter();
-            if (center) {
-                var res  = this.map.getResolution();
-        
-                var delta_x = viewPortPx.x - (size.w / 2);
-                var delta_y = viewPortPx.y - (size.h / 2);
-            
-                lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
-                                             center.lat - delta_y * res); 
-
-                if (this.wrapDateLine) {
-                    lonlat = lonlat.wrapDateLine(this.maxExtent);
-                }
-            } // else { DEBUG STATEMENT }
-        }
-        return lonlat;
-    },
-
-    /**
-     * APIMethod: getViewPortPxFromLonLat
-     * 
-     * Parameters:
-     * lonlat - {<OpenLayers.LonLat>}
-     *
-     * Returns: 
-     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in 
-     *     <OpenLayers.LonLat>,translated into view port pixels.
-     */
-    getViewPortPxFromLonLat: function (lonlat) {
-        var px = null; 
-        if (lonlat != null) {
-            var resolution = this.map.getResolution();
-            var extent = this.map.getExtent();
-            px = new OpenLayers.Pixel(
-                Math.round(1/resolution * (lonlat.lon - extent.left)),
-                Math.round(1/resolution * (extent.top - lonlat.lat))
-            );    
-        }
-        return px;
-    },
-    
-    /**
-     * APIMethod: setOpacity
-     * Sets the opacity for the entire layer (all images)
-     * 
-     * Parameter:
-     * opacity - {Float}
-     */
-    setOpacity: function(opacity) {
-        if (opacity != this.opacity) {
-            this.opacity = opacity;
-            for(var i=0; i<this.div.childNodes.length; ++i) {
-                var element = this.div.childNodes[i].firstChild;
-                OpenLayers.Util.modifyDOMElement(element, null, null, null, 
-                                                 null, null, null, opacity);
-            }
-        }
-    },
-
-    /**
-     * Method: setZIndex
-     * 
-     * Parameters: 
-     * zIndex - {Integer}
-     */    
-    setZIndex: function (zIndex) {
-        this.div.style.zIndex = zIndex;
-    },
-
-    /**
-     * Method: adjustBounds
-     * This function will take a bounds, and if wrapDateLine option is set
-     *     on the layer, it will return a bounds which is wrapped around the 
-     *     world. We do not wrap for bounds which *cross* the 
-     *     maxExtent.left/right, only bounds which are entirely to the left 
-     *     or entirely to the right.
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    adjustBounds: function (bounds) {
-
-        if (this.gutter) {
-            // Adjust the extent of a bounds in map units by the 
-            // layer's gutter in pixels.
-            var mapGutter = this.gutter * this.map.getResolution();
-            bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
-                                           bounds.bottom - mapGutter,
-                                           bounds.right + mapGutter,
-                                           bounds.top + mapGutter);
-        }
-
-        if (this.wrapDateLine) {
-            // wrap around the date line, within the limits of rounding error
-            var wrappingOptions = { 
-                'rightTolerance':this.getResolution()
-            };    
-            bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
-                              
-        }
-        return bounds;
-    },
-
-    CLASS_NAME: "OpenLayers.Layer"
-});
-/* ======================================================================
-    OpenLayers/Marker/Box.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Marker.js
- *
- * Class: OpenLayers.Marker.Box
- *
- * Inherits from:
- *  - <OpenLayers.Marker> 
- */
-OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
-
-    /** 
-     * Property: bounds 
-     * {<OpenLayers.Bounds>} 
-     */
-    bounds: null,
-
-    /** 
-     * Property: div 
-     * {DOMElement} 
-     */
-    div: null,
-    
-    /** 
-     * Constructor: OpenLayers.Marker.Box
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>} 
-     * borderColor - {String} 
-     * borderWidth - {int} 
-     */
-    initialize: function(bounds, borderColor, borderWidth) {
-        this.bounds = bounds;
-        this.div    = OpenLayers.Util.createDiv();
-        this.div.style.overflow = 'hidden';
-        this.events = new OpenLayers.Events(this, this.div, null);
-        this.setBorder(borderColor, borderWidth);
-    },
-
-    /**
-     * Method: destroy 
-     */    
-    destroy: function() {
-
-        this.bounds = null;
-        this.div = null;
-
-        OpenLayers.Marker.prototype.destroy.apply(this, arguments);
-    },
-
-    /** 
-     * Method: setBorder
-     * Allow the user to change the box's color and border width
-     * 
-     * Parameters:
-     * color - {String} Default is "red"
-     * width - {int} Default is 2
-     */
-    setBorder: function (color, width) {
-        if (!color) {
-            color = "red";
-        }
-        if (!width) {
-            width = 2;
-        }
-        this.div.style.border = width + "px solid " + color;
-    },
-    
-    /** 
-    * Method: draw
-    * 
-    * Parameters:
-    * px - {<OpenLayers.Pixel>} 
-    * sz - {<OpenLayers.Size>} 
-    * 
-    * Returns: 
-    * {DOMElement} A new DOM Image with this marker´s icon set at the 
-    *         location passed-in
-    */
-    draw: function(px, sz) {
-        OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
-        return this.div;
-    }, 
-
-    /**
-     * Method: onScreen
-     * 
-     * Rreturn:
-     * {Boolean} Whether or not the marker is currently visible on screen.
-     */
-    onScreen:function() {
-        var onScreen = false;
-        if (this.map) {
-            var screenBounds = this.map.getExtent();
-            onScreen = screenBounds.containsBounds(this.bounds, true, true);
-        }    
-        return onScreen;
-    },
-    
-    /**
-     * Method: display
-     * Hide or show the icon
-     * 
-     * Parameters:
-     * display - {Boolean} 
-     */
-    display: function(display) {
-        this.div.style.display = (display) ? "" : "none";
-    },
-
-    CLASS_NAME: "OpenLayers.Marker.Box"
-});
-
-/* ======================================================================
-    OpenLayers/Control/DragPan.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- *
- * Class: OpenLayers.Control.DragPan
- * DragPan control.
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
-
-    /** 
-     * Property: type
-     * {OpenLayers.Control.TYPES}
-     */
-    type: OpenLayers.Control.TYPE_TOOL,
-    
-    /**
-     * Property: panned
-     * {Boolean} The map moved.
-     */
-    panned: false,
-    
-    /**
-     * Method: draw
-     * Creates a Drag handler, using <OpenLayers.Control.PanMap.panMap> and
-     * <OpenLayers.Control.PanMap.panMapDone> as callbacks.
-     */    
-    draw: function() {
-        this.handler = new OpenLayers.Handler.Drag(this,
-                            {"move": this.panMap, "done": this.panMapDone});
-    },
-
-    /**
-    * Method: panMap
-    *
-    * Parameters:
-    * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
-    */
-    panMap: function(xy) {
-        this.panned = true;
-        var deltaX = this.handler.last.x - xy.x;
-        var deltaY = this.handler.last.y - xy.y;
-        var size = this.map.getSize();
-        var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
-                                         size.h / 2 + deltaY);
-        var newCenter = this.map.getLonLatFromViewPortPx( newXY );
-        this.map.setCenter(newCenter, null, this.handler.dragging);
-    },
-    
-    /**
-     * Method: panMapDone
-     * Finish the panning operation.  Only call setCenter (through <panMap>)
-     *     if the map has actually been moved.
-     *
-     * Parameters:
-     * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
-     */
-    panMapDone: function(xy) {
-        if(this.panned) {
-            this.panMap(xy);
-            this.panned = false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Control.DragPan"
-});
-/* ======================================================================
-    OpenLayers/Handler/Box.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Handler/Drag.js
- * 
- * Class: OpenLayers.Handler.Box
- * Handler for dragging a rectangle across the map.  Box is displayed 
- * on mouse down, moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- *  - <OpenLayers.Handler> 
- */
-OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
-
-    /** 
-     * Property: dragHandler 
-     * {<OpenLayers.Handler.Drag>} 
-     */
-    dragHandler: null,
-
-    /**
-     * Constructor: OpenLayers.Handler.Box
-     *
-     * Parameters:
-     * control - {<OpenLayers.Control>} 
-     * callbacks - {Object} An object containing a single function to be
-     *                          called when the drag operation is finished.
-     *                          The callback should expect to recieve a single
-     *                          argument, the point geometry.
-     * options - {Object} 
-     */
-    initialize: function(control, callbacks, options) {
-        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-        var callbacks = {
-            "down": this.startBox, 
-            "move": this.moveBox, 
-            "out":  this.removeBox,
-            "up":   this.endBox
-        };
-        this.dragHandler = new OpenLayers.Handler.Drag(
-                                this, callbacks, {keyMask: this.keyMask});
-    },
-
-    /**
-     * Method: setMap
-     */
-    setMap: function (map) {
-        OpenLayers.Handler.prototype.setMap.apply(this, arguments);
-        if (this.dragHandler) {
-            this.dragHandler.setMap(map);
-        }
-    },
-
-    /**
-    * Method: startBox
-    *
-    * Parameters:
-    * evt - {Event} 
-    */
-    startBox: function (xy) {
-        this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
-                                                 this.dragHandler.start,
-                                                 null,
-                                                 null,
-                                                 "absolute",
-                                                 "2px solid red");
-        this.zoomBox.style.backgroundColor = "white";
-        this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
-        this.zoomBox.style.opacity = "0.50";
-        this.zoomBox.style.fontSize = "1px";
-        this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
-        this.map.viewPortDiv.appendChild(this.zoomBox);
-
-        // TBD: use CSS classes instead
-        this.map.div.style.cursor = "crosshair";
-    },
-
-    /**
-    * Method: moveBox
-    */
-    moveBox: function (xy) {
-        var deltaX = Math.abs(this.dragHandler.start.x - xy.x);
-        var deltaY = Math.abs(this.dragHandler.start.y - xy.y);
-        this.zoomBox.style.width = Math.max(1, deltaX) + "px";
-        this.zoomBox.style.height = Math.max(1, deltaY) + "px";
-        if (xy.x < this.dragHandler.start.x) {
-            this.zoomBox.style.left = xy.x+"px";
-        }
-        if (xy.y < this.dragHandler.start.y) {
-            this.zoomBox.style.top = xy.y+"px";
-        }
-    },
-
-    /**
-    * Method: endBox
-    */
-    endBox: function(end) {
-        var result;
-        if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||    
-            Math.abs(this.dragHandler.start.y - end.y) > 5) {   
-            var start = this.dragHandler.start;
-            var top = Math.min(start.y, end.y);
-            var bottom = Math.max(start.y, end.y);
-            var left = Math.min(start.x, end.x);
-            var right = Math.max(start.x, end.x);
-            result = new OpenLayers.Bounds(left, bottom, right, top);
-        } else {
-            result = this.dragHandler.start.clone(); // i.e. OL.Pixel
-        } 
-        this.removeBox();
-
-        // TBD: use CSS classes instead
-        this.map.div.style.cursor = "";
-
-        this.callback("done", [result]);
-    },
-
-    /**
-     * Method: removeBox
-     * Remove the zoombox from the screen and nullify our reference to it.
-     */
-    removeBox: function() {
-        this.map.viewPortDiv.removeChild(this.zoomBox);
-        this.zoomBox = null;
-    },
-
-    /**
-     * Method: activate
-     */
-    activate: function () {
-        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
-            this.dragHandler.activate();
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    /**
-     * Method: deactivate
-     */
-    deactivate: function () {
-        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
-            this.dragHandler.deactivate();
-            return true;
-        } else {
-            return false;
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Handler.Box"
-});
-/* ======================================================================
-    OpenLayers/Layer/HTTPRequest.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- * 
- * Class: OpenLayers.Layer.HTTPRequest
- * 
- * Inherits from: 
- *  - <OpenLayers.Layer>
- */
-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
-
-    /** 
-     * Constant: URL_HASH_FACTOR
-     * {Float} Used to hash URL param strings for multi-WMS server selection.
-     *         Set to the Golden Ratio per Knuth's recommendation.
-     */
-    URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
-
-    /** 
-     * Property: url
-     * {Array(String) or String} This is either an array of url strings or 
-     *                           a single url string. 
-     */
-    url: null,
-
-    /** 
-     * Property: params
-     * {Object} Hashtable of key/value parameters
-     */
-    params: null,
-    
-    /** 
-     * APIProperty: reproject
-     * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
-     * for information on the replacement for this functionality. 
-     * {Boolean} Whether layer should reproject itself based on base layer 
-     *           locations. This allows reprojection onto commercial layers. 
-     *           Default is false: Most layers can't reproject, but layers 
-     *           which can create non-square geographic pixels can, like WMS.
-     *           
-     */
-    reproject: false,
-
-    /**
-     * Constructor: OpenLayers.Layer.HTTPRequest
-     * 
-     * Parameters:
-     * name - {String}
-     * url - {Array(String) or String}
-     * params - {Object}
-     * options - {Object} Hashtable of extra options to tag onto the layer
-     */
-    initialize: function(name, url, params, options) {
-        var newArguments = arguments;
-        newArguments = [name, options];
-        OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
-        this.url = url;
-        this.params = OpenLayers.Util.extend( {}, params);
-    },
-
-    /**
-     * APIMethod: destroy
-     */
-    destroy: function() {
-        this.url = null;
-        this.params = null;
-        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
-    },
-    
-    /**
-     * APIMethod: clone
-     * 
-     * Parameters:
-     * obj - {Object}
-     * 
-     * Returns:
-     * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this 
-     *                                  <OpenLayers.Layer.HTTPRequest>
-     */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer.HTTPRequest(this.name,
-                                                   this.url,
-                                                   this.params,
-                                                   this.options);
-        }
-        
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
-
-        // copy/set any non-init, non-simple values here
-        
-        return obj;
-    },
-
-    /** 
-     * APIMethod: setUrl
-     * 
-     * Parameters:
-     * newUrl - {String}
-     */
-    setUrl: function(newUrl) {
-        this.url = newUrl;
-    },
-
-    /**
-     * APIMethod: mergeNewParams
-     * 
-     * Parameters:
-     * newParams - {Object}
-     */
-    mergeNewParams:function(newParams) {
-        this.params = OpenLayers.Util.extend(this.params, newParams);
-        this.redraw();
-    },
-    
-    /**
-     * Method: selectUrl
-     * selectUrl() implements the standard floating-point multiplicative
-     *     hash function described by Knuth, and hashes the contents of the 
-     *     given param string into a float between 0 and 1. This float is then
-     *     scaled to the size of the provided urls array, and used to select
-     *     a URL.
-     *
-     * Parameters:
-     * paramString - {String}
-     * urls - {Array(String)}
-     * 
-     * Returns:
-     * {String} An entry from the urls array, deterministically selected based
-     *          on the paramString.
-     */
-    selectUrl: function(paramString, urls) {
-        var product = 1;
-        for (var i = 0; i < paramString.length; i++) { 
-            product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR; 
-            product -= Math.floor(product); 
-        }
-        return urls[Math.floor(product * urls.length)];
-    },
-
-    /** 
-     * Method: getFullRequestString
-     * Combine url with layer's params and these newParams. 
-     *   
-     *    does checking on the serverPath variable, allowing for cases when it 
-     *     is supplied with trailing ? or &, as well as cases where not. 
-     *
-     *    return in formatted string like this:
-     *        "server?key1=value1&key2=value2&key3=value3"
-     * 
-     * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
-     *
-     * Parameters:
-     * newParams - {Object}
-     * altUrl - {String} Use this as the url instead of the layer's url
-     *   
-     * Returns: 
-     * {String}
-     */
-    getFullRequestString:function(newParams, altUrl) {
-
-        // if not altUrl passed in, use layer's url
-        var url = altUrl || this.url;
-        
-        // create a new params hashtable with all the layer params and the 
-        // new params together. then convert to string
-        var allParams = OpenLayers.Util.extend({}, this.params);
-        allParams = OpenLayers.Util.extend(allParams, newParams);
-        var paramsString = OpenLayers.Util.getParameterString(allParams);
-        
-        // if url is not a string, it should be an array of strings, 
-        // in which case we will deterministically select one of them in 
-        // order to evenly distribute requests to different urls.
-        //
-        if (url instanceof Array) {
-            url = this.selectUrl(paramsString, url);
-        }   
- 
-        // ignore parameters that are already in the url search string
-        var urlParams = 
-            OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
-        for(var key in allParams) {
-            if(key.toUpperCase() in urlParams) {
-                delete allParams[key];
-            }
-        }
-        paramsString = OpenLayers.Util.getParameterString(allParams);
-        
-        // requestString always starts with url
-        var requestString = url;        
-        
-        if (paramsString != "") {
-            var lastServerChar = url.charAt(url.length - 1);
-            if ((lastServerChar == "&") || (lastServerChar == "?")) {
-                requestString += paramsString;
-            } else {
-                if (url.indexOf('?') == -1) {
-                    //serverPath has no ? -- add one
-                    requestString += '?' + paramsString;
-                } else {
-                    //serverPath contains ?, so must already have 
-                    // paramsString at the end
-                    requestString += '&' + paramsString;
-                }
-            }
-        }
-        return requestString;
-    },
-
-    CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
-});
-/* ======================================================================
-    OpenLayers/Control/ZoomBox.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Box.js
- *
- * Class: OpenLayers.Control.ZoomBox
- *
- * Inherits from:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
-    /**
-     * Property: type
-     * {OpenLayers.Control.TYPE}
-     */
-    type: OpenLayers.Control.TYPE_TOOL,
-
-    /**
-     * Method: draw
-     */    
-    draw: function() {
-        this.handler = new OpenLayers.Handler.Box( this,
-                            {done: this.zoomBox}, {keyMask: this.keyMask} );
-    },
-
-    /**
-     * Method: zoomBox
-     *
-     * Parameters:
-     * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
-     */
-    zoomBox: function (position) {
-        if (position instanceof OpenLayers.Bounds) {
-            var minXY = this.map.getLonLatFromPixel(
-                            new OpenLayers.Pixel(position.left, position.bottom));
-            var maxXY = this.map.getLonLatFromPixel(
-                            new OpenLayers.Pixel(position.right, position.top));
-            var bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
-                                               maxXY.lon, maxXY.lat);
-            this.map.zoomToExtent(bounds);
-        } else { // it's a pixel
-            this.map.setCenter(this.map.getLonLatFromPixel(position),
-                               this.map.getZoom() + 1);
-        }
-    },
-
-    CLASS_NAME: "OpenLayers.Control.ZoomBox"
-});
-/* ======================================================================
-    OpenLayers/Layer/Grid.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/HTTPRequest.js
- * 
- * Class: OpenLayers.Layer.Grid
- * Base class for layers that use a lattice of tiles.  Create a new grid
- * layer with the <OpenLayers.Layer.Grid> constructor.
- *
- * Inherits from:
- *  - <OpenLayers.Layer.HTTPRequest>
- */
-OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
-    
-    /**
-     * APIProperty: tileSize
-     * {<OpenLayers.Size>}
-     */
-    tileSize: null,
-    
-    /**
-     * Property: grid
-     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is 
-     *     an array of tiles.
-     */
-    grid: null,
-
-    /**
-     * APIProperty: singleTile
-     * {Boolean} Moves the layer into single-tile mode, meaning that one tile 
-     *     will be loaded. The tile's size will be determined by the 'ratio'
-     *     property. When the tile is dragged such that it does not cover the 
-     *     entire viewport, it is reloaded.
-     */
-    singleTile: false,
-
-    /** APIProperty: ratio
-     *  {Float} Used only when in single-tile mode, this specifies the 
-     *          ratio of the size of the single tile to the size of the map.
-     */
-    ratio: 1.5,
-
-    /**
-     * APIProperty: buffer
-     * {Integer} Used only when in gridded mode, this specifies the number of 
-     *           extra rows and colums of tiles on each side which will
-     *           surround the minimum grid tiles to cover the map.
-     */
-    buffer: 2,
-
-    /**
-     * APIProperty: numLoadingTiles
-     * {Integer} How many tiles are still loading?
-     */
-    numLoadingTiles: 0,
-
-    /**
-     * Constructor: OpenLayers.Layer.Grid
-     * Create a new grid layer
-     *
-     * Parameters:
-     * name - {String}
-     * url - {String}
-     * params - {Object}
-     * options - {Object} Hashtable of extra options to tag onto the layer
-     */
-    initialize: function(name, url, params, options) {
-        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, 
-                                                                arguments);
-        
-        //grid layers will trigger 'tileloaded' when each new tile is 
-        // loaded, as a means of progress update to listeners.
-        // listeners can access 'numLoadingTiles' if they wish to keep track
-        // of the loading progress
-        //
-        this.events.addEventType("tileloaded");
-
-        this.grid = [];
-    },
-
-    /**
-     * APIMethod: destroy
-     * Deconstruct the layer and clear the grid.
-     */
-    destroy: function() {
-        this.clearGrid();
-        this.grid = null;
-        this.tileSize = null;
-        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); 
-    },
-
-    /**
-     * Method: clearGrid
-     * Go through and remove all tiles from the grid, calling
-     *    destroy() on each of them to kill circular references
-     */
-    clearGrid:function() {
-        if (this.grid) {
-            for(var iRow=0; iRow < this.grid.length; iRow++) {
-                var row = this.grid[iRow];
-                for(var iCol=0; iCol < row.length; iCol++) {
-                    var tile = row[iCol];
-                    this.removeTileMonitoringHooks(tile);
-                    tile.destroy();
-                }
-            }
-            this.grid = [];
-        }
-    },
-
-    /**
-     * APIMethod: clone
-     * Create a clone of this layer
-     *
-     * Parameters:
-     * obj - {Object} Is this ever used?
-     * 
-     * Returns:
-     * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
-     */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer.Grid(this.name,
-                                            this.url,
-                                            this.params,
-                                            this.options);
-        }
-
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
-
-        // copy/set any non-init, non-simple values here
-        if (this.tileSize != null) {
-            obj.tileSize = this.tileSize.clone();
-        }
-        
-        // we do not want to copy reference to grid, so we make a new array
-        obj.grid = [];
-
-        return obj;
-    },    
-
-    /**
-     * Method: moveTo
-     * This function is called whenever the map is moved. All the moving
-     * of actual 'tiles' is done by the map, but moveTo's role is to accept
-     * a bounds and make sure the data that that bounds requires is pre-loaded.
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * zoomChanged - {Boolean}
-     * dragging - {Boolean}
-     */
-    moveTo:function(bounds, zoomChanged, dragging) {
-        OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
-        
-        bounds = bounds || this.map.getExtent();
-
-        if (bounds != null) {
-             
-            // if grid is empty or zoom has changed, we *must* re-tile
-            var forceReTile = !this.grid.length || zoomChanged;
-
-            // total bounds of the tiles
-            var tilesBounds = this.getTilesBounds();            
-      
-            if (this.singleTile) {
-                
-                // We want to redraw whenever even the slightest part of the 
-                //  current bounds is not contained by our tile.
-                //  (thus, we do not specify partial -- its default is false)
-                if ( forceReTile || 
-                     (!dragging && !tilesBounds.containsBounds(bounds))) {
-                    this.initSingleTile(bounds);
-                }
-            } else {
-             
-                // if the bounds have changed such that they are not even 
-                //  *partially* contained by our tiles (IE user has 
-                //  programmatically panned to the other side of the earth) 
-                //  then we want to reTile (thus, partial true).  
-                //
-                if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
-                    this.initGriddedTiles(bounds);
-                } else {
-                    //we might have to shift our buffer tiles
-                    this.moveGriddedTiles(bounds);
-                }
-            }
-        }
-    },
-    
-    /**
-     * APIMethod: setTileSize
-     * Check if we are in singleTile mode and if so, set the size as a ratio
-     *     of the map size (as specified by the layer's 'ratio' property).
-     * 
-     * Parameters:
-     * size - {<OpenLayers.Size>}
-     */
-    setTileSize: function(size) { 
-        if (this.singleTile) {
-            var size = this.map.getSize().clone();
-            size.h = parseInt(size.h * this.ratio);
-            size.w = parseInt(size.w * this.ratio);
-        } 
-        OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
-    },
-        
-    /**
-     * Method: getGridBounds
-     * Deprecated. This function will be removed in 3.0. Please use 
-     *     getTilesBounds() instead.
-     * 
-     * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     * currently loaded tiles (including those partially or not at all seen 
-     * onscreen)
-     */
-    getGridBounds: function() {
-        var msg = "The getGridBounds() function is deprecated. It will be " +
-                  "removed in 3.0. Please use getTilesBounds() instead.";
-        OpenLayers.Console.warn(msg);
-        return this.getTilesBounds();
-    },
-
-    /**
-     * APIMethod: getTilesBounds
-     * Return the bounds of the tile grid.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
-     *     currently loaded tiles (including those partially or not at all seen 
-     *     onscreen).
-     */
-    getTilesBounds: function() {    
-        var bounds = null; 
-        
-        if (this.grid.length) {
-            var bottom = this.grid.length - 1;
-            var bottomLeftTile = this.grid[bottom][0];
-    
-            var right = this.grid[0].length - 1; 
-            var topRightTile = this.grid[0][right];
-    
-            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left, 
-                                           bottomLeftTile.bounds.bottom,
-                                           topRightTile.bounds.right, 
-                                           topRightTile.bounds.top);
-            
-        }   
-        return bounds;
-    },
-
-    /**
-     * Method: initSingleTile
-     * 
-     * Parameters: 
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    initSingleTile: function(bounds) {
-
-        //determine new tile bounds
-        var center = bounds.getCenterLonLat();
-        var tileWidth = bounds.getWidth() * this.ratio;
-        var tileHeight = bounds.getHeight() * this.ratio;
-                                       
-        var tileBounds = 
-            new OpenLayers.Bounds(center.lon - (tileWidth/2),
-                                  center.lat - (tileHeight/2),
-                                  center.lon + (tileWidth/2),
-                                  center.lat + (tileHeight/2));
-  
-        var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
-        var px = this.map.getLayerPxFromLonLat(ul);
-
-        if (!this.grid.length) {
-            this.grid[0] = [];
-        }
-
-        var tile = this.grid[0][0];
-        if (!tile) {
-            tile = this.addTile(tileBounds, px);
-            
-            this.addTileMonitoringHooks(tile);
-            tile.draw();
-            this.grid[0][0] = tile;
-        } else {
-            tile.moveTo(tileBounds, px);
-        }           
-        
-        //remove all but our single tile
-        this.removeExcessTiles(1,1);
-    },
-
-    /**
-     * Method: initGriddedTiles
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    initGriddedTiles:function(bounds) {
-        
-        // work out mininum number of rows and columns; this is the number of
-        // tiles required to cover the viewport plus at least one for panning
-
-        var viewSize = this.map.getSize();
-        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 
-                      Math.max(1, 2 * this.buffer);
-        var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
-                      Math.max(1, 2 * this.buffer);
-        
-        var extent = this.map.getMaxExtent();
-        var resolution = this.map.getResolution();
-        var tilelon = resolution * this.tileSize.w;
-        var tilelat = resolution * this.tileSize.h;
-        
-        var offsetlon = bounds.left - extent.left;
-        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
-        var tilecolremain = offsetlon/tilelon - tilecol;
-        var tileoffsetx = -tilecolremain * this.tileSize.w;
-        var tileoffsetlon = extent.left + tilecol * tilelon;
-        
-        var offsetlat = bounds.top - (extent.bottom + tilelat);  
-        var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
-        var tilerowremain = tilerow - offsetlat/tilelat;
-        var tileoffsety = -tilerowremain * this.tileSize.h;
-        var tileoffsetlat = extent.bottom + tilerow * tilelat;
-        
-        tileoffsetx = Math.round(tileoffsetx); // heaven help us
-        tileoffsety = Math.round(tileoffsety);
-
-        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
-
-        var startX = tileoffsetx; 
-        var startLon = tileoffsetlon;
-
-        var rowidx = 0;
-    
-        do {
-            var row = this.grid[rowidx++];
-            if (!row) {
-                row = [];
-                this.grid.push(row);
-            }
-
-            tileoffsetlon = startLon;
-            tileoffsetx = startX;
-            var colidx = 0;
- 
-            do {
-                var tileBounds = 
-                    new OpenLayers.Bounds(tileoffsetlon, 
-                                          tileoffsetlat, 
-                                          tileoffsetlon + tilelon,
-                                          tileoffsetlat + tilelat);
-
-                var x = tileoffsetx;
-                x -= parseInt(this.map.layerContainerDiv.style.left);
-
-                var y = tileoffsety;
-                y -= parseInt(this.map.layerContainerDiv.style.top);
-
-                var px = new OpenLayers.Pixel(x, y);
-                var tile = row[colidx++];
-                if (!tile) {
-                    tile = this.addTile(tileBounds, px);
-                    this.addTileMonitoringHooks(tile);
-                    row.push(tile);
-                } else {
-                    tile.moveTo(tileBounds, px, false);
-                }
-     
-                tileoffsetlon += tilelon;       
-                tileoffsetx += this.tileSize.w;
-            } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
-                     || colidx < minCols)  
-             
-            tileoffsetlat -= tilelat;
-            tileoffsety += this.tileSize.h;
-        } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
-                || rowidx < minRows)
-        
-        //shave off exceess rows and colums
-        this.removeExcessTiles(rowidx, colidx);
-
-        //now actually draw the tiles
-        this.spiralTileLoad();
-    },
-    
-    /**
-     * Method: spiralTileLoad
-     *   Starts at the top right corner of the grid and proceeds in a spiral 
-     *    towards the center, adding tiles one at a time to the beginning of a 
-     *    queue. 
-     * 
-     *   Once all the grid's tiles have been added to the queue, we go back 
-     *    and iterate through the queue (thus reversing the spiral order from 
-     *    outside-in to inside-out), calling draw() on each tile. 
-     */
-    spiralTileLoad: function() {
-        var tileQueue = [];
- 
-        var directions = ["right", "down", "left", "up"];
-
-        var iRow = 0;
-        var iCell = -1;
-        var direction = OpenLayers.Util.indexOf(directions, "right");
-        var directionsTried = 0;
-        
-        while( directionsTried < directions.length) {
-
-            var testRow = iRow;
-            var testCell = iCell;
-
-            switch (directions[direction]) {
-                case "right":
-                    testCell++;
-                    break;
-                case "down":
-                    testRow++;
-                    break;
-                case "left":
-                    testCell--;
-                    break;
-                case "up":
-                    testRow--;
-                    break;
-            } 
-    
-            // if the test grid coordinates are within the bounds of the 
-            //  grid, get a reference to the tile.
-            var tile = null;
-            if ((testRow < this.grid.length) && (testRow >= 0) &&
-                (testCell < this.grid[0].length) && (testCell >= 0)) {
-                tile = this.grid[testRow][testCell];
-            }
-            
-            if ((tile != null) && (!tile.queued)) {
-                //add tile to beginning of queue, mark it as queued.
-                tileQueue.unshift(tile);
-                tile.queued = true;
-                
-                //restart the directions counter and take on the new coords
-                directionsTried = 0;
-                iRow = testRow;
-                iCell = testCell;
-            } else {
-                //need to try to load a tile in a different direction
-                direction = (direction + 1) % 4;
-                directionsTried++;
-            }
-        } 
-        
-        // now we go through and draw the tiles in forward order
-        for(var i=0; i < tileQueue.length; i++) {
-            var tile = tileQueue[i];
-            tile.draw();
-            //mark tile as unqueued for the next time (since tiles are reused)
-            tile.queued = false;       
-        }
-    },
-
-    /**
-     * APIMethod: addTile
-     * Gives subclasses of Grid the opportunity to create an 
-     * OpenLayer.Tile of their choosing. The implementer should initialize 
-     * the new tile and take whatever steps necessary to display it.
-     *
-     * Parameters
-     * bounds - {<OpenLayers.Bounds>}
-     *
-     * Returns:
-     * {<OpenLayers.Tile>} The added OpenLayers.Tile
-     */
-    addTile:function(bounds, position) {
-        // Should be implemented by subclasses
-    },
-    
-    /** 
-     * Method: addTileMonitoringHooks
-     * This function takes a tile as input and adds the appropriate hooks to 
-     *     the tile so that the layer can keep track of the loading tiles.
-     * 
-     * Parameters: 
-     * tile - {<OpenLayers.Tile>}
-     */
-    addTileMonitoringHooks: function(tile) {
-        
-        tile.onLoadStart = function() {
-            //if that was first tile then trigger a 'loadstart' on the layer
-            if (this.numLoadingTiles == 0) {
-                this.events.triggerEvent("loadstart");
-            }
-            this.numLoadingTiles++;
-        };
-        tile.events.register("loadstart", this, tile.onLoadStart);
-      
-        tile.onLoadEnd = function() {
-            this.numLoadingTiles--;
-            this.events.triggerEvent("tileloaded");
-            //if that was the last tile, then trigger a 'loadend' on the layer
-            if (this.numLoadingTiles == 0) {
-                this.events.triggerEvent("loadend");
-            }
-        };
-        tile.events.register("loadend", this, tile.onLoadEnd);
-    },
-
-    /** 
-     * Method: removeTileMonitoringHooks
-     * This function takes a tile as input and removes the tile hooks 
-     *     that were added in addTileMonitoringHooks()
-     * 
-     * Parameters: 
-     * tile - {<OpenLayers.Tile>}
-     */
-    removeTileMonitoringHooks: function(tile) {
-        tile.events.unregister("loadstart", this, tile.onLoadStart);
-        tile.events.unregister("loadend", this, tile.onLoadEnd);
-    },
-    
-    /**
-     * Method: moveGriddedTiles
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    moveGriddedTiles: function(bounds) {
-        var buffer = this.buffer || 1;
-        while (true) {
-            var tlLayer = this.grid[0][0].position;
-            var tlViewPort = 
-                this.map.getViewPortPxFromLayerPx(tlLayer);
-            if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
-                this.shiftColumn(true);
-            } else if (tlViewPort.x < -this.tileSize.w * buffer) {
-                this.shiftColumn(false);
-            } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
-                this.shiftRow(true);
-            } else if (tlViewPort.y < -this.tileSize.h * buffer) {
-                this.shiftRow(false);
-            } else {
-                break;
-            }
-        };
-    },
-
-    /**
-     * Method: shiftRow
-     * Shifty grid work
-     *
-     * Parameters:
-     * prepend - {Boolean} if true, prepend to beginning.
-     *                          if false, then append to end
-     */
-    shiftRow:function(prepend) {
-        var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
-        var modelRow = this.grid[modelRowIndex];
-
-        var resolution = this.map.getResolution();
-        var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
-        var deltaLat = resolution * -deltaY;
-
-        var row = (prepend) ? this.grid.pop() : this.grid.shift();
-
-        for (var i=0; i < modelRow.length; i++) {
-            var modelTile = modelRow[i];
-            var bounds = modelTile.bounds.clone();
-            var position = modelTile.position.clone();
-            bounds.bottom = bounds.bottom + deltaLat;
-            bounds.top = bounds.top + deltaLat;
-            position.y = position.y + deltaY;
-            row[i].moveTo(bounds, position);
-        }
-
-        if (prepend) {
-            this.grid.unshift(row);
-        } else {
-            this.grid.push(row);
-        }
-    },
-
-    /**
-     * Method: shiftColumn
-     * Shift grid work in the other dimension
-     *
-     * Parameters:
-     * prepend - {Boolean} if true, prepend to beginning.
-     *                          if false, then append to end
-     */
-    shiftColumn: function(prepend) {
-        var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
-        var resolution = this.map.getResolution();
-        var deltaLon = resolution * deltaX;
-
-        for (var i=0; i<this.grid.length; i++) {
-            var row = this.grid[i];
-            var modelTileIndex = (prepend) ? 0 : (row.length - 1);
-            var modelTile = row[modelTileIndex];
-            
-            var bounds = modelTile.bounds.clone();
-            var position = modelTile.position.clone();
-            bounds.left = bounds.left + deltaLon;
-            bounds.right = bounds.right + deltaLon;
-            position.x = position.x + deltaX;
-
-            var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
-            tile.moveTo(bounds, position);
-            if (prepend) {
-                this.grid[i].unshift(tile);
-            } else {
-                this.grid[i].push(tile);
-            }
-        }
-    },
-    
-    /**
-     * Method: removeExcessTiles
-     * When the size of the map or the buffer changes, we may need to
-     *     remove some excess rows and columns.
-     * 
-     * Parameters:
-     * rows - {Integer} Maximum number of rows we want our grid to have.
-     * colums - {Integer} Maximum number of columns we want our grid to have.
-     */
-    removeExcessTiles: function(rows, columns) {
-        
-        // remove extra rows
-        while (this.grid.length > rows) {
-            var row = this.grid.pop();
-            for (var i=0, l=row.length; i<l; i++) {
-                var tile = row[i];
-                this.removeTileMonitoringHooks(tile);
-                tile.destroy();
-            }
-        }
-        
-        // remove extra columns
-        while (this.grid[0].length > columns) {
-            for (var i=0, l=this.grid.length; i<l; i++) {
-                var row = this.grid[i];
-                var tile = row.pop();
-                this.removeTileMonitoringHooks(tile);
-                tile.destroy();
-            }
-        }
-    },
-
-    /**
-     * Method: onMapResize
-     * For singleTile layers, this will replace the tile with the
-     * a new one with updated tileSize and extent.
-     */
-    onMapResize: function() {
-      if (this.singleTile) {
-        this.clearGrid();
-        this.setTileSize();
-        this.initSingleTile(this.map.getExtent());
-      }
-    },
-    
-    /**
-     * APIMethod: getTileBounds
-     * Returns The tile bounds for a layer given a pixel location.
-     *
-     * Parameters:
-     * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
-     *
-     * Returns:
-     * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
-     */
-    getTileBounds: function(viewPortPx) {
-        var maxExtent = this.map.getMaxExtent();
-        var resolution = this.getResolution();
-        var tileMapWidth = resolution * this.tileSize.w;
-        var tileMapHeight = resolution * this.tileSize.h;
-        var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
-        var tileLeft = maxExtent.left + (tileMapWidth *
-                                         Math.floor((mapPoint.lon -
-                                                     maxExtent.left) /
-                                                    tileMapWidth));
-        var tileBottom = maxExtent.bottom + (tileMapHeight *
-                                             Math.floor((mapPoint.lat -
-                                                         maxExtent.bottom) /
-                                                        tileMapHeight));
-        return new OpenLayers.Bounds(tileLeft, tileBottom,
-                                     tileLeft + tileMapWidth,
-                                     tileBottom + tileMapHeight);
-    },
-    
-    CLASS_NAME: "OpenLayers.Layer.Grid"
-});
-/* ======================================================================
-    OpenLayers/Control/Navigation.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control/ZoomBox.js
- * @requires OpenLayers/Control/DragPan.js
- * @requires OpenLayers/Handler/MouseWheel.js
- * 
- * Class: OpenLayers.Control.Navigation
- * The navigation control handles map browsing with mouse events (dragging,
- *     double-clicking, and scrolling the wheel).  Create a new navigation 
- *     control with the <OpenLayers.Control.Navigation> control.  
- * 
- *     Note that this control is added to the map by default (if no controls 
- *     array is sent in the options object to the <OpenLayers.Map> 
- *     constructor).
- * 
- * Inherits:
- *  - <OpenLayers.Control>
- */
-OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
-
-    /** 
-     * Property: dragPan
-     * {<OpenLayers.Control.DragPan>} 
-     */
-    dragPan: null,
-
-    /** 
-     * Property: zoomBox
-     * {<OpenLayers.Control.ZoomBox>}
-     */
-    zoomBox: null,
-
-    /** 
-     * Property: wheelHandler
-     * {<OpenLayers.Handler.MouseWheel>}
-     */
-    wheelHandler: null,
-
-    /**
-     * Constructor: OpenLayers.Control.Navigation
-     * Create a new navigation control
-     * 
-     * Parameters:
-     * options - {Object} An optional object whose properties will be set on
-     *                    the control
-     */
-    initialize: function(options) {
-        OpenLayers.Control.prototype.initialize.apply(this, arguments);
-    },
-
-    /**
-     * Method: activate
-     */
-    activate: function() {
-        this.dragPan.activate();
-        this.wheelHandler.activate();
-        this.zoomBox.activate();
-        return OpenLayers.Control.prototype.activate.apply(this,arguments);
-    },
-
-    /**
-     * Method: deactivate
-     */
-    deactivate: function() {
-        this.zoomBox.deactivate();
-        this.dragPan.deactivate();
-        this.wheelHandler.deactivate();
-        return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
-    },
-    
-    /**
-     * Method: draw
-     */
-    draw: function() {
-        this.map.events.register( "dblclick", this, this.defaultDblClick );
-        this.dragPan = new OpenLayers.Control.DragPan({map: this.map});
-        this.zoomBox = new OpenLayers.Control.ZoomBox(
-                    {map: this.map, keyMask: OpenLayers.Handler.MOD_SHIFT});
-        this.dragPan.draw();
-        this.zoomBox.draw();
-        this.wheelHandler = new OpenLayers.Handler.MouseWheel(
-                                    this, {"up"  : this.wheelUp,
-                                           "down": this.wheelDown} );
-        this.activate();
-    },
-
-    /**
-     * Method: defaultDblClick 
-     * 
-     * Parameters:
-     * evt - {Event} 
-     */
-    defaultDblClick: function (evt) {
-        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
-        this.map.setCenter(newCenter, this.map.zoom + 1);
-        OpenLayers.Event.stop(evt);
-        return false;
-    },
-
-    /**
-     * Method: wheelChange  
-     *
-     * Parameters:
-     * evt - {Event}
-     */
-    wheelChange: function(evt, deltaZ) {
-        var newZoom = this.map.getZoom() + deltaZ;
-        if (!this.map.isValidZoomLevel(newZoom)) return;
-
-        var size    = this.map.getSize();
-        var deltaX  = size.w/2 - evt.xy.x;
-        var deltaY  = evt.xy.y - size.h/2;
-        var newRes  = this.map.baseLayer.resolutions[newZoom];
-        var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
-        var newCenter = new OpenLayers.LonLat(
-                            zoomPoint.lon + deltaX * newRes,
-                            zoomPoint.lat + deltaY * newRes );
-        this.map.setCenter( newCenter, newZoom );
-    },
-
-    /** 
-     * Method: wheelUp
-     * User spun scroll wheel up
-     * 
-     * Parameters:
-     * evt - {Event}
-     */
-    wheelUp: function(evt) {
-        this.wheelChange(evt, 1);
-    },
-
-    /** 
-     * Method: wheelDown
-     * User spun scroll wheel down
-     * 
-     * Parameters:
-     * evt - {Event}
-     */
-    wheelDown: function(evt) {
-        this.wheelChange(evt, -1);
-    },
-
-    CLASS_NAME: "OpenLayers.Control.Navigation"
-});
-/* ======================================================================
-    OpenLayers/Layer/MapGuide.js
-   ====================================================================== */
-
-/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Ajax.js
- * @requires OpenLayers/Layer/Grid.js
- *
- * Class: OpenLayers.Layer.MapGuide
- * Instances of OpenLayers.Layer.MapGuide are used to display
- * data from a MapGuide OS instance.
- *
- * Inherits from:
- *  - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
-    /** 
-     * APIProperty: reproject
-     * {Boolean} Try to reproject this layer if it is used as an overlay.
-     *     Default is false.
-     **/
-    reproject: false,
-    
-    /** 
-     * APIProperty: isBaseLayer
-     * {Boolean} Treat this layer as a base layer.  Default is true.
-     **/
-    isBaseLayer: true,
-    
-    /**
-     * Constant: DEFAULT_PARAMS
-     * {Object} Hashtable of default parameter key/value pairs 
-     */
-    TILE_PARAMS: {
-                      operation: 'GETTILEIMAGE',
-                      version: '1.2.0'
-                     },
-
-    SINGLE_TILE_PARAMS: {
-                      operation: 'GETMAPIMAGE',
-                      format: 'PNG',
-                      version: '1.0.0'
-                     },
-
-    session: null,
-    mapName: null,
-    groupName: null,
-
-    /**
-    * @constructor
-    *
-    * @param {str} name
-    * @param {str} url
-    * @param {hash} params
-    * @param {Object} options
-    */
-    initialize: function(name, url, params, options) {
-        
-        var newArguments = new Array();
-        newArguments.push(name, url, params, options);
-        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-
-        // unless explicitly set in options, if the layer is transparent, 
-        // it will be an overlay
-        if (options == null || options.isBaseLayer == null) {
-            this.isBaseLayer = ((this.params.transparent != "true") && 
-                                (this.params.transparent != true));
-        }
-
-        if (arguments.length > 0) {
-          if (this.options.singleTile) {
-            this.session = params.session;
-            this.mapName = params.mapname;
-            OpenLayers.Util.applyDefaults(
-                           this.params,
-                           this.SINGLE_TILE_PARAMS
-                           );
-            if (!this.isBaseLayer) {
-              this.params.operation = "GETDYNAMICMAPOVERLAYIMAGE";
-            }
-          } else {
-            this.groupName = params.groupname;
-            OpenLayers.Util.applyDefaults(
-                           this.params,
-                           this.TILE_PARAMS
-                           );
-            this.setTileSize(new OpenLayers.Size(300,300)); //TBD: set this by options?
-          }
-        }
-    },
-
-    updateExtents: function(a) {
-      var center = this.map.getExtent().getCenterLonLat();
-      var mapSize = this.map.getCurrentSize();
-      var sParams = "operation=GETVISIBLEMAPEXTENT&version=1.0.0";
-      sParams += "&session="+this.session;
-      sParams += "&mapname="+this.mapName;
-      sParams += "&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;   
-      sParams += "&setdisplayheight="+mapSize.h*this.ratio;
-      sParams += "&setdisplaywidth="+mapSize.w*this.ratio;
-      sParams += "&setviewcenterx="+center.lon;
-      sParams += "&setviewcentery="+center.lat;
-      sParams += "&setviewscale="+this.map.getScale();
-      if (this.options.showLayers) sParams += "&showlayers="+this.options.showLayers;
-      if (this.options.hideLayers) sParams += "&hidelayers="+this.options.hideLayers;
-      if (this.options.showGroups) sParams += "&showgroups="+this.options.showGroups;
-      if (this.options.hideGroups) sParams += "&hidegroups="+this.options.hideGroups;
-      if (this.options.refreshLayers) sParams += "&refreshlayers="+this.options.refreshLayers;
-      sParams += "&ts="+(new Date()).getTime();
-      // add in hidden/visible layers here?
-      new OpenLayers.Ajax.Request(this.url, 
-             {   parameters: sParams,
-                 onSuccess: this._getExtentSuccess, 
-                 onFailure: this._getExtentFailure,
-                 //requestHeaders: ['Authorization', 'Basic QW5vbnltb3VzOg=='], //TBD anon user base64 encoded
-                 asynchronous: false         //must be synchronous call to return control here
-              });
-
-    },
-    
-    _getExtentSuccess: function(transport) {
-      //really this is a no-op, result is thrown away
-      var temp = transport.responseXML;
-    },
-    
-    _getExtentFailure: function(r) {
-      //no-op
-    },
-    
-    
-	/**
-    * @param {Object} obj
-    *
-    * @returns A clone of this OpenLayers.Layer.MapGuide
-    * @type OpenLayers.Layer.MapGuide
-    */
-    clone: function (obj) {
-      if (obj == null) {
-            obj = new OpenLayers.Layer.MapGuide(this.name,
-                                           this.url,
-                                           this.params,
-                                           this.options);
-        }
-      //get all additions from superclasses
-      obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
-      // copy/set any non-init, non-simple values here
-
-      return obj;
-    },
-
-    /**
-    * addTile creates a tile, initializes it (via 'draw' in this case), and
-    * adds it to the layer div.
-    *
-    * @param {OpenLayers.Bounds} bounds
-    *
-    * @returns The added OpenLayers.Tile.Image
-    * @type OpenLayers.Tile.Image
-    */
-    addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds, url, this.tileSize);
-    },
-
-     /**
-     * @param {OpenLayers.Bounds} bounds
-     * 
-     * @returns A string with the layer's url and parameters and also the 
-     *           passed-in bounds and appropriate tile size specified as 
-     *           parameters
-     * @type String
-     */
-    getURL: function (bounds) {
-        
-        var center = bounds.getCenterLonLat();
-        var mapSize = this.map.getCurrentSize();
-
-        if (this.options.singleTile) {
-          //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY
-          var params = {};
-
-          params.session = this.session;
-          params.mapname = this.mapName;
-          if (this.isBaseLayer) {
-            params.locale = "en";
-            params.setdisplaydpi = OpenLayers.DOTS_PER_INCH;   
-            params.setdisplayheight = mapSize.h*this.ratio;
-            params.setdisplaywidth = mapSize.w*this.ratio;
-            params.setviewcenterx = center.lon;
-            params.setviewcentery = center.lat;
-            params.setviewscale = this.map.getScale();
-            if (this.options.showLayers) params.showlayers = this.options.showLayers;
-            if (this.options.hideLayers) params.hidelayers = this.options.hideLayers;
-            if (this.options.showGroups) params.showgroups = this.options.showGroups;
-            if (this.options.hideGroups) params.hidegroups = this.options.hideGroups;
-            if (this.options.refreshLayers) params.refreshlayers = this.options.refreshLayers;
-          } else {
-            this.updateExtents();
-          }
-          params.ts = (new Date()).getTime();
-
-          var url = this.getFullRequestString( params );
-
-        } else {
-
-          //tiled version
-          var currentRes = this.map.getResolution();
-          var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
-          colidx = Math.round(colidx/this.tileSize.w);
-          var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
-          rowidx = Math.round(rowidx/this.tileSize.h);
-
-          var url = this.getFullRequestString(
-                       {
-                           tilecol: colidx,
-                           tilerow: rowidx,
-                           scaleindex: this.resolutions.length-this.map.zoom-1
-                        });
-         }
-        
-        return url;
-    },
-
-    /** 
-     * getFullRequestString on MapGuide layers is special, because we 
-     * do a regular expression replace on ',' in parameters to '+'.
-     * This is why it is subclassed here.
-     *
-     * @param {Object} newParams Parameters to add to the default parameters
-     *                           for the layer.
-     * @param {String} altUrl    Alternative base URL to use.
-     */
-    getFullRequestString:function(newParams, altUrl) {
-        
-    
-        // use layer's url unless altUrl passed in
-        var url = (altUrl == null) ? this.url : altUrl;
-        
-        // if url is not a string, it should be an array of strings, 
-        //  in which case we will randomly select one of them in order
-        //  to evenly distribute requests to different urls.
-        if (typeof url == "object") {
-            url = url[Math.floor(Math.random()*url.length)];
-        }   
-        // requestString always starts with url
-        var requestString = url;        
-
-        // create a new params hashtable with all the layer params and the 
-        // new params together. then convert to string
-        var allParams = OpenLayers.Util.extend({}, this.params);
-        allParams = OpenLayers.Util.extend(allParams, newParams);
-        // ignore parameters that are already in the url search string
-        var urlParams = OpenLayers.Util.upperCaseObject(
-                            OpenLayers.Util.getArgs(url));
-        for(var key in allParams) {
-            if(key.toUpperCase() in urlParams) {
-                delete allParams[key];
-            }
-        }
-        var paramsString = OpenLayers.Util.getParameterString(allParams);
-        
-        /* MapGuide needs '+' seperating things like bounds/height/width.
-           Since typically this is URL encoded, we use a slight hack: we
-           depend on the list-like functionality of getParameterString to
-           leave ',' only in the case of list items (since otherwise it is
-           encoded) then do a regular expression replace on the , characters
-           to '+' */
-        paramsString = paramsString.replace(/,/g, "+");
-        
-        if (paramsString != "") {
-            var lastServerChar = url.charAt(url.length - 1);
-            if ((lastServerChar == "&") || (lastServerChar == "?")) {
-                requestString += paramsString;
-            } else {
-                if (url.indexOf('?') == -1) {
-                    //serverPath has no ? -- add one
-                    requestString += '?' + paramsString;
-                } else {
-                    //serverPath contains ?, so must already have paramsString at the end
-                    requestString += '&' + paramsString;
-                }
-            }
-        }
-        return requestString;
-    },
-
-    /**
-     * Method: initGriddedTiles
-     * 
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     */
-    initGriddedTiles:function(bounds) {
-       
-        // work out mininum number of rows and columns; this is the number of
-        // tiles required to cover the viewport plus one for panning
-        var viewSize = this.map.getSize();
-        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 1;
-        var minCols = Math.ceil(viewSize.w/this.tileSize.w) + 1;
-        
-        var extent = this.map.getMaxExtent();
-        var resolution = this.map.getResolution();
-        var tilelon = resolution * this.tileSize.w;
-        var tilelat = resolution * this.tileSize.h;
-        
-        var offsetlon = bounds.left - extent.left;
-        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
-        var tilecolremain = offsetlon/tilelon - tilecol;
-        var tileoffsetx = -tilecolremain * this.tileSize.w;
-        var tileoffsetlon = extent.left + tilecol * tilelon;
-        
-        //Original OL code
-        //var offsetlat = bounds.top - (extent.bottom + tilelat);  
-        //var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
-        //var tilerowremain = tilerow - offsetlat/tilelat;
-        //var tileoffsety = -tilerowremain * this.tileSize.h;
-        //var tileoffsetlat = extent.bottom + tilerow * tilelat;
-
-        var offsetlat = extent.top - bounds.top + tilelat; 
-        var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
-        var tilerowremain = tilerow - offsetlat/tilelat;
-        var tileoffsety = tilerowremain * this.tileSize.h;
-        var tileoffsetlat = extent.top - tilelat*tilerow;
-        
-
-        tileoffsetx = Math.round(tileoffsetx); // heaven help us
-        tileoffsety = Math.round(tileoffsety);
-
-        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
-
-        var startX = tileoffsetx; 
-        var startLon = tileoffsetlon;
-
-        var rowidx = 0;
-    
-        do {
-            var row = this.grid[rowidx++];
-            if (!row) {
-                row = [];
-                this.grid.push(row);
-            }
-
-            tileoffsetlon = startLon;
-            tileoffsetx = startX;
-            var colidx = 0;
- 
-            do {
-                var tileBounds = 
-                    new OpenLayers.Bounds(tileoffsetlon, 
-                                          tileoffsetlat, 
-                                          tileoffsetlon + tilelon,
-                                          tileoffsetlat + tilelat);
-
-                var x = tileoffsetx;
-                x -= parseInt(this.map.layerContainerDiv.style.left);
-
-                var y = tileoffsety;
-                //y -= parseInt(this.map.layerContainerDiv.style.top);
-
-                var px = new OpenLayers.Pixel(x, y);
-                var tile = row[colidx++];
-                if (!tile) {
-                    tile = this.addTile(tileBounds, px);
-                    this.addTileMonitoringHooks(tile);
-                    row.push(tile);
-                } else {
-                    tile.moveTo(tileBounds, px, false);
-                }
-     
-                tileoffsetlon += tilelon;       
-                tileoffsetx += this.tileSize.w;
-            } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
-                     || colidx < minCols)  
-             
-            tileoffsetlat -= tilelat;
-            tileoffsety += this.tileSize.h;
-        } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
-                || rowidx < minRows)
-        
-        //shave off exceess rows and colums
-        this.removeExcessTiles(rowidx, colidx);
-
-        //now actually draw the tiles
-        this.spiralTileLoad();
-    },
-    
-
-    /** @final @type String */
-    CLASS_NAME: "OpenLayers.Layer.MapGuide"
-});
-/* ======================================================================
-    OpenLayers/Layer/MapServer.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- *
- * Class: OpenLayers.Layer.MapServer
- * Instances of OpenLayers.Layer.MapServer are used to display
- * data from a MapServer CGI instance.
- *
- * Inherits from:
- *  - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
-    /**
-     * Constant: DEFAULT_PARAMS
-     * {Object} Hashtable of default parameter key/value pairs 
-     */
-    DEFAULT_PARAMS: {
-        mode: "map",
-        map_imagetype: "png"
-    },
-
-    /**
-     * Constructor: OpenLayers.Layer.MapServer
-     * Create a new MapServer layer object
-     *
-     * Parameters:
-     * name - {String} A name for the layer
-     * url - {String} Base url for the MapServer CGI
-     *       (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
-     * params - {Object} An object with key/value pairs representing the
-     *          GetMap query string parameters and parameter values.
-     * options - {Ojbect} Hashtable of extra options to tag onto the layer
-     */
-    initialize: function(name, url, params, options) {
-        var newArguments = [];
-        newArguments.push(name, url, params, options);
-        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-
-        if (arguments.length > 0) {
-            OpenLayers.Util.applyDefaults(
-                           this.params,
-                           this.DEFAULT_PARAMS
-                           );
-        }
-
-        // unless explicitly set in options, if the layer is transparent, 
-        // it will be an overlay
-        if (options == null || options.isBaseLayer == null) {
-            this.isBaseLayer = ((this.params.transparent != "true") && 
-                                (this.params.transparent != true));
-        }
-    },
-
-    /**
-     * Method: clone
-     * Create a clone of this layer
-     *
-     * Returns:
-     * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
-     */
-    clone: function (obj) {
-        if (obj == null) {
-            obj = new OpenLayers.Layer.MapServer(this.name,
-                                           this.url,
-                                           this.params,
-                                           this.options);
-        }
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
-        // copy/set any non-init, non-simple values here
-
-        return obj;
-    },
-
-    /**
-     * Method: addTile
-     * Creates a tile, initializes it, and adds it to the layer div. 
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * 
-     * Returns:
-     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
-     */
-    addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds, 
-                                         null, this.tileSize);
-    },
-    
-    /**
-     * Method: getURL
-     * Return a query string for this layer
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
-     *                                for the request
-     *
-     * Returns:
-     * {String} A string with the layer's url and parameters and also 
-     *          the passed-in bounds and appropriate tile size specified 
-     *          as parameters.
-     */
-    getURL: function (bounds) {
-        bounds = this.adjustBounds(bounds);
-        // Make a list, so that getFullRequestString uses literal "," 
-        var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
-
-        var imageSize = this.getImageSize(); 
-        
-        // make lists, so that literal ','s are used 
-        var url = this.getFullRequestString(
-                     {mapext:   extent,
-                      imgext:   extent,
-                      map_size: [imageSize.w, imageSize.h],
-                      imgx:     imageSize.w / 2,
-                      imgy:     imageSize.h / 2,
-                      imgxy:    [imageSize.w, imageSize.h]
-                      });
-        
-        return url;
-    },
-    
-    /** 
-     * Method: getFullRequestString
-     * combine the layer's url with its params and these newParams. 
-     *   
-     * Parameter:
-     * newParams - {Object} New parameters that should be added to the 
-     *                      request string.
-     * altUrl - {String} (optional) Replace the URL in the full request  
-     *                              string with the provided URL.
-     * 
-     * Returns: 
-     * {String} A string with the layer's url and parameters embedded in it.
-     */
-    getFullRequestString:function(newParams, altUrl) {
-        // use layer's url unless altUrl passed in
-        var url = (altUrl == null) ? this.url : altUrl;
-        
-        // if url is not a string, it should be an array of strings, 
-        //  in which case we will randomly select one of them in order
-        //  to evenly distribute requests to different urls.
-        if (typeof url == "object") {
-            url = url[Math.floor(Math.random()*url.length)];
-        }   
-        // requestString always starts with url
-        var requestString = url;        
-
-        // create a new params hashtable with all the layer params and the 
-        // new params together. then convert to string
-        var allParams = OpenLayers.Util.extend({}, this.params);
-        allParams = OpenLayers.Util.extend(allParams, newParams);
-        // ignore parameters that are already in the url search string
-        var urlParams = OpenLayers.Util.upperCaseObject(
-                            OpenLayers.Util.getParameters(url));
-        for(var key in allParams) {
-            if(key.toUpperCase() in urlParams) {
-                delete allParams[key];
-            }
-        }
-        var paramsString = OpenLayers.Util.getParameterString(allParams);
-        
-        // MapServer needs '+' seperating things like bounds/height/width.
-        //   Since typically this is URL encoded, we use a slight hack: we
-        //  depend on the list-like functionality of getParameterString to
-        //  leave ',' only in the case of list items (since otherwise it is
-        //  encoded) then do a regular expression replace on the , characters
-        //  to '+'
-        //
-        paramsString = paramsString.replace(/,/g, "+");
-        
-        if (paramsString != "") {
-            var lastServerChar = url.charAt(url.length - 1);
-            if ((lastServerChar == "&") || (lastServerChar == "?")) {
-                requestString += paramsString;
-            } else {
-                if (url.indexOf('?') == -1) {
-                    //serverPath has no ? -- add one
-                    requestString += '?' + paramsString;
-                } else {
-                    //serverPath contains ?, so must already have paramsString at the end
-                    requestString += '&' + paramsString;
-                }
-            }
-        }
-        return requestString;
-    },
-
-    CLASS_NAME: "OpenLayers.Layer.MapServer"
-});
-/* ======================================================================
-    OpenLayers/Layer/WMS.js
-   ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- * @requires OpenLayers/Tile/Image.js
- * 
- * Class: OpenLayers.Layer.WMS
- * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
- *     Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
- *     constructor.
- * 
- * Inherits from:
- *  - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
-    /**
-     * Constant: DEFAULT_PARAMS
-     * {Object} Hashtable of default parameter key/value pairs 
-     */
-    DEFAULT_PARAMS: { service: "WMS",
-                      version: "1.1.1",
-                      request: "GetMap",
-                      styles: "",
-                      exceptions: "application/vnd.ogc.se_inimage",
-                      format: "image/jpeg"
-                     },
-    
-    /**
-     * Property: reproject
-     * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
-     * for information on the replacement for this functionality. 
-     * {Boolean} Try to reproject this layer if its coordinate reference system
-     *           is different than that of the base layer.  Default is true.  
-     *           Set this in the layer options.  Should be set to false in 
-     *           most cases.
-     */
-    reproject: false,
- 
-    /**
-     * APIProperty: isBaseLayer
-     * {Boolean} Default is true for WMS layer
-     */
-    isBaseLayer: true,
-    
-    /**
-     * APIProperty: encodeBBOX
-     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', 
-     * but some services want it that way. Default false.
-     */
-    encodeBBOX: false,
- 
-    /**
-     * Constructor: OpenLayers.Layer.WMS
-     * Create a new WMS layer object
-     *
-     * Example:
-     * (code)
-     * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
-     *                                    "http://wms.jpl.nasa.gov/wms.cgi", 
-     *                                    {layers: "modis,global_mosaic"});
-     * (end)
-     *
-     * Parameters:
-     * name - {String} A name for the layer
-     * url - {String} Base url for the WMS
-     *                (e.g. http://wms.jpl.nasa.gov/wms.cgi)
-     * params - {Object} An object with key/value pairs representing the
-     *                   GetMap query string parameters and parameter values.
-     * options - {Ojbect} Hashtable of extra options to tag onto the layer
-     */
-    initialize: function(name, url, params, options) {
-        var newArguments = [];
-        //uppercase params
-        params = OpenLayers.Util.upperCaseObject(params);
-        newArguments.push(name, url, params, options);
-        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-        OpenLayers.Util.applyDefaults(
-                       this.params, 
-                       OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
-                       );
-
-
-        //layer is transparent        
-        if (this.params.TRANSPARENT && 
-            this.params.TRANSPARENT.toString().toLowerCase() == "true") {
-            
-            // unless explicitly set in options, make layer an overlay
-            if ( (options == null) || (!options.isBaseLayer) ) {
-                this.isBaseLayer = false;
-            } 
-            
-            // jpegs can never be transparent, so intelligently switch the 
-            //  format, depending on teh browser's capabilities
-            if (this.params.FORMAT == "image/jpeg") {
-                this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
-                                                                 : "image/png";
-            }
-        }
-
-    },    
-
-    /**
-     * Method: destroy
-     * Destroy this layer
-     */
-    destroy: function() {
-        // for now, nothing special to do here. 
-        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
-    },
-
-    
-    /**
-     * Method: clone
-     * Create a clone of this layer
-     *
-     * Returns:
-     * {<OpenLayers.Layer.WMS>} An exact clone of this layer
-     */
-    clone: function (obj) {
-        
-        if (obj == null) {
-            obj = new OpenLayers.Layer.WMS(this.name,
-                                           this.url,
-                                           this.params,
-                                           this.options);
-        }
-
-        //get all additions from superclasses
-        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
-        // copy/set any non-init, non-simple values here
-
-        return obj;
-    },    
-    
-    /**
-     * Method: getURL
-     * Return a GetMap query string for this layer
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
-     *                                request.
-     *
-     * Returns:
-     * {String} A string with the layer's url and parameters and also the
-     *          passed-in bounds and appropriate tile size specified as 
-     *          parameters.
-     */
-    getURL: function (bounds) {
-        bounds = this.adjustBounds(bounds);
-        
-        var imageSize = this.getImageSize(); 
-        return this.getFullRequestString(
-                     {BBOX: this.encodeBBOX ?  bounds.toBBOX() : bounds.toArray(),
-                      WIDTH:imageSize.w,
-                      HEIGHT:imageSize.h});
-    },
-
-    /**
-     * Method: addTile
-     * addTile creates a tile, initializes it, and adds it to the layer div. 
-     *
-     * Parameters:
-     * bounds - {<OpenLayers.Bounds>}
-     * 
-     * Returns:
-     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
-     */
-    addTile:function(bounds,position) {
-        return new OpenLayers.Tile.Image(this, position, bounds, 
-                                         null, this.tileSize);
-    },
-
-    /**
-     * APIMethod: mergeNewParams
-     * Catch changeParams and uppercase the new params to be merged in
-     *     before calling changeParams on the super class.
-     * 
-     *     Once params have been changed, we will need to re-init our tiles.
-     * 
-     * Parameters:
-     * newParams - {Object} Hashtable of new params to use
-     */
-    mergeNewParams:function(newParams) {
-        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
-        var newArguments = [upperParams];
-        OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
-                                                             newArguments);
-    },
-
-    /** 
-     * Method: getFullRequestString
-     * Combine the layer's url with its params and these newParams. 
-     *   
-     *     Add the SRS parameter from projection -- this is probably
-     *     more eloquently done via a setProjection() method, but this 
-     *     works for now and always.
-     *
-     * Parameters:
-     * newParams - {Object}
-     * 
-     * Returns:
-     * {String} 
-     */
-    getFullRequestString:function(newParams) {
-        var projection = this.map.getProjection();
-        this.params.SRS = (projection == "none") ? null : projection.getCode();
-
-        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
-                                                    this, arguments);
-    },
-
-    CLASS_NAME: "OpenLayers.Layer.WMS"
-});
+/* ======================================================================
+    OpenLayers/SingleFile.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+OpenLayers = {
+    singleFile: true
+};
+
+
+/* ======================================================================
+    OpenLayers.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/* 
+ * @requires OpenLayers/BaseTypes.js
+ */ 
+
+(function() {
+    /**
+     * Before creating the OpenLayers namespace, check to see if
+     * OpenLayers.singleFile is true.  This occurs if the
+     * OpenLayers/SingleFile.js script is included before this one - as is the
+     * case with single file builds.
+     */
+    var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
+    
+    /**
+     * Namespace: OpenLayers
+     * The OpenLayers object provides a namespace for all things OpenLayers
+     */
+    OpenLayers = {
+        
+        /**
+         * Property: _scriptName
+         * {String} Relative path of this script.
+         */
+        _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
+
+        /**
+         * Function: _getScriptLocation
+         * Return the path to this script.
+         *
+         * Returns:
+         * Path to this script
+         */
+        _getScriptLocation: function () {
+            var scriptLocation = "";
+            var scriptName = OpenLayers._scriptName;
+         
+            var scripts = document.getElementsByTagName('script');
+            for (var i = 0; i < scripts.length; i++) {
+                var src = scripts[i].getAttribute('src');
+                if (src) {
+                    var index = src.lastIndexOf(scriptName); 
+                    // is it found, at the end of the URL?
+                    if ((index > -1) && (index + scriptName.length == src.length)) {  
+                        scriptLocation = src.slice(0, -scriptName.length);
+                        break;
+                    }
+                }
+            }
+            return scriptLocation;
+         }
+    };
+    /**
+     * OpenLayers.singleFile is a flag indicating this file is being included
+     * in a Single File Library build of the OpenLayers Library.
+     * 
+     * When we are *not* part of a SFL build we dynamically include the
+     * OpenLayers library code.
+     * 
+     * When we *are* part of a SFL build we do not dynamically include the 
+     * OpenLayers library code as it will be appended at the end of this file.
+      */
+    if(!singleFile) {
+        var jsfiles = new Array(
+            "OpenLayers/Util.js",
+            "OpenLayers/BaseTypes.js",
+            "OpenLayers/BaseTypes/Class.js",
+            "OpenLayers/BaseTypes/Bounds.js",
+            "OpenLayers/BaseTypes/Element.js",
+            "OpenLayers/BaseTypes/LonLat.js",
+            "OpenLayers/BaseTypes/Pixel.js",
+            "OpenLayers/BaseTypes/Size.js",
+            "OpenLayers/Console.js",
+            "Rico/Corner.js",
+            "Rico/Color.js",
+            "OpenLayers/Ajax.js",
+            "OpenLayers/Events.js",
+            "OpenLayers/Map.js",
+            "OpenLayers/Layer.js",
+            "OpenLayers/Icon.js",
+            "OpenLayers/Marker.js",
+            "OpenLayers/Marker/Box.js",
+            "OpenLayers/Popup.js",
+            "OpenLayers/Tile.js",
+            "OpenLayers/Tile/Image.js",
+            "OpenLayers/Tile/WFS.js",
+            "OpenLayers/Layer/Image.js",
+            "OpenLayers/Layer/SphericalMercator.js",
+            "OpenLayers/Layer/EventPane.js",
+            "OpenLayers/Layer/FixedZoomLevels.js",
+            "OpenLayers/Layer/Google.js",
+            "OpenLayers/Layer/VirtualEarth.js",
+            "OpenLayers/Layer/Yahoo.js",
+            "OpenLayers/Layer/HTTPRequest.js",
+            "OpenLayers/Layer/Grid.js",
+            "OpenLayers/Layer/MapServer.js",
+            "OpenLayers/Layer/MapGuide.js",
+            "OpenLayers/Layer/MapServer/Untiled.js",
+            "OpenLayers/Layer/KaMap.js",
+            "OpenLayers/Layer/MultiMap.js",
+            "OpenLayers/Layer/Markers.js",
+            "OpenLayers/Layer/Text.js",
+            "OpenLayers/Layer/WorldWind.js",
+            "OpenLayers/Layer/WMS.js",
+            "OpenLayers/Layer/WMS/Untiled.js",
+            "OpenLayers/Layer/GeoRSS.js",
+            "OpenLayers/Layer/Boxes.js",
+            "OpenLayers/Layer/TMS.js",
+            "OpenLayers/Layer/TileCache.js",
+            "OpenLayers/Popup/Anchored.js",
+            "OpenLayers/Popup/AnchoredBubble.js",
+            "OpenLayers/Feature.js",
+            "OpenLayers/Feature/Vector.js",
+            "OpenLayers/Feature/WFS.js",
+            "OpenLayers/Handler.js",
+            "OpenLayers/Handler/Point.js",
+            "OpenLayers/Handler/Path.js",
+            "OpenLayers/Handler/Polygon.js",
+            "OpenLayers/Handler/Feature.js",
+            "OpenLayers/Handler/Drag.js",
+            "OpenLayers/Handler/RegularPolygon.js",
+            "OpenLayers/Handler/Box.js",
+            "OpenLayers/Handler/MouseWheel.js",
+            "OpenLayers/Handler/Keyboard.js",
+            "OpenLayers/Control.js",
+            "OpenLayers/Control/Attribution.js",
+            "OpenLayers/Control/ZoomBox.js",
+            "OpenLayers/Control/ZoomToMaxExtent.js",
+            "OpenLayers/Control/DragPan.js",
+            "OpenLayers/Control/Navigation.js",
+            "OpenLayers/Control/MouseDefaults.js",
+            "OpenLayers/Control/MousePosition.js",
+            "OpenLayers/Control/OverviewMap.js",
+            "OpenLayers/Control/KeyboardDefaults.js",
+            "OpenLayers/Control/PanZoom.js",
+            "OpenLayers/Control/PanZoomBar.js",
+            "OpenLayers/Control/ArgParser.js",
+            "OpenLayers/Control/Permalink.js",
+            "OpenLayers/Control/Scale.js",
+            "OpenLayers/Control/LayerSwitcher.js",
+            "OpenLayers/Control/DrawFeature.js",
+            "OpenLayers/Control/DragFeature.js",
+            "OpenLayers/Control/ModifyFeature.js",
+            "OpenLayers/Control/Panel.js",
+            "OpenLayers/Control/SelectFeature.js",
+            "OpenLayers/Geometry.js",
+            "OpenLayers/Geometry/Rectangle.js",
+            "OpenLayers/Geometry/Collection.js",
+            "OpenLayers/Geometry/Point.js",
+            "OpenLayers/Geometry/MultiPoint.js",
+            "OpenLayers/Geometry/Curve.js",
+            "OpenLayers/Geometry/LineString.js",
+            "OpenLayers/Geometry/LinearRing.js",        
+            "OpenLayers/Geometry/Polygon.js",
+            "OpenLayers/Geometry/MultiLineString.js",
+            "OpenLayers/Geometry/MultiPolygon.js",
+            "OpenLayers/Geometry/Surface.js",
+            "OpenLayers/Renderer.js",
+            "OpenLayers/Renderer/Elements.js",
+            "OpenLayers/Renderer/SVG.js",
+            "OpenLayers/Renderer/VML.js",
+            "OpenLayers/Layer/Vector.js",
+            "OpenLayers/Layer/GML.js",
+            "OpenLayers/Format.js",
+            "OpenLayers/Format/XML.js",
+            "OpenLayers/Format/GML.js",
+            "OpenLayers/Format/KML.js",
+            "OpenLayers/Format/GeoRSS.js",
+            "OpenLayers/Format/WFS.js",
+            "OpenLayers/Format/WKT.js",
+            "OpenLayers/Format/JSON.js",
+            "OpenLayers/Format/GeoJSON.js",
+            "OpenLayers/Layer/WFS.js",
+            "OpenLayers/Control/MouseToolbar.js",
+            "OpenLayers/Control/NavToolbar.js",
+            "OpenLayers/Control/EditingToolbar.js",
+            "OpenLayers/Projection.js",
+            "OpenLayers/Strings/en.js"
+        ); // etc.
+
+
+
+        var allScriptTags = "";
+        var host = OpenLayers._getScriptLocation() + "lib/";
+    
+        for (var i = 0; i < jsfiles.length; i++) {
+            if (/MSIE/.test(navigator.userAgent) || /Safari/.test(navigator.userAgent)) {
+                var currentScriptTag = "<script src='" + host + jsfiles[i] + "'></script>"; 
+                allScriptTags += currentScriptTag;
+            } else {
+                var s = document.createElement("script");
+                s.src = host + jsfiles[i];
+                var h = document.getElementsByTagName("head").length ? 
+                           document.getElementsByTagName("head")[0] : 
+                           document.body;
+                h.appendChild(s);
+            }
+        }
+        if (allScriptTags) document.write(allScriptTags);
+    }
+})();
+
+/**
+ * Constant: VERSION_NUMBER
+ */
+OpenLayers.VERSION_NUMBER="$Revision$";
+/* ======================================================================
+    OpenLayers/Util.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * Namespace: Util
+ */
+OpenLayers.Util = {};
+
+/** 
+ * Function: getElement
+ * This is the old $() from prototype
+ */
+OpenLayers.Util.getElement = function() {
+    var elements = [];
+
+    for (var i = 0; i < arguments.length; i++) {
+        var element = arguments[i];
+        if (typeof element == 'string') {
+            element = document.getElementById(element);
+        }
+        if (arguments.length == 1) {
+            return element;
+        }
+        elements.push(element);
+    }
+    return elements;
+};
+
+/** 
+ * Maintain $() from prototype
+ */
+if ($ == null) {
+    var $ = OpenLayers.Util.getElement;
+}
+
+/**
+ * APIFunction: extend
+ * Copy all properties of a source object to a destination object.  Modifies
+ *     the passed in destination object.
+ *
+ * Parameters:
+ * destination - {Object} The object that will be modified
+ * source - {Object} The object with properties to be set on the destination
+ *
+ * Returns:
+ * {Object} The destination object.
+ */
+OpenLayers.Util.extend = function(destination, source) {
+    if(destination && source) {
+        for(var property in source) {
+            destination[property] = source[property];
+        }
+        /**
+         * IE doesn't include the toString property when iterating over an object's
+         * properties with the for(property in object) syntax.  Explicitly check if
+         * the source has its own toString property.
+         */
+        if(source.hasOwnProperty && source.hasOwnProperty('toString')) {
+            destination.toString = source.toString;
+        }
+    }
+    return destination;
+};
+
+
+/** 
+ * Function: removeItem
+ * Remove an object from an array. Iterates through the array
+ *     to find the item, then removes it.
+ *
+ * Parameters:
+ * array - {Array}
+ * item - {Object}
+ * 
+ * Return
+ * {Array} A reference to the array
+ */
+OpenLayers.Util.removeItem = function(array, item) {
+    for(var i=0; i < array.length; i++) {
+        if(array[i] == item) {
+            array.splice(i,1);
+            //break;more than once??
+        }
+    }
+    return array;
+};
+
+/**
+ * Function: clearArray
+ * *Deprecated*. This function will disappear in 3.0.
+ * Please use "array.length = 0" instead.
+ * 
+ * Parameters:
+ * array - {Array}
+ */
+OpenLayers.Util.clearArray = function(array) {
+    var msg = OpenLayers.String.translate("clearArrayDeprecated");
+    OpenLayers.Console.warn(msg);
+    array.length = 0;
+};
+
+/** 
+ * Function: indexOf
+ * Seems to exist already in FF, but not in MOZ.
+ * 
+ * Parameters:
+ * array - {Array}
+ * obj - {Object}
+ * 
+ * Returns:
+ * {Integer} The index at, which the object was found in the array.
+ *           If not found, returns -1.v
+ */
+OpenLayers.Util.indexOf = function(array, obj) {
+
+    for(var i=0; i < array.length; i++) {
+        if (array[i] == obj) return i;
+    }
+    return -1;   
+};
+
+
+
+/**
+ * Function: modifyDOMElement
+ * 
+ * Modifies many properties of a DOM element all at once.  Passing in 
+ * null to an individual parameter will avoid setting the attribute.
+ *
+ * Parameters:
+ * id - {String} The element id attribute to set.
+ * px - {<OpenLayers.Pixel>} The left and top style position.
+ * sz - {<OpenLayers.Size>}  The width and height style attributes.
+ * position - {String}       The position attribute.  eg: absolute, 
+ *                           relative, etc.
+ * border - {String}         The style.border attribute.  eg:
+ *                           solid black 2px
+ * overflow - {String}       The style.overview attribute.  
+ * opacity - {Float}         Fractional value (0.0 - 1.0)
+ */
+OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, 
+                                            border, overflow, opacity) {
+
+    if (id) {
+        element.id = id;
+    }
+    if (px) {
+        element.style.left = px.x + "px";
+        element.style.top = px.y + "px";
+    }
+    if (sz) {
+        element.style.width = sz.w + "px";
+        element.style.height = sz.h + "px";
+    }
+    if (position) {
+        element.style.position = position;
+    }
+    if (border) {
+        element.style.border = border;
+    }
+    if (overflow) {
+        element.style.overflow = overflow;
+    }
+    if (opacity) {
+        element.style.opacity = opacity;
+        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
+    }
+};
+
+/** 
+ * Function: createDiv
+ * Creates a new div and optionally set some standard attributes.
+ * Null may be passed to each parameter if you do not wish to
+ * set a particular attribute.d
+ * 
+ * Note: zIndex is NOT set
+ * 
+ * Parameters:
+ * id - {String} An identifier for this element.  If no id is
+ *               passed an identifier will be created 
+ *               automatically.
+ * px - {<OpenLayers.Pixel>} The element left and top position. 
+ * sz - {<OpenLayers.Size>} The element width and height.
+ * imgURL - {String} A url pointing to an image to use as a 
+ *                   background image.
+ * position - {String} The style.position value. eg: absolute,
+ *                     relative etc.
+ * border - {String} The the style.border value. 
+ *                   eg: 2px solid black
+ * overflow - {String} The style.overflow value. Eg. hidden
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ * 
+ * Returns: 
+ * {DOMElement} A DOM Div created with the specified attributes.
+ */
+OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, 
+                                     border, overflow, opacity) {
+
+    var dom = document.createElement('div');
+
+    if (imgURL) {
+        dom.style.backgroundImage = 'url(' + imgURL + ')';
+    }
+
+    //set generic properties
+    if (!id) {
+        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+    }
+    if (!position) {
+        position = "absolute";
+    }
+    OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, 
+                                     border, overflow, opacity);
+
+    return dom;
+};
+
+/**
+ * Function: createImage
+ * Creates an img element with specific attribute values.
+ *  
+ * Parameters:
+ * id - {String} The id field for the img.  If none assigned one will be
+ *               automatically generated.
+ * px - {<OpenLayers.Pixel>} The left and top positions.
+ * sz - {<OpenLayers.Size>} The style.width and style.height values.
+ * imgURL - {String} The url to use as the image source.
+ * position - {String} The style.position value.
+ * border - {String} The border to place around the image.
+ * delayDisplay - {Boolean} If true waits until the image has been
+ *                          loaded.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ * 
+ * Returns:
+ * {DOMElement} A DOM Image created with the specified attributes.
+ */
+OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
+                                       opacity, delayDisplay) {
+
+    var image = document.createElement("img");
+
+    //set generic properties
+    if (!id) {
+        id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+    }
+    if (!position) {
+        position = "relative";
+    }
+    OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, 
+                                     border, null, opacity);
+
+    if(delayDisplay) {
+        image.style.display = "none";
+        OpenLayers.Event.observe(image, "load", 
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
+        OpenLayers.Event.observe(image, "error", 
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
+        
+    }
+    
+    //set special properties
+    image.style.alt = id;
+    image.galleryImg = "no";
+    if (imgURL) {
+        image.src = imgURL;
+    }
+
+
+        
+    return image;
+};
+
+/**
+ * Function: setOpacity
+ * Deprecated.
+ * This function has been deprecated. Instead, please use 
+ *     OpenLayers.Util.modifyDOMElement() 
+ *     or 
+ *     OpenLayers.Util.modifyAlphaImageDiv()
+ * 
+ * Set the opacity of a DOM Element
+ *     Note that for this function to work in IE, elements must "have layout"
+ *     according to:
+ *     http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
+ *
+ * Parameters:
+ * element - {DOMElement} Set the opacity on this DOM element
+ * opacity - {Float} Opacity value (0.0 - 1.0)
+ */
+OpenLayers.Util.setOpacity = function(element, opacity) {
+    OpenLayers.Util.modifyDOMElement(element, null, null, null,
+                                     null, null, null, opacity);
+}
+
+/**
+ * Function: onImageLoad
+ */
+OpenLayers.Util.onImageLoad = function() {
+    // The complex check here is to solve issues described in #480.
+    // Every time a map view changes, it increments the 'viewRequestID' 
+    // property. As the requests for the images for the new map view are sent
+    // out, they are tagged with this unique viewRequestID. 
+    // 
+    // If an image has no viewRequestID property set, we display it regardless, 
+    // but if it does have a viewRequestID property, we check that it matches 
+    // the viewRequestID set on the map.
+    // 
+    // If the viewRequestID on the map has changed, that means that the user
+    // has changed the map view since this specific request was sent out, and
+    // therefore this tile does not need to be displayed (so we do not execute
+    // this code that turns its display on).
+    //
+    if (!this.viewRequestID ||
+        (this.map && this.viewRequestID == this.map.viewRequestID)) { 
+        this.style.backgroundColor = null;
+        this.style.display = "";  
+    }
+};
+
+/**
+ * Property: onImageLoadErrorColor
+ * {String} The color tiles with load errors will turn.
+ *          Default is "pink"
+ */
+OpenLayers.Util.onImageLoadErrorColor = "pink";
+
+/**
+ * Property: onImageLoadErrorColor
+ * {Integer} How many times should we try to reload an image before giving up?
+ *           Default is 0
+ */
+OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
+
+/**
+ * Function: onImageLoadError 
+ */
+OpenLayers.Util.onImageLoadError = function() {
+    this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
+    if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+        this.src = this.src;
+    } else {
+        this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
+    }
+    this.style.display = "";
+};
+
+/**
+ * Function: alphaHack
+ * Checks whether it's necessary (and possible) to use the png alpha
+ * hack which allows alpha transparency for png images under Internet
+ * Explorer.
+ * 
+ * Returns:
+ * {Boolean} true if alpha has is necessary and possible, false otherwise.
+ */
+OpenLayers.Util.alphaHack = function() {
+    var arVersion = navigator.appVersion.split("MSIE");
+    var version = parseFloat(arVersion[1]);
+    var filter = false;
+    
+    // IEs4Lin dies when trying to access document.body.filters, because 
+    // the property is there, but requires a DLL that can't be provided. This
+    // means that we need to wrap this in a try/catch so that this can
+    // continue.
+    
+    try { 
+        filter = document.body.filters;
+    } catch (e) {
+    }    
+    
+    return ( filter &&
+                      (version >= 5.5) && (version < 7) );
+}
+
+/** 
+ * Function: modifyAlphaImageDiv
+ * 
+ * div - {DOMElement} Div containing Alpha-adjusted Image
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ */ 
+OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, 
+                                               position, border, sizing, 
+                                               opacity) {
+
+    OpenLayers.Util.modifyDOMElement(div, id, px, sz);
+
+    var img = div.childNodes[0];
+
+    if (imgURL) {
+        img.src = imgURL;
+    }
+    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, 
+                                     "relative", border);
+    if (opacity) {
+        div.style.opacity = opacity;
+        div.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
+    }
+    
+    if (OpenLayers.Util.alphaHack()) {
+
+        div.style.display = "inline-block";
+        if (sizing == null) {
+            sizing = "scale";
+        }
+        
+        div.style.filter = "progid:DXImageTransform.Microsoft" +
+                           ".AlphaImageLoader(src='" + img.src + "', " +
+                           "sizingMethod='" + sizing + "')";
+        if (div.style.opacity) {
+            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
+        }
+
+        img.style.filter = "progid:DXImageTransform.Microsoft" +
+                                ".Alpha(opacity=0)";
+    }
+};
+
+/** 
+ * Function: createAlphaImageDiv
+ * 
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * delayDisplay{Boolean}
+ * 
+ * Returns:
+ * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is 
+ *              needed for transparency in IE, it is added.
+ */ 
+OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, 
+                                               position, border, sizing, 
+                                               opacity, delayDisplay) {
+    
+    var div = OpenLayers.Util.createDiv();
+    var img = OpenLayers.Util.createImage(null, null, null, null, null, null, 
+                                          null, false);
+    div.appendChild(img);
+
+    if (delayDisplay) {
+        img.style.display = "none";
+        OpenLayers.Event.observe(img, "load",
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
+        OpenLayers.Event.observe(img, "error",
+            OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
+    }
+
+    OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, 
+                                        border, sizing, opacity);
+    
+    return div;
+};
+
+
+/** 
+ * Function: upperCaseObject
+ * Creates a new hashtable and copies over all the keys from the 
+ *     passed-in object, but storing them under an uppercased
+ *     version of the key at which they were stored.
+ * 
+ * Parameters: 
+ * object - {Object}
+ * 
+ * Returns: 
+ * {Object} A new Object with all the same keys but uppercased
+ */
+OpenLayers.Util.upperCaseObject = function (object) {
+    var uObject = {};
+    for (var key in object) {
+        uObject[key.toUpperCase()] = object[key];
+    }
+    return uObject;
+};
+
+/** 
+ * Function: applyDefaults
+ * Takes a hashtable and copies any keys that don't exist from
+ *     another hashtable, by analogy with OpenLayers.Util.extend() from
+ *     Prototype.js.
+ * 
+ * Parameters:
+ * to - {Object}
+ * from - {Object}
+ */
+OpenLayers.Util.applyDefaults = function (to, from) {
+    for (var key in from) {
+        if (to[key] == null) {
+            to[key] = from[key];
+        }
+    }
+};
+
+/**
+ * Function: getParameterString
+ * 
+ * Parameters:
+ * params - {Object}
+ * 
+ * Returns:
+ * {String} A concatenation of the properties of an object in 
+ *          http parameter notation. 
+ *          (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
+ *          If a parameter is actually a list, that parameter will then
+ *          be set to a comma-seperated list of values (foo,bar) instead
+ *          of being URL escaped (foo%3Abar). 
+ */
+OpenLayers.Util.getParameterString = function(params) {
+    paramsArray = [];
+    
+    for (var key in params) {
+      var value = params[key];
+      if ((value != null) && (typeof value != 'function')) {
+        var encodedValue;
+        if (typeof value == 'object' && value.constructor == Array) {
+          /* value is an array; encode items and separate with "," */
+          var encodedItemArray = [];
+          for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
+            encodedItemArray.push(encodeURIComponent(value[itemIndex]));
+          }
+          encodedValue = encodedItemArray.join(",");
+        }
+        else {
+          /* value is a string; simply encode */
+          encodedValue = encodeURIComponent(value);
+        }
+        paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+      }
+    }
+    
+    return paramsArray.join("&");
+};
+
+/**
+ * Property: ImgPath
+ * {String} Default is ''.
+ */
+OpenLayers.ImgPath = '';
+
+/** 
+ * Function: getImagesLocation
+ * 
+ * Returns:
+ * {String} The fully formatted image location string
+ */
+OpenLayers.Util.getImagesLocation = function() {
+    return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
+};
+
+
+/** 
+ * Function: Try
+ * Execute functions until one of them doesn't throw an error. 
+ *     Capitalized because "try" is a reserved word in JavaScript.
+ *     Taken directly from OpenLayers.Util.Try()
+ * 
+ * Parameters:
+ * [*] - {Function} Any number of parameters may be passed to Try()
+ *    It will attempt to execute each of them until one of them 
+ *    successfully executes. 
+ *    If none executes successfully, returns null.
+ * 
+ * Returns:
+ * {*} The value returned by the first successfully executed function.
+ */
+OpenLayers.Util.Try = function() {
+    var returnValue = null;
+
+    for (var i = 0; i < arguments.length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) {}
+    }
+
+    return returnValue;
+}
+
+
+/** 
+ * Function: getNodes
+ * 
+ * These could/should be made namespace aware?
+ * 
+ * Parameters:
+ * p - {}
+ * tagName - {String}
+ * 
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util.getNodes=function(p, tagName) {
+    var nodes = OpenLayers.Util.Try(
+        function () {
+            return OpenLayers.Util._getNodes(p.documentElement.childNodes,
+                                            tagName);
+        },
+        function () {
+            return OpenLayers.Util._getNodes(p.childNodes, tagName);
+        }
+    );
+    return nodes;
+};
+
+/**
+ * Function: _getNodes
+ * 
+ * Parameters:
+ * nodes - {Array}
+ * tagName - {String}
+ * 
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util._getNodes=function(nodes, tagName) {
+    var retArray = [];
+    for (var i=0;i<nodes.length;i++) {
+        if (nodes[i].nodeName==tagName) {
+            retArray.push(nodes[i]);
+        }
+    }
+
+    return retArray;
+};
+
+
+
+/**
+ * Function: getTagText
+ * 
+ * Parameters:
+ * parent - {}
+ * item - {String}
+ * index - {Integer}
+ * 
+ * Returns:
+ * {String}
+ */
+OpenLayers.Util.getTagText = function (parent, item, index) {
+    var result = OpenLayers.Util.getNodes(parent, item);
+    if (result && (result.length > 0))
+    {
+        if (!index) {
+            index=0;
+        }
+        if (result[index].childNodes.length > 1) {
+            return result.childNodes[1].nodeValue; 
+        }
+        else if (result[index].childNodes.length == 1) {
+            return result[index].firstChild.nodeValue; 
+        }
+    } else { 
+        return ""; 
+    }
+};
+
+/**
+ * Function: getXmlNodeValue
+ * 
+ * Parameters:
+ * node - {XMLNode}
+ * 
+ * Returns:
+ * {String} The text value of the given node, without breaking in firefox or IE
+ */
+OpenLayers.Util.getXmlNodeValue = function(node) {
+    var val = null;
+    OpenLayers.Util.Try( 
+        function() {
+            val = node.text;
+            if (!val)
+                val = node.textContent;
+            if (!val)
+                val = node.firstChild.nodeValue;
+        }, 
+        function() {
+            val = node.textContent;
+        }); 
+    return val;
+};
+
+/** 
+ * Function: mouseLeft
+ * 
+ * Parameters:
+ * evt - {Event}
+ * div - {HTMLDivElement}
+ * 
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.mouseLeft = function (evt, div) {
+    // start with the element to which the mouse has moved
+    var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
+    // walk up the DOM tree.
+    while (target != div && target != null) {
+        target = target.parentNode;
+    }
+    // if the target we stop at isn't the div, then we've left the div.
+    return (target != div);
+};
+
+/**
+ * Function: rad
+ * 
+ * Parameters:
+ * x - {Float}
+ * 
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
+
+/**
+ * Function: distVincenty
+ * 
+ * Parameters:
+ * p1 - {Float}
+ * p2 - {Float}
+ * 
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.distVincenty=function(p1, p2) {
+    var a = 6378137, b = 6356752.3142,  f = 1/298.257223563;
+    var L = OpenLayers.Util.rad(p2.lon - p1.lon);
+    var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
+    var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
+    var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
+    var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
+    var lambda = L, lambdaP = 2*Math.PI;
+    var iterLimit = 20;
+    while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
+        var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
+        var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
+        (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
+        if (sinSigma==0) return 0;  // co-incident points
+        var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
+        var sigma = Math.atan2(sinSigma, cosSigma);
+        var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
+        var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
+        var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
+        var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
+        lambdaP = lambda;
+        lambda = L + (1-C) * f * Math.sin(alpha) *
+        (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
+    }
+    if (iterLimit==0) return NaN  // formula failed to converge
+    var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
+    var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
+    var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
+    var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+        B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
+    var s = b*A*(sigma-deltaSigma);
+    var d = s.toFixed(3)/1000; // round to 1mm precision
+    return d;
+};
+
+/**
+ * Function: getParameters
+ * Parse the parameters from a URL or from the current page itself into a 
+ *     JavaScript Object. Note that parameter values with commas are separated
+ *     out into an Array.
+ * 
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ *                If null, query string is taken from page location.
+ * 
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getParameters = function(url) {
+    //if no url specified, take it from the location bar
+    url = url || window.location.href
+    if(url == null) {
+        url = window.location.href;
+    }
+
+    //parse out parameters portion of url string
+    var paramsString = "";
+    if (OpenLayers.String.contains(url, '?')) {
+        var start = url.indexOf('?') + 1;
+        var end = OpenLayers.String.contains(url, "#") ?
+                    url.indexOf('#') : url.length;
+        paramsString = url.substring(start, end);
+    }
+        
+    var parameters = {};
+    var pairs = paramsString.split(/[&;]/);
+    for(var i = 0; i < pairs.length; ++i) {
+        var keyValue = pairs[i].split('=');
+        if (keyValue[0]) {
+            var key = decodeURIComponent(keyValue[0]);
+            var value = keyValue[1] || ''; //empty string if no value
+
+            //decode individual values
+            value = value.split(",");
+            for(var j=0; j < value.length; j++) {
+                value[j] = decodeURIComponent(value[j]);
+            }
+
+            //if there's only one value, do not return as array                    
+            if (value.length == 1) {
+                value = value[0];
+            }                
+            
+            parameters[key] = value;
+         }
+     }
+    return parameters;
+};
+
+/**
+ * Function: getArgs
+ * Deprecated - Will be removed in 3.0. 
+ *     Please use instead OpenLayers.Util.getParameters
+ * 
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ *                If null, query string is taken from page location.
+ * 
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getArgs = function(url) {
+    var err = OpenLayers.String.translate("getArgsDeprecated");
+    OpenLayers.Console.warn(err);
+    return OpenLayers.Util.getParameters(url);
+};
+
+/**
+ * Property: lastSeqID
+ * {Integer} The ever-incrementing count variable.
+ *           Used for generating unique ids.
+ */
+OpenLayers.Util.lastSeqID = 0;
+
+/**
+ * Function: createUniqueID
+ * 
+ * Parameters:
+ * prefix {String} String to prefix unique id. 
+ *                 If null, default is "id_"
+ * 
+ * Returns:
+ * {String} A unique id string, built on the passed in prefix
+ */
+OpenLayers.Util.createUniqueID = function(prefix) {
+    if (prefix == null) {
+        prefix = "id_";
+    }
+    OpenLayers.Util.lastSeqID += 1; 
+    return prefix + OpenLayers.Util.lastSeqID;        
+};
+
+/**
+ * Constant: INCHES_PER_UNIT
+ * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
+ */
+OpenLayers.INCHES_PER_UNIT = { 
+    'inches': 1.0,
+    'ft': 12.0,
+    'mi': 63360.0,
+    'm': 39.3701,
+    'km': 39370.1,
+    'dd': 4374754
+};
+OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
+OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
+
+/** 
+ * Constant: DOTS_PER_INCH
+ * {Integer} 72 (A sensible default)
+ */
+OpenLayers.DOTS_PER_INCH = 72;
+
+/**
+ * Function: normalzeScale
+ * 
+ * Parameters:
+ * scale - {float}
+ * 
+ * Returns:
+ * {Float} A normalized scale value, in 1 / X format. 
+ *         This means that if a value less than one ( already 1/x) is passed
+ *         in, it just returns scale directly. Otherwise, it returns 
+ *         1 / scale
+ */
+OpenLayers.Util.normalizeScale = function (scale) {
+    var normScale = (scale > 1.0) ? (1.0 / scale) 
+                                  : scale;
+    return normScale;
+};
+
+/**
+ * Function: getResolutionFromScale
+ * 
+ * Parameters:
+ * scale - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ *                  Default is degrees
+ * 
+ * Returns:
+ * {Float} The corresponding resolution given passed-in scale and unit 
+ *         parameters.
+ */
+OpenLayers.Util.getResolutionFromScale = function (scale, units) {
+
+    if (units == null) {
+        units = "degrees";
+    }
+
+    var normScale = OpenLayers.Util.normalizeScale(scale);
+
+    var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
+                                    * OpenLayers.DOTS_PER_INCH);
+    return resolution;
+};
+
+/**
+ * Function: getScaleFromResolution
+ * 
+ * Parameters:
+ * resolution - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ *                  Default is degrees
+ * 
+ * Returns:
+ * {Float} The corresponding scale given passed-in resolution and unit 
+ *         parameters.
+ */
+OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
+
+    if (units == null) {
+        units = "degrees";
+    }
+
+    var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
+                    OpenLayers.DOTS_PER_INCH;
+    return scale;
+};
+
+/**
+ * Function: safeStopPropagation
+ * Deprecated.
+ * 
+ * This function has been deprecated. Please use directly 
+ *     OpenLayers.Event.stop() passing 'true' as the 2nd 
+ *     argument (preventDefault)
+ * 
+ * Safely stop the propagation of an event *without* preventing
+ *   the default browser action from occurring.
+ * 
+ * Parameter:
+ * evt - {Event}
+ */
+OpenLayers.Util.safeStopPropagation = function(evt) {
+    OpenLayers.Event.stop(evt, true);
+};
+
+/**
+ * Function: pagePositon
+ * Calculates the position of an element on the page. 
+ *
+ * Parameters:
+ * forElement - {DOMElement}
+ * 
+ * Returns:´
+ * {Array} two item array, L value then T value.
+ */
+OpenLayers.Util.pagePosition = function(forElement) {
+    var valueT = 0, valueL = 0;
+
+    var element = forElement;
+    var child = forElement;
+    while(element) {
+
+        if(element == document.body) {
+            if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
+                break;
+            }
+        }
+        
+        valueT += element.offsetTop  || 0;
+        valueL += element.offsetLeft || 0;
+
+        child = element;
+        try {
+            // wrapping this in a try/catch because IE chokes on the offsetParent
+            element = element.offsetParent;
+        } catch(e) {
+            OpenLayers.Console.error(OpenLayers.String.translate(
+                                              "pagePositionFailed",element.id));
+            break;
+        }
+    }
+
+    element = forElement;
+    while(element) {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+        element = element.parentNode;
+    }
+    
+    return [valueL, valueT];
+};
+
+
+/** 
+ * Function: isEquivalentUrl
+ * Test two URLs for equivalence. 
+ * 
+ * Setting 'ignoreCase' allows for case-independent comparison.
+ * 
+ * Comparison is based on: 
+ *  - Protocol
+ *  - Host (evaluated without the port)
+ *  - Port (set 'ignorePort80' to ignore "80" values)
+ *  - Hash ( set 'ignoreHash' to disable)
+ *  - Pathname (for relative <-> absolute comparison) 
+ *  - Arguments (so they can be out of order)
+ *  
+ * Parameters:
+ * url1 - {String}
+ * url2 - {String}
+ * options - {Object} Allows for customization of comparison:
+ *                    'ignoreCase' - Default is True
+ *                    'ignorePort80' - Default is True
+ *                    'ignoreHash' - Default is True
+ *
+ * Returns:
+ * {Boolean} Whether or not the two URLs are equivalent
+ */
+OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
+    options = options || {};
+
+    OpenLayers.Util.applyDefaults(options, {
+        ignoreCase: true,
+        ignorePort80: true,
+        ignoreHash: true
+    });
+
+    urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
+    urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
+
+    //compare all keys (host, port, etc)
+    for(var key in urlObj1) {
+        if (options.test) {
+            alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
+        }
+        var val1 = urlObj1[key];
+        var val2 = urlObj2[key];
+        
+        switch(key) {
+            case "args":
+                //do nothing, they'll be treated below
+                break;
+            case "host":
+            case "port":
+            case "protocol":
+                if ((val1 == "") || (val2 == "")) {
+                    //these will be blank for relative urls, so no need to 
+                    // compare them here -- call break. 
+                    // 
+                    break;
+                } 
+                // otherwise continue with default compare
+                //
+            default: 
+                if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
+                    return false;
+                }
+                break;
+        }
+        
+    }
+
+    // compare search args - irrespective of order
+    for(var key in urlObj1.args) {
+        if(urlObj1.args[key] != urlObj2.args[key]) {
+            return false;
+        }
+        delete urlObj2.args[key];
+    }
+    // urlObj2 shouldn't have any args left
+    for(var key in urlObj2.args) {
+        return false;
+    }
+    
+    return true;
+};
+
+/**
+ * Function: createUrlObject
+ * 
+ * Parameters:
+ * url - {String}
+ * options - {Object} A hash of options.  Can be one of:
+ *            ignoreCase: lowercase url,
+ *            ignorePort80: don't include explicit port if port is 80,
+ *            ignoreHash: Don't include part of url after the hash (#).
+ * 
+ * Returns:
+ * {Object} An object with separate url, a, port, host, and args parsed out 
+ *          and ready for comparison
+ */
+OpenLayers.Util.createUrlObject = function(url, options) {
+    options = options || {};
+
+    var urlObject = {};
+  
+    if (options.ignoreCase) {
+        url = url.toLowerCase(); 
+    }
+
+    var a = document.createElement('a');
+    a.href = url;
+    
+  //host (without port)
+    urlObject.host = a.host;
+    var port = a.port;
+    if (port.length <= 0) {
+        var newHostLength = urlObject.host.length - (port.length);
+        urlObject.host = urlObject.host.substring(0, newHostLength); 
+    }
+
+  //protocol
+    urlObject.protocol = a.protocol;  
+
+  //port
+    urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
+                                                                     
+  //hash
+    urlObject.hash = (options.ignoreHash) ? "" : a.hash;  
+    
+  //args
+    var queryString = a.search;
+    if (!queryString) {
+        var qMark = url.indexOf("?");
+        queryString = (qMark != -1) ? url.substr(qMark) : "";
+    }
+    urlObject.args = OpenLayers.Util.getParameters(queryString);
+
+
+  //pathname (this part allows for relative <-> absolute comparison)
+    if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) || 
+         ((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
+
+        urlObject.pathname = a.pathname;  
+
+        //Test to see if the pathname includes the arguments (Opera)
+        var qIndex = urlObject.pathname.indexOf("?");
+        if (qIndex != -1) {
+            urlObject.pathname = urlObject.pathname.substring(0, qIndex);
+        }
+
+    } else {
+        var relStr = OpenLayers.Util.removeTail(url);
+
+        var backs = 0;
+        do {
+            var index = relStr.indexOf("../");
+
+            if (index == 0) {
+                backs++
+                relStr = relStr.substr(3);
+            } else if (index >= 0) {
+                var prevChunk = relStr.substr(0,index - 1);
+                
+                var slash = prevChunk.indexOf("/");
+                prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
+                                          : "";
+                
+                var postChunk = relStr.substr(index + 3);                
+                relStr = prevChunk + postChunk;
+            }
+        } while(index != -1)
+
+        var windowAnchor = document.createElement("a");
+        var windowUrl = window.location.href;
+        if (options.ignoreCase) {
+            windowUrl = windowUrl.toLowerCase();
+        }
+        windowAnchor.href = windowUrl;
+
+      //set protocol of window
+        urlObject.protocol = windowAnchor.protocol;
+
+        var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
+        var dirs = windowAnchor.pathname.split(splitter);
+        dirs.pop(); //remove filename
+        while ((backs > 0) && (dirs.length > 0)) {
+            dirs.pop();
+            backs--;
+        }
+        relStr = dirs.join("/") + "/"+ relStr;
+        urlObject.pathname = relStr;
+    }
+    
+    if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
+        urlObject.host = "localhost";
+    }
+
+    return urlObject; 
+};
+ 
+/**
+ * Function: removeTail
+ * Takes a url and removes everything after the ? and #
+ * 
+ * Parameters:
+ * url - {String} The url to process
+ * 
+ * Returns:
+ * {String} The string with all queryString and Hash removed
+ */
+OpenLayers.Util.removeTail = function(url) {
+    var head = null;
+    
+    var qMark = url.indexOf("?");
+    var hashMark = url.indexOf("#");
+
+    if (qMark == -1) {
+        head = (hashMark != -1) ? url.substr(0,hashMark) : url;
+    } else {
+        head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) 
+                                  : url.substr(0, qMark);
+    }
+    return head;
+};
+
+
+/**
+ * Function: getBrowserName
+ * 
+ * Returns:
+ * {String} A string which specifies which is the current 
+ *          browser in which we are running. 
+ * 
+ *          Currently-supported browser detection and codes:
+ *           * 'opera' -- Opera
+ *           * 'msie'  -- Internet Explorer
+ *           * 'safari' -- Safari
+ *           * 'firefox' -- FireFox
+ *           * 'mozilla' -- Mozilla
+ * 
+ *          If we are unable to property identify the browser, we 
+ *           return an empty string.
+ */
+OpenLayers.Util.getBrowserName = function() {
+    var browserName = "";
+    
+    var ua = navigator.userAgent.toLowerCase();
+    if ( ua.indexOf( "opera" ) != -1 ) {
+        browserName = "opera";
+    } else if ( ua.indexOf( "msie" ) != -1 ) {
+        browserName = "msie";
+    } else if ( ua.indexOf( "safari" ) != -1 ) {
+        browserName = "safari";
+    } else if ( ua.indexOf( "mozilla" ) != -1 ) {
+        if ( ua.indexOf( "firefox" ) != -1 ) {
+            browserName = "firefox";
+        } else {
+            browserName = "mozilla";
+        }
+    }
+    
+    return browserName;
+};
+/* ======================================================================
+    OpenLayers/Console.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Console
+ * The OpenLayers.Console namespace is used for debugging and error logging.
+ * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
+ * calls to OpenLayers.Console methods will get redirected to window.console.
+ * This makes use of the Firebug extension where available and allows for
+ * cross-browser debugging Firebug style.
+ *
+ * Note:
+ * Note that behavior will differ with the Firebug extention and Firebug Lite.
+ * Most notably, the Firebug Lite console does not currently allow for
+ * hyperlinks to code or for clicking on object to explore their properties.
+ * 
+ */
+OpenLayers.Console = {
+    /**
+     * Create empty functions for all console methods.  The real value of these
+     * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
+     * included.  We explicitly require the Firebug Lite script to trigger
+     * functionality of the OpenLayers.Console methods.
+     */
+    
+    /**
+     * APIFunction: log
+     * Log an object in the console.  The Firebug Lite console logs string
+     * representation of objects.  Given multiple arguments, they will
+     * be cast to strings and logged with a space delimiter.  If the first
+     * argument is a string with printf-like formatting, subsequent arguments
+     * will be used in string substitution.  Any additional arguments (beyond
+     * the number substituted in a format string) will be appended in a space-
+     * delimited line.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    log: function() {},
+
+    /**
+     * APIFunction: debug
+     * Writes a message to the console, including a hyperlink to the line
+     * where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    debug: function() {},
+
+    /**
+     * APIFunction: info
+     * Writes a message to the console with the visual "info" icon and color
+     * coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    info: function() {},
+
+    /**
+     * APIFunction: warn
+     * Writes a message to the console with the visual "warning" icon and
+     * color coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    warn: function() {},
+
+    /**
+     * APIFunction: error
+     * Writes a message to the console with the visual "error" icon and color
+     * coding and a hyperlink to the line where it was called.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    error: function() {},
+
+    /**
+     * APIFunction: assert
+     * Tests that an expression is true. If not, it will write a message to
+     * the console and throw an exception.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    assert: function() {},
+
+    /**
+     * APIFunction: dir
+     * Prints an interactive listing of all properties of the object. This
+     * looks identical to the view that you would see in the DOM tab.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    dir: function() {},
+
+    /**
+     * APIFunction: dirxml
+     * Prints the XML source tree of an HTML or XML element. This looks
+     * identical to the view that you would see in the HTML tab. You can click
+     * on any node to inspect it in the HTML tab.
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    dirxml: function() {},
+
+    /**
+     * APIFunction: trace
+     * Prints an interactive stack trace of JavaScript execution at the point
+     * where it is called.  The stack trace details the functions on the stack,
+     * as well as the values that were passed as arguments to each function.
+     * You can click each function to take you to its source in the Script tab,
+     * and click each argument value to inspect it in the DOM or HTML tabs.
+     * 
+     */
+    trace: function() {},
+
+    /**
+     * APIFunction: group
+     * Writes a message to the console and opens a nested block to indent all
+     * future messages sent to the console. Call OpenLayers.Console.groupEnd()
+     * to close the block.
+     *
+     * May be called with multiple arguments as with OpenLayers.Console.log().
+     * 
+     * Parameters:
+     * object - {Object}
+     */
+    group: function() {},
+
+    /**
+     * APIFunction: groupEnd
+     * Closes the most recently opened block created by a call to
+     * OpenLayers.Console.group
+     */
+    groupEnd: function() {},
+    
+    /**
+     * APIFunction: time
+     * Creates a new timer under the given name. Call
+     * OpenLayers.Console.timeEnd(name)
+     * with the same name to stop the timer and print the time elapsed.
+     *
+     * Parameters:
+     * name - {String}
+     */
+    time: function() {},
+
+    /**
+     * APIFunction: timeEnd
+     * Stops a timer created by a call to OpenLayers.Console.time(name) and
+     * writes the time elapsed.
+     *
+     * Parameters:
+     * name - {String}
+     */
+    timeEnd: function() {},
+
+    /**
+     * APIFunction: profile
+     * Turns on the JavaScript profiler. The optional argument title would
+     * contain the text to be printed in the header of the profile report.
+     *
+     * This function is not currently implemented in Firebug Lite.
+     * 
+     * Parameters:
+     * title - {String} Optional title for the profiler
+     */
+    profile: function() {},
+
+    /**
+     * APIFunction: profileEnd
+     * Turns off the JavaScript profiler and prints its report.
+     * 
+     * This function is not currently implemented in Firebug Lite.
+     */
+    profileEnd: function() {},
+
+    /**
+     * APIFunction: count
+     * Writes the number of times that the line of code where count was called
+     * was executed. The optional argument title will print a message in
+     * addition to the number of the count.
+     *
+     * This function is not currently implemented in Firebug Lite.
+     *
+     * Parameters:
+     * title - {String} Optional title to be printed with count
+     */
+    count: function() {},
+
+    CLASS_NAME: "OpenLayers.Console"
+};
+
+/**
+ * Execute an anonymous function to extend the OpenLayers.Console namespace
+ * if the firebug.js script is included.  This closure is used so that the
+ * "scripts" and "i" variables don't pollute the global namespace.
+ */
+(function() {
+    /**
+     * If Firebug Lite is included (before this script), re-route all
+     * OpenLayers.Console calls to the console object.
+     */
+    if(window.console) {
+        var scripts = document.getElementsByTagName("script");
+        for(var i=0; i<scripts.length; ++i) {
+            if(scripts[i].src.indexOf("firebug.js") != -1) {
+                OpenLayers.Util.extend(OpenLayers.Console, console);
+                break;
+            }
+        }
+    }
+})();
+/* ======================================================================
+    OpenLayers/BaseTypes.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/BaseTypes/LonLat.js
+ * @requires OpenLayers/BaseTypes/Size.js
+ * @requires OpenLayers/BaseTypes/Pixel.js
+ * @requires OpenLayers/BaseTypes/Bounds.js
+ * @requires OpenLayers/BaseTypes/Element.js
+ * @requires OpenLayers/Strings/en.js
+ * 
+ * Header: OpenLayers Base Types
+ * OpenLayers custom string, number and function functions are described here.
+ */
+
+/*********************
+ *                   *
+ *      STRING       * 
+ *                   * 
+ *********************/
+
+OpenLayers.String = {
+    /**
+     * APIMethod: OpenLayers.String.startsWith
+     * Test whether a string starts with another string. 
+     * 
+     * Parameters:
+     * str - {String} The string to test.
+     * sub - {Sring} The substring to look for.
+     *  
+     * Returns:
+     * {Boolean} The first string starts with the second.
+     */
+    startsWith: function(str, sub) {
+        return (str.indexOf(sub) == 0);
+    },
+
+    /**
+     * APIMethod: OpenLayers.String.contains
+     * Test whether a string contains another string.
+     * 
+     * Parameters:
+     * str - {String} The string to test.
+     * sub - {String} The substring to look for.
+     * 
+     * Returns:
+     * {Boolean} The first string contains the second.
+     */
+    contains: function(str, sub) {
+        return (str.indexOf(sub) != -1);
+    },
+    
+    /**
+     * APIMethod: OpenLayers.String.trim
+     * Removes leading and trailing whitespace characters from a string.
+     * 
+     * Parameters:
+     * str - {String} The (potentially) space padded string.  This string is not
+     *     modified.
+     * 
+     * Returns:
+     * {String} A trimmed version of the string with all leading and 
+     *     trailing spaces removed.
+     */
+    trim: function(str) {
+        return str.replace(/^\s*(.*?)\s*$/, "$1");    
+    },
+    
+    /**
+     * APIMethod: OpenLayers.String.camelize
+     * Camel-case a hyphenated string. 
+     *     Ex. "chicken-head" becomes "chickenHead", and
+     *     "-chicken-head" becomes "ChickenHead".
+     *
+     * Parameters:
+     * str - {String} The string to be camelized.  The original is not modified.
+     * 
+     * Returns:
+     * {String} The string, camelized
+     */
+    camelize: function(str) {
+        var oStringList = str.split('-');
+        var camelizedString = oStringList[0];
+        for (var i = 1; i < oStringList.length; i++) {
+            var s = oStringList[i];
+            camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+        }
+        return camelizedString;
+    },
+    
+    langCode: (OpenLayers.Util.getBrowserName() == "msie") ?
+                  navigator.userLanguage.substring(0,2)://only use the prefix part for now, 
+                  navigator.language.substring(0,2),    //e.g. en-CA becomes just en
+    defaultLangCode: 'en',
+    
+    /**
+     * APIMethod: OpenLayers.String.translate
+     * uses the key into a dictionary of values based on the current language string.
+     * any number of additional arguments. If additional arguments are passed,
+     *  they will be interpolated in the string in order.
+     * 
+     * Parameters:
+     * key - {String} The key for an i18n string value in the dictionary
+     * 
+     * Returns:
+     * {String} A internationalized string
+     */
+    translate: function(key) {
+      var langCode = OpenLayers.String.langCode;
+      if (!OpenLayers.Strings[langCode]) {
+        var msg = 'failed to find ' +OpenLayers.String.langCode+ ' dictionary, falling back to default language';
+        OpenLayers.Console.log(msg);
+        OpenLayers.Strings[langCode] = OpenLayers.Strings[OpenLayers.String.defaultLangCode];
+        langCode = OpenLayers.String.defaultLangCode;
+      }
+      
+      var dictionary = OpenLayers.Strings[langCode];
+      var message = "NoMsgsFound";
+      var msgValue = dictionary[key];
+      if (!msgValue) {
+        // Message not found, fall back to message key
+        message = key;
+      } else {
+        // Message found; pick last one so user can override messages
+        message = msgValue;
+        if (arguments[this.translate.length]) {
+          // Extra arguments, format message
+          var varArgs = [].slice.call(arguments, this.translate.length);
+          varArgs.unshift(message);
+          message = this.formatMessage.apply(this, varArgs);
+        }
+      }
+      return message;
+    },
+    
+  /**
+     * APIMethod: OpenLayers.String.formatMessage
+     * Formats a message template with the extra arguments. 
+     * E.g. if called as: <code>OpenLayers.String.formatMessage("{1} is {0} {2}, {1}", "a good", "this", "test")</code>
+     * the formatted message returned is: <code>"this is a good test, this"</code>
+     *
+     * Parameters:
+     * messageTemplate  the message format string
+     * args       optional extra parameters for formatting the message
+     *
+     * Returns:
+     * the formatted message
+     */
+    formatMessage: function(messageTemplate)
+    {
+      var message = messageTemplate;
+      var varArgs = [].slice.call(arguments, this.formatMessage.length);
+      for (var i in varArgs) {
+        var parm = new RegExp("\\{" + i + "\\}", "g");
+        message = message.replace(parm, varArgs[i]);
+      }
+      return message;
+    }
+};
+
+/**
+ * Header: OpenLayers Strings
+ * OpenLayers I18n strings in various langauges.  Default language is English, langcode='en'
+ */
+OpenLayers.Strings = {};
+
+if (!String.prototype.startsWith) {
+    /**
+     * APIMethod: String.startsWith
+     * *Deprecated*. Whether or not a string starts with another string. 
+     * 
+     * Parameters:
+     * sStart - {Sring} The string we're testing for.
+     *  
+     * Returns:
+     * {Boolean} Whether or not this string starts with the string passed in.
+     */
+    String.prototype.startsWith = function(sStart) {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                              "OpenLayers.String.startsWith"));
+        return OpenLayers.String.startsWith(this, sStart);
+    };
+}
+
+if (!String.prototype.contains) {
+    /**
+     * APIMethod: String.contains
+     * *Deprecated*. Whether or not a string contains another string.
+     * 
+     * Parameters:
+     * str - {String} The string that we're testing for.
+     * 
+     * Returns:
+     * {Boolean} Whether or not this string contains with the string passed in.
+     */
+    String.prototype.contains = function(str) {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                              "OpenLayers.String.contains"));
+        return OpenLayers.String.contains(this, str);
+    };
+}
+
+if (!String.prototype.trim) {
+    /**
+     * APIMethod: String.trim
+     * *Deprecated*. Removes leading and trailing whitespace characters from a string.
+     * 
+     * Returns:
+     * {String} A trimmed version of the string - all leading and 
+     *          trailing spaces removed
+     */
+    String.prototype.trim = function() {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                              "OpenLayers.String.trim"));
+        return OpenLayers.String.trim(this);
+    };
+}
+
+if (!String.prototype.camelize) {
+    /**
+     * APIMethod: String.camelize
+     * *Deprecated*. Camel-case a hyphenated string. 
+     *     Ex. "chicken-head" becomes "chickenHead", and
+     *     "-chicken-head" becomes "ChickenHead".
+     * 
+     * Returns:
+     * {String} The string, camelized
+     */
+    String.prototype.camelize = function() {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                              "OpenLayers.String.camelize"));
+        return OpenLayers.String.camelize(this);
+    };
+}
+
+/*********************
+ *                   *
+ *      NUMBER       * 
+ *                   * 
+ *********************/
+
+OpenLayers.Number = {
+    /**
+     * APIMethod: OpenLayers.Number.limitSigDigs
+     * Limit the number of significant digits on an integer.
+     * 
+     * Parameters:
+     * num - {Integer}
+     * sig - {Integer}
+     * 
+     * Returns:
+     * {Integer} The number, rounded to the specified number of significant
+     *     digits.
+     */
+    limitSigDigs: function(num, sig) {
+        var fig;
+        if(sig > 0) {
+            fig = parseFloat(num.toPrecision(sig));
+        } else {
+            fig = 0;
+        }
+        return fig;
+    }
+};
+
+if (!Number.prototype.limitSigDigs) {
+    /**
+     * APIMethod: Number.limitSigDigs
+     * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
+     *     work with floats!
+     * 
+     * Parameters:
+     * sig - {Integer}
+     * 
+     * Returns:
+     * {Integer} The number, rounded to the specified number of significant digits.
+     *           If null, 0, or negative value passed in, returns 0
+     */
+    Number.prototype.limitSigDigs = function(sig) {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                            "OpenLayers.Number.limitSigDigs"));
+        return OpenLayers.Number.limitSigDigs(this, sig);
+    };
+}
+
+/*********************
+ *                   *
+ *      FUNCTION     * 
+ *                   * 
+ *********************/
+
+OpenLayers.Function = {
+    /**
+     * APIMethod: OpenLayers.Function.bind
+     * Bind a function to an object.  Method to easily create closures with
+     *     'this' altered.
+     * 
+     * Parameters:
+     * func - {Function} Input function.
+     * object - {Object} The object to bind to the input function (as this).
+     * 
+     * Returns:
+     * {Function} A closure with 'this' set to the passed in object.
+     */
+    bind: function(func, object) {
+        // create a reference to all arguments past the second one
+        var args = Array.prototype.slice.apply(arguments, [2]);
+        return function() {
+            // Push on any additional arguments from the actual function call.
+            // These will come after those sent to the bind call.
+            var newArgs = args.concat(
+                Array.prototype.slice.apply(arguments, [0])
+            );
+            return func.apply(object, newArgs);
+        };
+    },
+    
+    /**
+     * APIMethod: OpenLayers.Function.bindAsEventListener
+     * Bind a function to an object, and configure it to receive the event
+     *     object as first parameter when called. 
+     * 
+     * Parameters:
+     * func - {Function} Input function to serve as an event listener.
+     * object - {Object} A reference to this.
+     * 
+     * Returns:
+     * {Function}
+     */
+    bindAsEventListener: function(func, object) {
+        return function(event) {
+            return func.call(object, event || window.event);
+        };
+    }
+};
+
+if (!Function.prototype.bind) {
+    /**
+     * APIMethod: Function.bind
+     * *Deprecated*. Bind a function to an object. 
+     * Method to easily create closures with 'this' altered.
+     * 
+     * Parameters:
+     * object - {Object} the this parameter
+     * 
+     * Returns:
+     * {Function} A closure with 'this' altered to the first
+     *            argument.
+     */
+    Function.prototype.bind = function() {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                              "OpenLayers.Function.bind"));
+        // new function takes the same arguments with this function up front
+        Array.prototype.unshift.apply(arguments, [this]);
+        return OpenLayers.Function.bind.apply(null, arguments);
+    };
+}
+
+if (!Function.prototype.bindAsEventListener) {
+    /**
+     * APIMethod: Function.bindAsEventListener
+     * *Deprecated*. Bind a function to an object, and configure it to receive the
+     *     event object as first parameter when called. 
+     * 
+     * Parameters:
+     * object - {Object} A reference to this.
+     * 
+     * Returns:
+     * {Function}
+     */
+    Function.prototype.bindAsEventListener = function(object) {
+        OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
+                                    "OpenLayers.Function.bindAsEventListener"));
+        return OpenLayers.Function.bindAsEventListener(this, object);
+    };
+}
+/* ======================================================================
+    OpenLayers/BaseTypes/Class.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Constructor: OpenLayers.Class
+ * Base class used to construct all other classes. Includes support for 
+ *     multiple inheritance. 
+ *     
+ * This constructor is new in OpenLayers 2.5.  At OpenLayers 3.0, the old 
+ *     syntax for creating classes and dealing with inheritance 
+ *     will be removed.
+ * 
+ * To create a new OpenLayers-style class, use the following syntax:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ *     following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ *
+ */
+OpenLayers.Class = function() {
+    var Class = function() {
+        /**
+         * This following condition can be removed at 3.0 - this is only for
+         * backwards compatibility while the Class.inherit method is still
+         * in use.  So at 3.0, the following three lines would be replaced with
+         * simply:
+         * this.initialize.apply(this, arguments);
+         */
+        if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+            this.initialize.apply(this, arguments);
+        }
+    }
+    var extended = {};
+    var parent;
+    for(var i=0; i<arguments.length; ++i) {
+        if(typeof arguments[i] == "function") {
+            // get the prototype of the superclass
+            parent = arguments[i].prototype;
+        } else {
+            // in this case we're extending with the prototype
+            parent = arguments[i];
+        }
+        OpenLayers.Util.extend(extended, parent);
+    }
+    Class.prototype = extended;
+    return Class;
+}
+
+/**
+ * Property: isPrototype
+ * *Deprecated*.  This is no longer needed and will be removed at 3.0.
+ */
+OpenLayers.Class.isPrototype = function () {};
+
+/**
+ * APIFunction: OpenLayers.create
+ * *Deprecated*.  Old method to create an OpenLayers style class.  Use the
+ *     <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
+ */
+OpenLayers.Class.create = function() {
+    return function() {
+        if (arguments && arguments[0] != OpenLayers.Class.isPrototype)
+            this.initialize.apply(this, arguments);
+    }
+}
+
+
+/**
+ * APIFunction: inherit
+ * *Deprecated*.  Old method to inherit from one or more OpenLayers style
+ *     classes.  Use the <OpenLayers.Class> constructor instead.
+ *
+ * Parameters:
+ * class - One or more classes can be provided as arguments
+ *
+ * Returns:
+ * An object prototype
+ */
+OpenLayers.Class.inherit = function () {
+    var superClass = arguments[0];
+    var proto = new superClass(OpenLayers.Class.isPrototype);
+    for (var i = 1; i < arguments.length; i++) {
+        if (typeof arguments[i] == "function") {
+            var mixin = arguments[i];
+            arguments[i] = new mixin(OpenLayers.Class.isPrototype);
+        }
+        OpenLayers.Util.extend(proto, arguments[i]);
+    }
+    return proto;
+}
+/* ======================================================================
+    OpenLayers/BaseTypes/Size.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
+ */
+OpenLayers.Size = OpenLayers.Class({
+
+    /**
+     * APIProperty: w
+     * {Number} width
+     */
+    w: 0.0,
+    
+    /**
+     * APIProperty: h
+     * {Number} height
+     */
+    h: 0.0,
+
+
+    /**
+     * Constructor: OpenLayers.Size
+     * Create an instance of OpenLayers.Size
+     *
+     * Parameters:
+     * w - {Number} width
+     * h - {Number} height
+     */
+    initialize: function(w, h) {
+        this.w = parseFloat(w);
+        this.h = parseFloat(h);
+    },
+
+    /**
+     * Method: toString
+     * Return the string representation of a size object
+     *
+     * Returns:
+     * {String} The string representation of OpenLayers.Size object. 
+     * (ex. <i>"w=55,h=66"</i>)
+     */
+    toString:function() {
+        return ("w=" + this.w + ",h=" + this.h);
+    },
+
+    /**
+     * APIMethod: clone
+     * Create a clone of this size object
+     *
+     * Returns:
+     * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+     * values
+     */
+    clone:function() {
+        return new OpenLayers.Size(this.w, this.h);
+    },
+
+    /**
+     *
+     * APIMethod: equals
+     * Determine where this size is equal to another
+     *
+     * Parameters:
+     * sz - {<OpenLayers.Size>}
+     *
+     * Returns: 
+     * {Boolean} The passed in size has the same h and w properties as this one.
+     * Note that if sz passed in is null, returns false.
+     *
+     */
+    equals:function(sz) {
+        var equals = false;
+        if (sz != null) {
+            equals = ((this.w == sz.w && this.h == sz.h) ||
+                      (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
+        }
+        return equals;
+    },
+
+    CLASS_NAME: "OpenLayers.Size"
+});
+/* ======================================================================
+    OpenLayers/BaseTypes/Bounds.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Class: OpenLayers.Bounds
+ * Instances of this class represent bounding boxes.  Data stored as left,
+ * bottom, right, top floats. All values are initialized to null, however,
+ * you should make sure you set them before using the bounds for anything.
+ * 
+ * Possible use case:
+ * > bounds = new OpenLayers.Bounds();
+ * > bounds.extend(new OpenLayers.LonLat(4,5));
+ * > bounds.extend(new OpenLayers.LonLat(5,6));
+ * > bounds.toBBOX(); // returns 4,5,5,6
+ */
+OpenLayers.Bounds = OpenLayers.Class({
+
+    /**
+     * Property: left
+     * {Number}
+     */
+    left: null,
+
+    /**
+     * Property: bottom
+     * {Number}
+     */
+    bottom: null,
+
+    /**
+     * Property: right
+     * {Number}
+     */
+    right: null,
+
+    /**
+     * Property: top
+     * {Number}
+     */
+    top: null,    
+
+    /**
+     * Constructor: OpenLayers.Bounds
+     * Construct a new bounds object.
+     *
+     * Parameters:
+     * left - {Number} The left bounds of the box.  Note that for width
+     *        calculations, this is assumed to be less than the right value.
+     * bottom - {Number} The bottom bounds of the box.  Note that for height
+     *          calculations, this is assumed to be more than the top value.
+     * right - {Number} The right bounds.
+     * top - {Number} The top bounds.
+     */
+    initialize: function(left, bottom, right, top) {
+        if (left != null) {
+            this.left = parseFloat(left);
+        }
+        if (bottom != null) {
+            this.bottom = parseFloat(bottom);
+        }
+        if (right != null) {
+            this.right = parseFloat(right);
+        }
+        if (top != null) {
+            this.top = parseFloat(top);
+        }
+    },
+
+    /**
+     * Method: clone
+     * Create a cloned instance of this bounds.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} A fresh copy of the bounds
+     */
+    clone:function() {
+        return new OpenLayers.Bounds(this.left, this.bottom, 
+                                     this.right, this.top);
+    },
+
+    /**
+     * Method: equals
+     * Test a two bounds for equivalence.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {Boolean} The passed-in bounds object has the same left,
+     *           right, top, bottom components as this.  Note that if bounds 
+     *           passed in is null, returns false.
+     */
+    equals:function(bounds) {
+        var equals = false;
+        if (bounds != null) {
+            equals = ((this.left == bounds.left) && 
+                      (this.right == bounds.right) &&
+                      (this.top == bounds.top) && 
+                      (this.bottom == bounds.bottom));
+        }
+        return equals;
+    },
+
+    /** 
+     * APIMethod: toString
+     * 
+     * Returns:
+     * {String} String representation of bounds object. 
+     *          (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
+     */
+    toString:function() {
+        return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+                 + " right-top=(" + this.right + "," + this.top + ")" );
+    },
+
+    /**
+     * APIMethod: toArray
+     *
+     * Returns:
+     * {Array} array of left, bottom, right, top
+     */
+    toArray: function() {
+        return [this.left, this.bottom, this.right, this.top];
+    },    
+
+    /** 
+     * APIMethod: toBBOX
+     * 
+     * Parameters:
+     * decimal - {Integer} How many significant digits in the bbox coords?
+     *                     Default is 6
+     * 
+     * Returns:
+     * {String} Simple String representation of bounds object.
+     *          (ex. <i>"5,42,10,45"</i>)
+     */
+    toBBOX:function(decimal) {
+        if (decimal== null) {
+            decimal = 6; 
+        }
+        var mult = Math.pow(10, decimal);
+        var bbox = Math.round(this.left * mult) / mult + "," + 
+                   Math.round(this.bottom * mult) / mult + "," + 
+                   Math.round(this.right * mult) / mult + "," + 
+                   Math.round(this.top * mult) / mult;
+
+        return bbox;
+    },
+    
+    /**
+     * APIMethod: getWidth
+     * 
+     * Returns:
+     * {Float} The width of the bounds
+     */
+    getWidth:function() {
+        return (this.right - this.left);
+    },
+
+    /**
+     * APIMethod: getHeight
+     * 
+     * Returns:
+     * {Float} The height of the bounds (top minus bottom).
+     */
+    getHeight:function() {
+        return (this.top - this.bottom);
+    },
+
+    /**
+     * APIMethod: getSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} The size of the box.
+     */
+    getSize:function() {
+        return new OpenLayers.Size(this.getWidth(), this.getHeight());
+    },
+
+    /**
+     * APIMethod: getCenterPixel
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
+     */
+    getCenterPixel:function() {
+        return new OpenLayers.Pixel( (this.left + this.right) / 2,
+                                     (this.bottom + this.top) / 2);
+    },
+
+    /**
+     * APIMethod: getCenterLonLat
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} The center of the bounds in map space.
+     */
+    getCenterLonLat:function() {
+        return new OpenLayers.LonLat( (this.left + this.right) / 2,
+                                      (this.bottom + this.top) / 2);
+    },
+
+    /**
+     * APIMethod: add
+     * 
+     * Parameters:
+     * x - {Float}
+     * y - {Float}
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
+     *     this, but shifted by the passed-in x and y values.
+     */
+    add:function(x, y) {
+        if ( (x == null) || (y == null) ) {
+            var msg = OpenLayers.String.translate("boundsAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.Bounds(this.left + x, this.bottom + y,
+                                     this.right + x, this.top + y);
+    },
+    
+    /**
+     * APIMethod: extend
+     * Extend the bounds to include the point, lonlat, or bounds specified.
+     *     Note, this function assumes that left < right and bottom < top.
+     * 
+     * Parameters: 
+     * object - {Object} Can be LonLat, Point, or Bounds
+     */
+    extend:function(object) {
+        var bounds = null;
+        if (object) {
+            switch(object.CLASS_NAME) {
+                case "OpenLayers.LonLat":    
+                    bounds = new OpenLayers.Bounds(object.lon, object.lat,
+                                                    object.lon, object.lat);
+                    break;
+                case "OpenLayers.Geometry.Point":
+                    bounds = new OpenLayers.Bounds(object.x, object.y,
+                                                    object.x, object.y);
+                    break;
+                    
+                case "OpenLayers.Bounds":    
+                    bounds = object;
+                    break;
+            }
+    
+            if (bounds) {
+                if ( (this.left == null) || (bounds.left < this.left)) {
+                    this.left = bounds.left;
+                }
+                if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
+                    this.bottom = bounds.bottom;
+                } 
+                if ( (this.right == null) || (bounds.right > this.right) ) {
+                    this.right = bounds.right;
+                }
+                if ( (this.top == null) || (bounds.top > this.top) ) { 
+                    this.top = bounds.top;
+                }
+            }
+        }
+    },
+
+    /**
+     * APIMethod: containsLonLat
+     * 
+     * Parameters:
+     * ll - {<OpenLayers.LonLat>}
+     * inclusive - {Boolean} Whether or not to include the border.
+     *     Default is true.
+     *
+     * Returns:
+     * {Boolean} The passed-in lonlat is within this bounds.
+     */
+    containsLonLat:function(ll, inclusive) {
+        return this.contains(ll.lon, ll.lat, inclusive);
+    },
+
+    /**
+     * APIMethod: containsPixel
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     * inclusive - {Boolean} Whether or not to include the border. Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} The passed-in pixel is within this bounds.
+     */
+    containsPixel:function(px, inclusive) {
+        return this.contains(px.x, px.y, inclusive);
+    },
+    
+    /**
+     * APIMethod: contains
+     * 
+     * Parameters:
+     * x - {Float}
+     * y - {Float}
+     * inclusive - {Boolean} Whether or not to include the border. Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} Whether or not the passed-in coordinates are within this
+     *     bounds.
+     */
+    contains:function(x, y, inclusive) {
+    
+        //set default
+        if (inclusive == null) {
+            inclusive = true;
+        }
+        
+        var contains = false;
+        if (inclusive) {
+            contains = ((x >= this.left) && (x <= this.right) && 
+                        (y >= this.bottom) && (y <= this.top));
+        } else {
+            contains = ((x > this.left) && (x < this.right) && 
+                        (y > this.bottom) && (y < this.top));
+        }              
+        return contains;
+    },
+
+    /**
+     * APIMethod: intersectsBounds
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * inclusive - {<Boolean>} Whether or not to include the border.  Default
+     *     is true.
+     *
+     * Returns:
+     * {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
+     *     Simple math just check if either contains the other, allowing for
+     *     partial.
+     */
+    intersectsBounds:function(bounds, inclusive) {
+
+        if (inclusive == null) {
+            inclusive = true;
+        }
+        var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+                    true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) || 
+                           ((this.bottom > bounds.bottom) && (this.bottom < bounds.top))); 
+        var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+                    true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
+                           ((this.top > bounds.bottom) && (this.top < bounds.top))); 
+        var inRight = (bounds.right == this.right && bounds.left == this.left) ?
+                    true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
+                           ((this.right > bounds.left) && (this.right < bounds.right))); 
+        var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
+                    true : (((bounds.left > this.left) && (bounds.left < this.right)) || 
+                           ((this.left > bounds.left) && (this.left < bounds.right))); 
+
+        return (this.containsBounds(bounds, true, inclusive) ||
+                bounds.containsBounds(this, true, inclusive) ||
+                ((inTop || inBottom ) && (inLeft || inRight )));
+    },
+    
+    /**
+     * APIMethod: containsBounds
+     * 
+     * bounds - {<OpenLayers.Bounds>}
+     * partial - {<Boolean>} If true, only part of passed-in bounds needs be
+     *     within this bounds.  If false, the entire passed-in bounds must be
+     *     within. Default is false
+     * inclusive - {<Boolean>} Whether or not to include the border. Default is
+     *     true.
+     *
+     * Returns:
+     * {Boolean} The passed-in bounds object is contained within this bounds. 
+     */
+    containsBounds:function(bounds, partial, inclusive) {
+
+        //set defaults
+        if (partial == null) {
+            partial = false;
+        }
+        if (inclusive == null) {
+            inclusive = true;
+        }
+
+        var inLeft;
+        var inTop;
+        var inRight;
+        var inBottom;
+        
+        if (inclusive) {
+            inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
+            inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
+            inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
+            inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
+        } else {
+            inLeft = (bounds.left > this.left) && (bounds.left < this.right);
+            inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
+            inRight= (bounds.right > this.left) && (bounds.right < this.right);
+            inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
+        }
+        
+        return (partial) ? (inTop || inBottom ) && (inLeft || inRight ) 
+                         : (inTop && inLeft && inBottom && inRight);
+    },
+
+    /** 
+     * APIMethod: determineQuadrant
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
+     *     coordinate lies.
+     */
+    determineQuadrant: function(lonlat) {
+    
+        var quadrant = "";
+        var center = this.getCenterLonLat();
+        
+        quadrant += (lonlat.lat < center.lat) ? "b" : "t";
+        quadrant += (lonlat.lon < center.lon) ? "l" : "r";
+    
+        return quadrant; 
+    },
+
+    /**
+     * APIMethod: wrapDateLine
+     *  
+     * Parameters:
+     * maxExtent - {<OpenLayers.Bounds>}
+     * options - {Object} Some possible options are:
+     *                    leftTolerance - {float} Allow for a margin of error 
+     *                                            with the 'left' value of this 
+     *                                            bound.
+     *                                            Default is 0.
+     *                    rightTolerance - {float} Allow for a margin of error 
+     *                                             with the 'right' value of 
+     *                                             this bound.
+     *                                             Default is 0.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
+     *                       maxExtent). Note that this function only returns 
+     *                       a different bounds value if this bounds is 
+     *                       *entirely* outside of the maxExtent. If this 
+     *                       bounds straddles the dateline (is part in/part 
+     *                       out of maxExtent), the returned bounds will be 
+     *                       merely a copy of this one.
+     */
+    wrapDateLine: function(maxExtent, options) {    
+        options = options || {};
+        
+        var leftTolerance = options.leftTolerance || 0;
+        var rightTolerance = options.rightTolerance || 0;
+
+        var newBounds = this.clone();
+    
+        if (maxExtent) {
+
+           //shift right?
+           while ( newBounds.left < maxExtent.left && 
+                   (newBounds.right - rightTolerance) <= maxExtent.left ) { 
+                newBounds = newBounds.add(maxExtent.getWidth(), 0);
+           }
+
+           //shift left?
+           while ( (newBounds.left + leftTolerance) >= maxExtent.right && 
+                   newBounds.right > maxExtent.right ) { 
+                newBounds = newBounds.add(-maxExtent.getWidth(), 0);
+           }
+        }
+                
+        return newBounds;
+    },
+
+    CLASS_NAME: "OpenLayers.Bounds"
+});
+
+/** 
+ * APIFunction: fromString
+ * Alternative constructor that builds a new OpenLayers.Bounds from a 
+ *     parameter string
+ * 
+ * Parameters: 
+ * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ * 
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the 
+ *                       passed-in String.
+ */
+OpenLayers.Bounds.fromString = function(str) {
+    var bounds = str.split(",");
+    return OpenLayers.Bounds.fromArray(bounds);
+};
+
+/** 
+ * APIFunction: fromArray
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ *     from an array
+ * 
+ * Parameters:
+ * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
+ */
+OpenLayers.Bounds.fromArray = function(bbox) {
+    return new OpenLayers.Bounds(parseFloat(bbox[0]),
+                                 parseFloat(bbox[1]),
+                                 parseFloat(bbox[2]),
+                                 parseFloat(bbox[3]));
+};
+
+/** 
+ * APIFunction: fromSize
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ *     from a size
+ * 
+ * Parameters:
+ * size - {<OpenLayers.Size>} 
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
+ */
+OpenLayers.Bounds.fromSize = function(size) {
+    return new OpenLayers.Bounds(0,
+                                 size.h,
+                                 size.w,
+                                 0);
+};
+
+/**
+ * Function: oppositeQuadrant
+ * Get the opposite quadrant for a given quadrant string.
+ *
+ * Parameters:
+ * quadrant - {String} two character quadrant shortstring
+ *
+ * Returns:
+ * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if 
+ *          you pass in "bl" it returns "tr", if you pass in "br" it 
+ *          returns "tl", etc.
+ */
+OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
+    var opp = "";
+    
+    opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
+    opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
+    
+    return opp;
+};
+/* ======================================================================
+    OpenLayers/BaseTypes/Element.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Element
+ */
+OpenLayers.Element = {
+
+    /**
+     * APIFunction: visible
+     * 
+     * Parameters: 
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Boolean} Is the element visible?
+     */
+    visible: function(element) {
+        return OpenLayers.Util.getElement(element).style.display != 'none';
+    },
+
+    /**
+     * APIFunction: toggle
+     * Toggle the visibility of element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    toggle: function() {
+        for (var i = 0; i < arguments.length; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            var display = OpenLayers.Element.visible(element) ? 'hide' 
+                                                              : 'show';
+            OpenLayers.Element[display](element);
+        }
+    },
+
+
+    /**
+     * APIFunction: hide
+     * Hide element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    hide: function() {
+        for (var i = 0; i < arguments.length; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            element.style.display = 'none';
+        }
+    },
+
+    /**
+     * APIFunction: show
+     * Show element(s) passed in
+     * 
+     * Parameters:
+     * element - {DOMElement} Actually user can pass any number of elements
+     */
+    show: function() {
+        for (var i = 0; i < arguments.length; i++) {
+            var element = OpenLayers.Util.getElement(arguments[i]);
+            element.style.display = '';
+        }
+    },
+
+    /**
+     * APIFunction: remove
+     * Remove the specified element from the DOM.
+     * 
+     * Parameters:
+     * element - {DOMElement}
+     */
+    remove: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        element.parentNode.removeChild(element);
+    },
+
+    /**
+     * APIFunction: getHeight
+     *  
+     * Parameters:
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Integer} The offset height of the element passed in
+     */
+    getHeight: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        return element.offsetHeight;
+    },
+
+    /**
+     * APIFunction: getDimensions
+     *  
+     * Parameters:
+     * element - {DOMElement}
+     * 
+     * Returns:
+     * {Object} Object with 'width' and 'height' properties which are the 
+     *          dimensions of the element passed in.
+     */
+    getDimensions: function(element) {
+        element = OpenLayers.Util.getElement(element);
+        if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
+            return {width: element.offsetWidth, height: element.offsetHeight};
+        }
+    
+        // All *Width and *Height properties give 0 on elements with display none,
+        // so enable the element temporarily
+        var els = element.style;
+        var originalVisibility = els.visibility;
+        var originalPosition = els.position;
+        els.visibility = 'hidden';
+        els.position = 'absolute';
+        els.display = '';
+        var originalWidth = element.clientWidth;
+        var originalHeight = element.clientHeight;
+        els.display = 'none';
+        els.position = originalPosition;
+        els.visibility = originalVisibility;
+        return {width: originalWidth, height: originalHeight};
+    },
+
+    /**
+     * APIFunction: getStyle
+     * 
+     * Parameters:
+     * element - {DOMElement}
+     * style - {?}
+     * 
+     * Returns:
+     * {?}
+     */
+    getStyle: function(element, style) {
+        element = OpenLayers.Util.getElement(element);
+        var value = element.style[OpenLayers.String.camelize(style)];
+        if (!value) {
+            if (document.defaultView && 
+                document.defaultView.getComputedStyle) {
+                
+                var css = document.defaultView.getComputedStyle(element, null);
+                value = css ? css.getPropertyValue(style) : null;
+            } else if (element.currentStyle) {
+                value = element.currentStyle[OpenLayers.String.camelize(style)];
+            }
+        }
+    
+        var positions = ['left', 'top', 'right', 'bottom'];
+        if (window.opera &&
+            (OpenLayers.Util.indexOf(positions,style) != -1) &&
+            (OpenLayers.Element.getStyle(element, 'position') == 'static')) { 
+            value = 'auto';
+        }
+    
+        return value == 'auto' ? null : value;
+    }
+
+};
+/* ======================================================================
+    OpenLayers/BaseTypes/LonLat.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Class: OpenLayers.LonLat
+ * This class represents a longitude and latitude pair
+ */
+OpenLayers.LonLat = OpenLayers.Class({
+
+    /** 
+     * APIProperty: lon
+     * {Float} The x-axis coodinate in map units
+     */
+    lon: 0.0,
+    
+    /** 
+     * APIProperty: lat
+     * {Float} The y-axis coordinate in map units
+     */
+    lat: 0.0,
+
+    /**
+     * Constructor: OpenLayers.LonLat
+     * Create a new map location.
+     *
+     * Parameters:
+     * lon - {Number} The x-axis coordinate in map units.  If your map is in
+     *     a geographic projection, this will be the Longitude.  Otherwise,
+     *     it will be the x coordinate of the map location in your map units.
+     * lat - {Number} The y-axis coordinate in map units.  If your map is in
+     *     a geographic projection, this will be the Latitude.  Otherwise,
+     *     it will be the y coordinate of the map location in your map units.
+     */
+    initialize: function(lon, lat) {
+        this.lon = parseFloat(lon);
+        this.lat = parseFloat(lat);
+    },
+    
+    /**
+     * Method: toString
+     * Return a readable string version of the lonlat
+     *
+     * Returns:
+     * {String} String representation of OpenLayers.LonLat object. 
+     *           (ex. <i>"lon=5,lat=42"</i>)
+     */
+    toString:function() {
+        return ("lon=" + this.lon + ",lat=" + this.lat);
+    },
+
+    /** 
+     * APIMethod: toShortString
+     * 
+     * Returns:
+     * {String} Shortened String representation of OpenLayers.LonLat object. 
+     *         (ex. <i>"5, 42"</i>)
+     */
+    toShortString:function() {
+        return (this.lon + ", " + this.lat);
+    },
+
+    /** 
+     * APIMethod: clone
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon 
+     *                       and lat values
+     */
+    clone:function() {
+        return new OpenLayers.LonLat(this.lon, this.lat);
+    },
+
+    /** 
+     * APIMethod: add
+     * 
+     * Parameters:
+     * lon - {Float}
+     * lat - {Float}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and 
+     *                       lat passed-in added to this's. 
+     */
+    add:function(lon, lat) {
+        if ( (lon == null) || (lat == null) ) {
+            var msg = OpenLayers.String.translate("lonlatAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
+    },
+
+    /** 
+     * APIMethod: equals
+     * 
+     * Parameters:
+     * ll - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {Boolean} Boolean value indicating whether the passed-in 
+     *           <OpenLayers.LonLat> object has the same lon and lat 
+     *           components as this.
+     *           Note: if ll passed in is null, returns false
+     */
+    equals:function(ll) {
+        var equals = false;
+        if (ll != null) {
+            equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
+                      (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
+        }
+        return equals;
+    },
+    
+    /**
+     * APIMethod: wrapDateLine
+     * 
+     * Parameters:
+     * maxExtent - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the 
+     *                       "dateline" (as specified by the borders of 
+     *                       maxExtent)
+     */
+    wrapDateLine: function(maxExtent) {    
+
+        var newLonLat = this.clone();
+    
+        if (maxExtent) {
+            //shift right?
+            while (newLonLat.lon < maxExtent.left) {
+                newLonLat.lon +=  maxExtent.getWidth();
+            }    
+           
+            //shift left?
+            while (newLonLat.lon > maxExtent.right) {
+                newLonLat.lon -= maxExtent.getWidth();
+            }    
+        }
+                
+        return newLonLat;
+    },
+
+    CLASS_NAME: "OpenLayers.LonLat"
+});
+
+/** 
+ * Function: fromString
+ * Alternative constructor that builds a new <OpenLayers.LonLat> from a 
+ *     parameter string
+ * 
+ * Parameters:
+ * str - {String} Comma-separated Lon,Lat coordinate string. 
+ *                 (ex. <i>"5,40"</i>)
+ * 
+ * Returns:
+ * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the 
+ *                       passed-in String.
+ */
+OpenLayers.LonLat.fromString = function(str) {
+    var pair = str.split(",");
+    return new OpenLayers.LonLat(parseFloat(pair[0]), 
+                                 parseFloat(pair[1]));
+};
+/* ======================================================================
+    OpenLayers/BaseTypes/Pixel.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Class: OpenLayers.Pixel
+ * This class represents a screen coordinate, in x and y coordinates
+ */
+OpenLayers.Pixel = OpenLayers.Class({
+    
+    /**
+     * APIProperty: x
+     * {Number} The x coordinate
+     */
+    x: 0.0,
+
+    /**
+     * APIProperty: y
+     * {Number} The y coordinate
+     */
+    y: 0.0,
+    
+    /**
+     * Constructor: OpenLayers.Pixel
+     * Create a new OpenLayers.Pixel instance
+     *
+     * Parameters:
+     * x - {Number} The x coordinate
+     * y - {Number} The y coordinate
+     *
+     * Returns:
+     * An instance of OpenLayers.Pixel
+     */
+    initialize: function(x, y) {
+        this.x = parseFloat(x);
+        this.y = parseFloat(y);
+    },
+    
+    /**
+     * Method: toString
+     * Cast this object into a string
+     *
+     * Returns:
+     * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
+     */
+    toString:function() {
+        return ("x=" + this.x + ",y=" + this.y);
+    },
+
+    /**
+     * APIMethod: clone
+     * Return a clone of this pixel object
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} A clone pixel
+     */
+    clone:function() {
+        return new OpenLayers.Pixel(this.x, this.y); 
+    },
+    
+    /**
+     * APIMethod: equals
+     * Determine whether one pixel is equivalent to another
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {Boolean} The point passed in as parameter is equal to this. Note that
+     * if px passed in is null, returns false.
+     */
+    equals:function(px) {
+        var equals = false;
+        if (px != null) {
+            equals = ((this.x == px.x && this.y == px.y) ||
+                      (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
+        }
+        return equals;
+    },
+
+    /**
+     * APIMethod: add
+     *
+     * Parameters:
+     * x - {Integer}
+     * y - {Integer}
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
+     * values passed in.
+     */
+    add:function(x, y) {
+        if ( (x == null) || (y == null) ) {
+            var msg = OpenLayers.String.translate("pixelAddError");
+            OpenLayers.Console.error(msg);
+            return null;
+        }
+        return new OpenLayers.Pixel(this.x + x, this.y + y);
+    },
+
+    /**
+    * APIMethod: offset
+    * 
+    * Parameters
+    * px - {<OpenLayers.Pixel>}
+    * 
+    * Returns:
+    * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the 
+    *                      x&y values of the pixel passed in.
+    */
+    offset:function(px) {
+        var newPx = this.clone();
+        if (px) {
+            newPx = this.add(px.x, px.y);
+        }
+        return newPx;
+    },
+
+    CLASS_NAME: "OpenLayers.Pixel"
+});
+/* ======================================================================
+    OpenLayers/Ajax.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+OpenLayers.ProxyHost = "";
+//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
+
+/**
+ * Ajax reader for OpenLayers
+ *
+ *  @uri url to do remote XML http get
+ *  @param {String} 'get' format params (x=y&a=b...)
+ *  @who object to handle callbacks for this request
+ *  @complete  the function to be called on success 
+ *  @failure  the function to be called on failure
+ *  
+ *   example usage from a caller:
+ *  
+ *     caps: function(request) {
+ *      -blah-  
+ *     },
+ *  
+ *     OpenLayers.loadURL(url,params,this,caps);
+ *
+ * Notice the above example does not provide an error handler; a default empty
+ * handler is provided which merely logs the error if a failure handler is not 
+ * supplied
+ *
+ */
+
+
+/** 
+* @param {} request
+*/
+OpenLayers.nullHandler = function(request) {
+    alert(OpenLayers.String.translate("unhandledRequest", request.statusText));
+};
+
+/** 
+ * Function: loadURL
+ * Background load a document.
+ *
+ * Parameters:
+ * uri - {String} URI of source doc
+ * params - {String} Params on get (doesnt seem to work)
+ * caller - {Object} object which gets callbacks
+ * onComplete - {Function} callback for success
+ * onFailure - {Function} callback for failure
+ *
+ * Both callbacks optional (though silly)
+ */
+OpenLayers.loadURL = function(uri, params, caller,
+                                  onComplete, onFailure) {
+
+    if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(uri, "http")) {
+        uri = OpenLayers.ProxyHost + escape(uri);
+    }
+
+    var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
+                                : OpenLayers.nullHandler;
+
+    var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
+                           : OpenLayers.nullHandler;
+
+    // from prototype.js
+    new OpenLayers.Ajax.Request(uri, 
+                     {   method: 'get', 
+                         parameters: params,
+                         onComplete: success, 
+                         onFailure: failure
+                      }
+                     );
+};
+
+/** 
+ * Function: parseXMLString
+ * Parse XML into a doc structure
+ * 
+ * Parameters:
+ * text - {String} 
+ * 
+ * Returns:
+ * {?} Parsed AJAX Responsev
+ */
+OpenLayers.parseXMLString = function(text) {
+
+    //MS sucks, if the server is bad it dies
+    var index = text.indexOf('<');
+    if (index > 0) {
+        text = text.substring(index);
+    }
+
+    var ajaxResponse = OpenLayers.Util.Try(
+        function() {
+            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
+            xmldom.loadXML(text);
+            return xmldom;
+        },
+        function() {
+            return new DOMParser().parseFromString(text, 'text/xml');
+        },
+        function() {
+            var req = new XMLHttpRequest();
+            req.open("GET", "data:" + "text/xml" +
+                     ";charset=utf-8," + encodeURIComponent(text), false);
+            if (req.overrideMimeType) {
+                req.overrideMimeType("text/xml");
+            }
+            req.send(null);
+            return req.responseXML;
+        }
+    );
+
+    return ajaxResponse;
+};
+
+
+/**
+ * Namespace: OpenLayers.Ajax
+ */
+OpenLayers.Ajax = {
+
+    /**
+     * Method: emptyFunction
+     */
+    emptyFunction: function () {},
+
+    /**
+     * Method: getTransport
+     * 
+     * Returns: 
+     * {Object} Transport mechanism for whichever browser we're in, or false if
+     *          none available.
+     */
+    getTransport: function() {
+        return OpenLayers.Util.Try(
+            function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+            function() {return new ActiveXObject('Microsoft.XMLHTTP')},
+            function() {return new XMLHttpRequest()}
+        ) || false;
+    },
+
+    /**
+     * Property: activeRequestCount
+     * {Integer}
+     */
+    activeRequestCount: 0
+};
+
+/**
+ * Namespace: OpenLayers.Ajax.Responders
+ * {Object}
+ */
+OpenLayers.Ajax.Responders = {
+  
+    /**
+     * Property: responders
+     * {Array}
+     */
+    responders: [],
+
+    /**
+     * Method: register
+     *  
+     * Parameters:
+     * responderToAdd - {?}
+     */
+    register: function(responderToAdd) {
+      for (var i = 0; i < this.responders.length; i++)
+          if (responderToAdd == this.responders[i])
+              return;
+      this.responders.push(responderToAdd);
+    },
+
+    /**
+     * Method: dispatch
+     * 
+     * Parameters:
+     * callback - {?}
+     * request - {?}
+     * transport - {?}
+     * json - {?}
+     */
+    dispatch: function(callback, request, transport, json) {
+        var responder;
+        for (var i = 0; i < this.responders.length; i++) {
+            responder = this.responders[i];
+     
+            if (responder[callback] && 
+                typeof responder[callback] == 'function') {
+                try {
+                    responder[callback].apply(responder, 
+                                              [request, transport, json]);
+                } catch (e) {}
+            }
+        }
+    }
+};
+
+OpenLayers.Ajax.Responders.register({
+    /** 
+     * Function: onCreate
+     */
+    onCreate: function() {
+        OpenLayers.Ajax.activeRequestCount++;
+    },
+
+    /**
+     * Function: onComplete
+     */
+     onComplete: function() {
+         OpenLayers.Ajax.activeRequestCount--;
+     }
+});
+
+/**
+ * Namespace: OpenLayers.Ajax.Base
+ * {Object}
+ */
+OpenLayers.Ajax.Base = function() {};
+OpenLayers.Ajax.Base.prototype = {
+
+    /**
+     * Function: setOptions
+     * 
+     * Parameters:
+     * options - {Object}
+     */
+    setOptions: function(options) {
+        this.options = {
+            'method': 'post',
+            'asynchronous': true,
+            'parameters': ''
+        };
+        OpenLayers.Util.extend(this.options, options || {});
+    },
+
+    /**
+     * Function: responseIsSuccess
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    responseIsSuccess: function() {
+        return this.transport.status == undefined || 
+               this.transport.status == 0 || 
+               (this.transport.status >= 200 && this.transport.status < 300);
+    },
+
+    /**
+     * Function: responseIsFailure
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    responseIsFailure: function() {
+        return !this.responseIsSuccess();
+    }
+};
+
+
+/**
+ * Class: OpenLayers.Ajax.Request
+ *
+ * Inherit:
+ *  - <OpenLayers.Ajax.Base>
+ */
+OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
+      
+      /**
+       * Constructor: OpenLayers.Ajax.Request
+       * 
+       * Parameters: 
+       * url - {String}
+       * options - {Object}
+       */
+    initialize: function(url, options) {
+        this.transport = OpenLayers.Ajax.getTransport();
+        this.setOptions(options);
+        this.request(url);
+    },
+
+    /**
+     * Method: request
+     * 
+     * Parameters:
+     * url - {String}
+     */
+    request: function(url) {
+        var parameters = this.options.parameters || '';
+        if (parameters.length > 0) parameters += '&_=';
+    
+        try {
+            this.url = url;
+            if (this.options.method == 'get' && parameters.length > 0) {
+               this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+            }
+            
+            OpenLayers.Ajax.Responders.dispatch('onCreate', 
+                                                this, 
+                                                this.transport);
+    
+            this.transport.open(this.options.method, 
+                                this.url,
+                                this.options.asynchronous);
+    
+            if (this.options.asynchronous) {
+                this.transport.onreadystatechange = 
+                    OpenLayers.Function.bind(this.onStateChange, this);
+                
+                setTimeout(OpenLayers.Function.bind(
+                    (function() {this.respondToReadyState(1)}),this), 10
+                );
+            }
+    
+            this.setRequestHeaders();
+    
+            var body = this.options.postBody ? this.options.postBody 
+                                             : parameters;
+            this.transport.send(this.options.method == 'post' ? body : null);
+    
+            // Force Firefox to handle ready state 4 for synchronous requests
+            if (!this.options.asynchronous && 
+                this.transport.overrideMimeType) {
+                
+                this.onStateChange();
+            }
+    
+        } catch (e) {
+            this.dispatchException(e);
+        }
+    },
+     
+    /**
+     * Method: setRequestHeaders
+     */
+    setRequestHeaders: function() {
+        var requestHeaders = [
+            'X-Requested-With',
+            'XMLHttpRequest',
+            'X-Prototype-Version',
+            'OpenLayers'
+        ];
+    
+        if (this.options.method == 'post' && !this.options.postBody) {
+            requestHeaders.push('Content-type',
+                                'application/x-www-form-urlencoded');
+    
+            // Force "Connection: close" for Mozilla browsers to work around
+            // a bug where XMLHttpReqeuest sends an incorrect Content-length
+            // header. See Mozilla Bugzilla #246651.
+            if (this.transport.overrideMimeType) {
+                requestHeaders.push('Connection', 'close');
+            }
+        }
+    
+        if (this.options.requestHeaders) {
+            requestHeaders.push.apply(requestHeaders, 
+                                      this.options.requestHeaders);
+        }
+          
+        for (var i = 0; i < requestHeaders.length; i += 2) {
+            this.transport.setRequestHeader(requestHeaders[i], 
+                                            requestHeaders[i+1]);
+        }
+    },
+
+    /**
+     * Method: onStateChange
+     */
+    onStateChange: function() {
+        var readyState = this.transport.readyState;
+        if (readyState != 1) {
+          this.respondToReadyState(this.transport.readyState);
+        }
+    },
+
+    /** 
+     * Method: header
+     * 
+     * Returns:
+     * {?}
+     */
+    header: function(name) {
+        try {
+            return this.transport.getResponseHeader(name);
+        } catch (e) {}
+    },
+
+    /** 
+     * Method: evalJSON
+     * 
+     * Returns:
+     * {?}
+     */
+    evalJSON: function() {
+        try {
+            return eval(this.header('X-JSON'));
+        } catch (e) {}
+    },
+
+    /**
+     * Method: evalResponse
+     * 
+     * Returns: 
+     * {?}
+     */
+    evalResponse: function() {
+        try {
+            return eval(this.transport.responseText);
+        } catch (e) {
+            this.dispatchException(e);
+        }
+    },
+
+    /**
+     * Method: respondToReadyState
+     *
+     * Parameters:
+     * readyState - {?}
+     */
+    respondToReadyState: function(readyState) {
+        var event = OpenLayers.Ajax.Request.Events[readyState];
+        var transport = this.transport, json = this.evalJSON();
+    
+        if (event == 'Complete') {
+            try {
+                var responseSuccess = this.responseIsSuccess() ? 'Success'
+                                                                : 'Failure';
+                                                                 
+                (this.options['on' + this.transport.status] ||
+                 this.options['on' + responseSuccess] ||
+                 OpenLayers.Ajax.emptyFunction)(transport, json);
+            } catch (e) {
+                this.dispatchException(e);
+            }
+    
+            var contentType = this.header('Content-type') || '';
+            if (contentType.match(/^text\/javascript/i)) {
+                this.evalResponse();
+            }
+        }
+    
+        try {
+            (this.options['on' + event] || 
+             OpenLayers.Ajax.emptyFunction)(transport, json);
+             OpenLayers.Ajax.Responders.dispatch('on' + event, 
+                                                 this, 
+                                                 transport, 
+                                                 json);
+        } catch (e) {
+            this.dispatchException(e);
+        }
+    
+        // Avoid memory leak in MSIE: clean up the oncomplete event handler
+        if (event == 'Complete') {
+            this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
+        }
+    },
+
+    /**
+     * Method: dispatchException
+     * 
+     * Parameters:
+     * exception - {?}
+     */
+    dispatchException: function(exception) {
+        if (this.options.onException) {
+            this.options.onException(this, exception);
+        } else {
+            // if we get here, Responders.dispatch('onException') will never
+            // be called. too bad. we should probably take out the Responders
+            // stuff anyway.
+            throw exception;
+        }
+        OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+    }
+    
+});
+
+/** 
+ * Property: Events
+ * {Array(String)}
+ */
+OpenLayers.Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+/**
+ * Function: getElementsByTagNameNS
+ * 
+ * Parameters:
+ * parentnode - {?}
+ * nsuri - {?}
+ * nsprefix - {?}
+ * tagname - {?}
+ * 
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri, 
+                                                   nsprefix, tagname) {
+    var elem = null;
+    if (parentnode.getElementsByTagNameNS) {
+        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
+    } else {
+        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
+    }
+    return elem;
+};
+
+
+/**
+ * Function: serializeXMLToString
+ * Wrapper function around XMLSerializer, which doesn't exist/work in
+ *     IE/Safari. We need to come up with a way to serialize in those browser:
+ *     for now, these browsers will just fail. #535, #536
+ *
+ * Parameters: 
+ * xmldom {XMLNode} xml dom to serialize
+ * 
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
+    var serializer = new XMLSerializer();
+    data = serializer.serializeToString(xmldom);
+    return data;
+}
+/* ======================================================================
+    OpenLayers/Control.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * Class: OpenLayers.Control
+ * Controls affect the display or behavior of the map. They allow everything
+ * from panning and zooming to displaying a scale indicator. Controls by 
+ * default are added to the map they are contained within however it is
+ * possible to add a control to an external div by passing the div in the
+ * options parameter.
+ * 
+ * Example:
+ * The following example shows how to add many of the common controls
+ * to a map.
+ * 
+ * > var map = new OpenLayers.Map('map', { controls: [] });
+ * >
+ * > map.addControl(new OpenLayers.Control.PanZoomBar());
+ * > map.addControl(new OpenLayers.Control.MouseToolbar());
+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ * > map.addControl(new OpenLayers.Control.Permalink());
+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
+ * > map.addControl(new OpenLayers.Control.MousePosition());
+ * > map.addControl(new OpenLayers.Control.OverviewMap());
+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+ *
+ * The next code fragment is a quick example of how to intercept 
+ * shift-mouse click to display the extent of the bounding box
+ * dragged out by the user.  Usually controls are not created
+ * in exactly this manner.  See the source for a more complete 
+ * example:
+ *
+ * > var control = new OpenLayers.Control();
+ * > OpenLayers.Util.extend(control, {
+ * >     draw: function () {
+ * >         // this Handler.Box will intercept the shift-mousedown
+ * >         // before Control.MouseDefault gets to see it
+ * >         this.box = new OpenLayers.Handler.Box( control, 
+ * >             {"done": this.notice},
+ * >             {keyMask: OpenLayers.Handler.MOD_SHIFT});
+ * >         this.box.activate();
+ * >     },
+ * >
+ * >     notice: function (bounds) {
+ * >         alert(bounds);
+ * >     }
+ * > }); 
+ * > map.addControl(control);
+ * 
+ */
+OpenLayers.Control = OpenLayers.Class({
+
+    /** 
+     * Property: id 
+     * {String} 
+     */
+    id: null,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} this gets set in the addControl() function in
+     * OpenLayers.Map 
+     */
+    map: null,
+
+    /** 
+     * Property: div 
+     * {DOMElement} 
+     */
+    div: null,
+
+    /** 
+     * Property: type 
+     * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
+     * determines the type of interactions which are possible with them when
+     * they are placed into a toolbar. 
+     */
+    type: null, 
+
+    /** 
+     * Property: displayClass 
+     * {string}  This property is used for CSS related to the drawing of the
+     * Control. 
+     */
+    displayClass: "",
+
+    /** 
+     * Property: active 
+     * {boolean} null
+     */
+    active: null,
+
+    /** 
+     * Property: handler 
+     * {<OpenLayers.Handler>} null
+     */
+    handler: null,
+
+    /**
+     * Constructor: OpenLayers.Control
+     * Create an OpenLayers Control.  The options passed as a parameter
+     * directly extend the control.  For example passing the following:
+     * 
+     * > var control = new OpenLayers.Control({div: myDiv});
+     *
+     * Overrides the default div attribute value of null.
+     * 
+     * Parameters:
+     * options - {Object} 
+     */
+    initialize: function (options) {
+        // We do this before the extend so that instances can override
+        // className in options.
+        this.displayClass = 
+            this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+        
+        OpenLayers.Util.extend(this, options);
+        
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+    },
+
+    /**
+     * Method: destroy
+     * The destroy method is used to perform any clean up before the control
+     * is dereferenced.  Typically this is where event listeners are removed
+     * to prevent memory leaks.
+     */
+    destroy: function () {
+        // eliminate circular references
+        if (this.handler) {
+            this.handler.destroy();
+        }    
+        this.map = null;
+    },
+
+    /** 
+     * Method: setMap
+     * Set the map property for the control. This is done through an accessor
+     * so that subclasses can override this and take special action once 
+     * they have their map variable set. 
+     *
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        this.map = map;
+        if (this.handler) {
+            this.handler.setMap(map);
+        }
+    },
+  
+    /**
+     * Method: draw
+     * The draw method is called when the control is ready to be displayed
+     * on the page.  If a div has not been created one is created.  Controls
+     * with a visual component will almost always want to override this method 
+     * to customize the look of control. 
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
+     *      or null.
+     *
+     * Returns:
+     * {DOMElement} A reference to the DIV DOMElement containing the control
+     */
+    draw: function (px) {
+        if (this.div == null) {
+            this.div = OpenLayers.Util.createDiv();
+            this.div.id = this.id;
+            this.div.className = this.displayClass;
+        }
+        if (px != null) {
+            this.position = px.clone();
+        }
+        this.moveTo(this.position);        
+        return this.div;
+    },
+
+    /**
+     * Method: moveTo
+     * Sets the left and top style attributes to the passed in pixel 
+     * coordinates.
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     */
+    moveTo: function (px) {
+        if ((px != null) && (this.div != null)) {
+            this.div.style.left = px.x + "px";
+            this.div.style.top = px.y + "px";
+        }
+    },
+
+    /**
+     * Method: activate
+     * Explicitly activates a control and it's associated
+     * handler if one has been set.  Controls can be
+     * deactivated by calling the deactivate() method.
+     * 
+     * Returns:
+     * {Boolean}  True if the control was successfully activated or
+     *            false if the control was already active.
+     */
+    activate: function () {
+        if (this.active) {
+            return false;
+        }
+        if (this.handler) {
+            this.handler.activate();
+        }
+        this.active = true;
+        return true;
+    },
+    
+    /**
+     * Method: deactivate
+     * Deactivates a control and it's associated handler if any.  The exact
+     * effect of this depends on the control itself.
+     * 
+     * Returns:
+     * {Boolean} True if the control was effectively deactivated or false
+     *           if the control was already inactive.
+     */
+    deactivate: function () {
+        if (this.active) {
+            if (this.handler) {
+                this.handler.deactivate();
+            }
+            this.active = false;
+            return true;
+        }
+        return false;
+    },
+
+    CLASS_NAME: "OpenLayers.Control"
+});
+
+OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Control.TYPE_TOOL   = 3;
+/* ======================================================================
+    OpenLayers/Icon.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * Class: OpenLayers.Icon
+ * 
+ * The icon represents a graphical icon on the screen.  Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
+ *
+ * An icon has a url, size and position.  It also contains an offset which 
+ * allows the center point to be represented correctly.  This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset. 
+ * 
+ */
+OpenLayers.Icon = OpenLayers.Class({
+    
+    /** 
+     * Property: url 
+     * {String}  image url
+     */
+    url: null,
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} 
+     */
+    size: null,
+
+    /** 
+     * Property: offset 
+     * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
+     */
+    offset: null,    
+    
+    /** 
+     * Property: calculateOffset 
+     * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size) 
+     */
+    calculateOffset: null,    
+    
+    /** 
+     * Property: imageDiv 
+     * {DOMElement} 
+     */
+    imageDiv: null,
+
+    /** 
+     * Property: px 
+     * {<OpenLayers.Pixel>} 
+     */
+    px: null,
+    
+    /** 
+     * Constructor: OpenLayers.Icon
+     * Creates an icon, which is an image tag in a div.  
+     *
+     * url - {String} 
+     * size - {<OpenLayers.Size>} 
+     * calculateOffset - {Function} 
+     */
+    initialize: function(url, size, offset, calculateOffset) {
+        this.url = url;
+        this.size = (size) ? size : new OpenLayers.Size(20,20);
+        this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+        this.calculateOffset = calculateOffset;
+
+        var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+        this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+    },
+    
+    /** 
+     * Method: destroy
+     * Nullify references and remove event listeners to prevent circular 
+     * references and memory leaks
+     */
+    destroy: function() {
+        OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); 
+        this.imageDiv.innerHTML = "";
+        this.imageDiv = null;
+    },
+
+    /** 
+     * Method: clone
+     * 
+     * Returns:
+     * {<OpenLayers.Icon>} A fresh copy of the icon.
+     */
+    clone: function() {
+        return new OpenLayers.Icon(this.url, 
+                                   this.size, 
+                                   this.offset, 
+                                   this.calculateOffset);
+    },
+    
+    /**
+     * Method: setSize
+     * 
+     * size - {<OpenLayers.Size>} 
+     */
+    setSize: function(size) {
+        if (size != null) {
+            this.size = size;
+        }
+        this.draw();
+    },
+
+    /** 
+     * Method: draw
+     * Move the div to the given pixel.
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     * 
+     * Returns:
+     * {DOMElement} A new DOM Image of this icon set at the location passed-in
+     */
+    draw: function(px) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, 
+                                            null, 
+                                            null, 
+                                            this.size, 
+                                            this.url, 
+                                            "absolute");
+        this.moveTo(px);
+        return this.imageDiv;
+    }, 
+
+    
+    /** 
+     * Method: setOpacity
+     * Change the icon's opacity
+     *
+     * Parameters:
+     * opacity - {float} 
+     */
+    setOpacity: function(opacity) {
+        OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, 
+                                            null, null, null, null, opacity);
+
+    },
+    
+    /**
+     * Method: moveTo
+     * move icon to passed in px.
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     */
+    moveTo: function (px) {
+        //if no px passed in, use stored location
+        if (px != null) {
+            this.px = px;
+        }
+
+        if (this.imageDiv != null) {
+            if (this.px == null) {
+                this.display(false);
+            } else {
+                if (this.calculateOffset) {
+                    this.offset = this.calculateOffset(this.size);  
+                }
+                var offsetPx = this.px.offset(this.offset);
+                OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
+            }
+        }
+    },
+    
+    /** 
+     * Method: display
+     * Hide or show the icon
+     *
+     * Parameters:
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.imageDiv.style.display = (display) ? "" : "none"; 
+    },
+
+    CLASS_NAME: "OpenLayers.Icon"
+});
+/* ======================================================================
+    OpenLayers/Strings/en.js
+   ====================================================================== */
+
+OpenLayers.Strings.en = {
+'test1': 'this is a test',
+'test2': 'and another test',
+'test3': 'arg one:{0} arg two: {1}',
+'unhandledRequest': "Unhandled request return {0}",
+'permalink': "Permalink",
+'overlays': "Overlays",
+'baseLayer': "Base Layer",
+'sameProjection': "The overview map only works when it is in the same projection as the main map",
+'readNotImplemented': "Read not implemented.",
+'writeNotImplemented': "Write not implemented.",
+'noFID': "Can't update a feature for which there is no FID.",
+'errorLoadingGML': "Error in loading GML file {0}",
+'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
+'componentShouldBe': "addFeatures : component should be an {0}",
+'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
+                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
+'minZoomLevelError': "The minZoomLevel property is only intended for use " +
+                    "with the FixedZoomLevels-descendent layers. That this " +
+                    "wfs layer checks for minZoomLevel is a relic of the" +
+                    "past. We cannot, however, remove it without possibly " +
+                    "breaking OL based applications that may depend on it." +
+                    " Therefore we are deprecating it -- the minZoomLevel " +
+                    "check below will be removed at 3.0. Please instead " +
+                    "use min/max resolution setting as described here: " +
+                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
+'commitSuccess': "WFS Transaction: SUCCESS {0}",
+'commitFailed': "WFS Transaction: FAILED {0}",
+'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the Google Maps library " +
+                "script was either not included, or does not contain the " +
+                "correct API key for your site.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/Google' " +
+                "target='_blank'>click here</a>",
+'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the {0} library " +
+                "script was either not correctly included.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/{1}' " +
+                "target='_blank'>click here</a>",
+'scale': "Scale = 1 : {0}",
+'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
+'reprojectDeprecated': "You are using the 'reproject' option " +
+                "on the {0} layer. This option is deprecated: " +
+                "its use was designed to support displaying data over commercial " + 
+                "basemaps, but that functionality should now be achieved by using " +
+                "Spherical Mercator support. More information is available from " +
+                "http://trac.openlayers.org/wiki/SphericalMercator.",
+'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
+                "Please use {0} instead.",
+'boundsAddError': "You must pass both x and y values to the add function.",
+'lonlatAddError': "You must pass both lon and lat values to the add function.",
+'pixelAddError': "You must pass both x and y values to the add function.",
+'unsupportedGeometryType': "Unsupported geometry type: {0}",
+'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
+                " Please use 'array.length = 0' instead.",
+'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
+                "with the 3.0 version of OpenLayers. Please instead use " +
+                "OpenLayers.Util.getParameters().",
+'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
+                
+'end': ''
+};
+/* ======================================================================
+    OpenLayers/Control/ArgParser.js
+   ====================================================================== */
+
+/* Cpyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ *
+ * Class: OpenLayers.Control.ArgParser
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Parameter: center
+     * {<OpenLayers.LonLat>}
+     */
+    center: null,
+    
+    /**
+     * Parameter: zoom
+     * {int}
+     */
+    zoom: null,
+
+    /**
+     * Parameter: layers 
+     * {Array(<OpenLayers.Layer>)}
+     */
+    layers: null,
+
+    /**
+     * Constructor: OpenLayers.Control.ArgParser
+     *
+     * Parameters:
+     * options - {Object}
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the control. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>} 
+     */
+    setMap: function(map) {
+        OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+        //make sure we dont already have an arg parser attached
+        for(var i=0; i< this.map.controls.length; i++) {
+            var control = this.map.controls[i];
+            if ( (control != this) &&
+                 (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
+                break;
+            }
+        }
+        if (i == this.map.controls.length) {
+
+            var args = OpenLayers.Util.getParameters();
+            if (args.lat && args.lon) {
+                this.center = new OpenLayers.LonLat(parseFloat(args.lon),
+                                                    parseFloat(args.lat));
+                if (args.zoom) {
+                    this.zoom = parseInt(args.zoom);
+                }
+    
+                // when we add a new baselayer to see when we can set the center
+                this.map.events.register('changebaselayer', this, 
+                                         this.setCenter);
+                this.setCenter();
+            }
+    
+            if (args.layers) {
+                this.layers = args.layers;
+    
+                // when we add a new layer, set its visibility 
+                this.map.events.register('addlayer', this, 
+                                         this.configureLayers);
+                this.configureLayers();
+            }
+        }
+    },
+   
+    /** 
+     * Method: setCenter
+     * As soon as a baseLayer has been loaded, we center and zoom
+     *   ...and remove the handler.
+     */
+    setCenter: function() {
+        
+        if (this.map.baseLayer) {
+            //dont need to listen for this one anymore
+            this.map.events.unregister('changebaselayer', this, 
+                                       this.setCenter);
+                                       
+            this.map.setCenter(this.center, this.zoom);
+        }
+    },
+
+    /** 
+     * Method: configureLayers
+     * As soon as all the layers are loaded, cycle through them and 
+     *   hide or show them. 
+     */
+    configureLayers: function() {
+
+        if (this.layers.length == this.map.layers.length) { 
+            this.map.events.unregister('addlayer', this, this.configureLayers);
+
+            for(var i=0; i < this.layers.length; i++) {
+                
+                var layer = this.map.layers[i];
+                var c = this.layers.charAt(i);
+                
+                if (c == "B") {
+                    this.map.setBaseLayer(layer);
+                } else if ( (c == "T") || (c == "F") ) {
+                    layer.setVisibility(c == "T");
+                }
+            }
+        }
+    },     
+
+    CLASS_NAME: "OpenLayers.Control.ArgParser"
+});
+/* ======================================================================
+    OpenLayers/Control/PanZoom.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ *
+ * Class: OpenLayers.PanZoom
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
+
+    /** 
+     * APIProperty: slideFactor
+     * {Integer}
+     */
+    slideFactor: 50,
+
+    /** 
+     * Property: buttons
+     * {Array(DOMElement)} Array of Button Divs 
+     */
+    buttons: null,
+
+    /** 
+     * Property: position
+     * {<OpenLayers.Pixel>} 
+     */
+    position: null,
+
+    /**
+     * Constructor: OpenLayers.Control.PanZoom
+     * 
+     * Parameters:
+     * options - {Object}
+     */
+    initialize: function(options) {
+        this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
+                                             OpenLayers.Control.PanZoom.Y);
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);
+        while(this.buttons.length) {
+            var btn = this.buttons.shift();
+            btn.map = null;
+            OpenLayers.Event.stopObservingElement(btn);
+        }
+        this.buttons = null;
+        this.position = null;
+    },
+
+    /**
+     * Method: draw
+     *
+     * Parameters:
+     * px - {<OpenLayers.Pixel>} 
+     * 
+     * Returns:
+     * {DOMElement} A reference to the container div for the PanZoom control.
+     */
+    draw: function(px) {
+        // initialize our internal div
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        px = this.position;
+
+        // place the controls
+        this.buttons = [];
+
+        var sz = new OpenLayers.Size(18,18);
+        var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
+
+        this._addButton("panup", "north-mini.png", centered, sz);
+        px.y = centered.y+sz.h;
+        this._addButton("panleft", "west-mini.png", px, sz);
+        this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
+        this._addButton("pandown", "south-mini.png", 
+                        centered.add(0, sz.h*2), sz);
+        this._addButton("zoomin", "zoom-plus-mini.png", 
+                        centered.add(0, sz.h*3+5), sz);
+        this._addButton("zoomworld", "zoom-world-mini.png", 
+                        centered.add(0, sz.h*4+5), sz);
+        this._addButton("zoomout", "zoom-minus-mini.png", 
+                        centered.add(0, sz.h*5+5), sz);
+        return this.div;
+    },
+    
+    /**
+     * Method: _addButton
+     * 
+     * Parameters:
+     * id - {String} 
+     * img - {String} 
+     * xy - {<OpenLayers.Pixel>} 
+     * sz - {<OpenLayers.Size>} 
+     * 
+     * Returns:
+     * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
+     *     image of the button, and has all the proper event handlers set.
+     */
+    _addButton:function(id, img, xy, sz) {
+        var imgLocation = OpenLayers.Util.getImagesLocation() + img;
+        var btn = OpenLayers.Util.createAlphaImageDiv(
+                                    "OpenLayers_Control_PanZoom_" + id, 
+                                    xy, sz, imgLocation, "absolute");
+
+        //we want to add the outer div
+        this.div.appendChild(btn);
+
+        OpenLayers.Event.observe(btn, "mousedown", 
+            OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
+        OpenLayers.Event.observe(btn, "dblclick", 
+            OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+        OpenLayers.Event.observe(btn, "click", 
+            OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+        btn.action = id;
+        btn.map = this.map;
+        btn.slideFactor = this.slideFactor;
+
+        //we want to remember/reference the outer div
+        this.buttons.push(btn);
+        return btn;
+    },
+    
+    /**
+     * Method: doubleClick
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean}
+     */
+    doubleClick: function (evt) {
+        OpenLayers.Event.stop(evt);
+        return false;
+    },
+    
+    /**
+     * Method: buttonDown
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    buttonDown: function (evt) {
+        if (!OpenLayers.Event.isLeftClick(evt)) return;
+
+        switch (this.action) {
+            case "panup": 
+                this.map.pan(0, -50);
+                break;
+            case "pandown": 
+                this.map.pan(0, 50);
+                break;
+            case "panleft": 
+                this.map.pan(-50, 0);
+                break;
+            case "panright": 
+                this.map.pan(50, 0);
+                break;
+            case "zoomin": 
+                this.map.zoomIn(); 
+                break;
+            case "zoomout": 
+                this.map.zoomOut(); 
+                break;
+            case "zoomworld": 
+                this.map.zoomToMaxExtent(); 
+                break;
+        }
+
+        OpenLayers.Event.stop(evt);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.PanZoom"
+});
+
+/**
+ * Constant: X
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.X = 4;
+
+/**
+ * Constant: Y
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.Y = 4;
+/* ======================================================================
+    OpenLayers/Events.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ *
+ * Namespace: OpenLayers.Event
+ * Utility functions for event handling.
+ */
+OpenLayers.Event = {
+
+    /** 
+     * Property: observers 
+     * {Object} A hashtable cache of the event observers. Keyed by
+     * element._eventCacheID 
+     */
+    observers: false,
+    
+    /** 
+     * Constant: KEY_BACKSPACE 
+     * {int} 
+     */
+    KEY_BACKSPACE: 8,
+
+    /** 
+     * Constant: KEY_TAB 
+     * {int} 
+     */
+    KEY_TAB: 9,
+
+    /** 
+     * Constant: KEY_RETURN 
+     * {int} 
+     */
+    KEY_RETURN: 13,
+
+    /** 
+     * Constant: KEY_ESC 
+     * {int} 
+     */
+    KEY_ESC: 27,
+
+    /** 
+     * Constant: KEY_LEFT 
+     * {int} 
+     */
+    KEY_LEFT: 37,
+
+    /** 
+     * Constant: KEY_UP 
+     * {int} 
+     */
+    KEY_UP: 38,
+
+    /** 
+     * Constant: KEY_RIGHT 
+     * {int} 
+     */
+    KEY_RIGHT: 39,
+
+    /** 
+     * Constant: KEY_DOWN 
+     * {int} 
+     */
+    KEY_DOWN: 40,
+
+    /** 
+     * Constant: KEY_DELETE 
+     * {int} 
+     */
+    KEY_DELETE: 46,
+
+
+    /**
+     * Method: element
+     * Cross browser event element detection.
+     * 
+     * Parameters:
+     * event - {Event} 
+     * 
+     * Returns:
+     * {DOMElement} The element that caused the event 
+     */
+    element: function(event) {
+        return event.target || event.srcElement;
+    },
+
+    /**
+     * Method: isLeftClick
+     * Determine whether event was caused by a left click. 
+     *
+     * Parameters:
+     * event - {Event} 
+     * 
+     * Returns:
+     * {Boolean}
+     */
+    isLeftClick: function(event) {
+        return (((event.which) && (event.which == 1)) ||
+                ((event.button) && (event.button == 1)));
+    },
+
+    /**
+     * Method: stop
+     * Stops an event from propagating. 
+     *
+     * Parameters: 
+     * event - {Event} 
+     * allowDefault - {Boolean} If true, we stop the event chain but 
+     *                               still allow the default browser 
+     *                               behaviour (text selection, radio-button 
+     *                               clicking, etc)
+     *                               Default false
+     */
+    stop: function(event, allowDefault) {
+        
+        if (!allowDefault) { 
+            if (event.preventDefault) {
+                event.preventDefault();
+            } else {
+                event.returnValue = false;
+            }
+        }
+                
+        if (event.stopPropagation) {
+            event.stopPropagation();
+        } else {
+            event.cancelBubble = true;
+        }
+    },
+
+    /** 
+     * Method: findElement
+     * 
+     * Parameters:
+     * event - {Event} 
+     * tagName - {String} 
+     * 
+     * Returns:
+     * {DOMElement} The first node with the given tagName, starting from the
+     * node the event was triggered on and traversing the DOM upwards
+     */
+    findElement: function(event, tagName) {
+        var element = OpenLayers.Event.element(event);
+        while (element.parentNode && (!element.tagName ||
+              (element.tagName.toUpperCase() != tagName.toUpperCase())))
+            element = element.parentNode;
+        return element;
+    },
+
+    /** 
+     * Method: observe
+     * 
+     * Parameters:
+     * elementParam - {DOMElement || String} 
+     * name - {String} 
+     * observer - {function} 
+     * useCapture - {Boolean} 
+     */
+    observe: function(elementParam, name, observer, useCapture) {
+        var element = OpenLayers.Util.getElement(elementParam);
+        useCapture = useCapture || false;
+
+        if (name == 'keypress' &&
+           (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+           || element.attachEvent)) {
+            name = 'keydown';
+        }
+
+        //if observers cache has not yet been created, create it
+        if (!this.observers) {
+            this.observers = {};
+        }
+
+        //if not already assigned, make a new unique cache ID
+        if (!element._eventCacheID) {
+            var idPrefix = "eventCacheID_";
+            if (element.id) {
+                idPrefix = element.id + "_" + idPrefix;
+            }
+            element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
+        }
+
+        var cacheID = element._eventCacheID;
+
+        //if there is not yet a hash entry for this element, add one
+        if (!this.observers[cacheID]) {
+            this.observers[cacheID] = [];
+        }
+
+        //add a new observer to this element's list
+        this.observers[cacheID].push({
+            'element': element,
+            'name': name,
+            'observer': observer,
+            'useCapture': useCapture
+        });
+
+        //add the actual browser event listener
+        if (element.addEventListener) {
+            element.addEventListener(name, observer, useCapture);
+        } else if (element.attachEvent) {
+            element.attachEvent('on' + name, observer);
+        }
+    },
+
+    /** 
+     * Method: stopObservingElement
+     * Given the id of an element to stop observing, cycle through the 
+     *   element's cached observers, calling stopObserving on each one, 
+     *   skipping those entries which can no longer be removed.
+     * 
+     * parameters:
+     * elementParam - {DOMElement || String} 
+     */
+    stopObservingElement: function(elementParam) {
+        var element = OpenLayers.Util.getElement(elementParam);
+        var cacheID = element._eventCacheID;
+
+        this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
+    },
+
+    /**
+     * Method: _removeElementObservers
+     *
+     * Parameters:
+     * elementObservers - {Array(Object)} Array of (element, name, 
+     *                                         observer, usecapture) objects, 
+     *                                         taken directly from hashtable
+     */
+    _removeElementObservers: function(elementObservers) {
+        if (elementObservers) {
+            for(var i = elementObservers.length-1; i >= 0; i--) {
+                var entry = elementObservers[i];
+                var args = new Array(entry.element,
+                                     entry.name,
+                                     entry.observer,
+                                     entry.useCapture);
+                var removed = OpenLayers.Event.stopObserving.apply(this, args);
+            }
+        }
+    },
+
+    /**
+     * Method: stopObserving
+     * 
+     * Parameters:
+     * elementParam - {DOMElement || String} 
+     * name - {String} 
+     * observer - {function} 
+     * useCapture - {Boolean} 
+     *  
+     * Returns:
+     * {Boolean} Whether or not the event observer was removed
+     */
+    stopObserving: function(elementParam, name, observer, useCapture) {
+        useCapture = useCapture || false;
+    
+        var element = OpenLayers.Util.getElement(elementParam);
+        var cacheID = element._eventCacheID;
+
+        if (name == 'keypress') {
+            if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || 
+                 element.detachEvent) {
+              name = 'keydown';
+            }
+        }
+
+        // find element's entry in this.observers cache and remove it
+        var foundEntry = false;
+        var elementObservers = OpenLayers.Event.observers[cacheID];
+        if (elementObservers) {
+    
+            // find the specific event type in the element's list
+            var i=0;
+            while(!foundEntry && i < elementObservers.length) {
+                var cacheEntry = elementObservers[i];
+    
+                if ((cacheEntry.name == name) &&
+                    (cacheEntry.observer == observer) &&
+                    (cacheEntry.useCapture == useCapture)) {
+    
+                    elementObservers.splice(i, 1);
+                    if (elementObservers.length == 0) {
+                        delete OpenLayers.Event.observers[cacheID];
+                    }
+                    foundEntry = true;
+                    break; 
+                }
+                i++;           
+            }
+        }
+    
+        //actually remove the event listener from browser
+        if (element.removeEventListener) {
+            element.removeEventListener(name, observer, useCapture);
+        } else if (element && element.detachEvent) {
+            element.detachEvent('on' + name, observer);
+        }
+        return foundEntry;
+    },
+    
+    /** 
+     * Method: unloadCache
+     * Cycle through all the element entries in the events cache and call
+     *   stopObservingElement on each. 
+     */
+    unloadCache: function() {
+        if (OpenLayers.Event.observers) {
+            for (var cacheID in OpenLayers.Event.observers) {
+                var elementObservers = OpenLayers.Event.observers[cacheID];
+                OpenLayers.Event._removeElementObservers.apply(this, 
+                                                           [elementObservers]);
+            }
+            OpenLayers.Event.observers = false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Event"
+};
+
+/* prevent memory leaks in IE */
+OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
+
+// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
+// by OpenLayers.
+if (window.Event) {
+    OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
+} else {
+    var Event = OpenLayers.Event;
+}
+
+/**
+ * Class: OpenLayers.Events
+ */
+OpenLayers.Events = OpenLayers.Class({
+
+    /** 
+     * Constant: BROWSER_EVENTS
+     * {Array(String)} supported events 
+     */
+    BROWSER_EVENTS: [
+        "mouseover", "mouseout",
+        "mousedown", "mouseup", "mousemove", 
+        "click", "dblclick",
+        "resize", "focus", "blur"
+    ],
+
+    /** 
+     * Property: listeners 
+     * {Object} Hashtable of Array(Function): events listener functions  
+     */
+    listeners: null,
+
+    /** 
+     * Property: object 
+     * {Object}  the code object issuing application events 
+     */
+    object: null,
+
+    /** 
+     * Property: element 
+     * {DOMElement}  the DOM element receiving browser events 
+     */
+    element: null,
+
+    /** 
+     * Property: eventTypes 
+     * {Array(String)}  list of support application events 
+     */
+    eventTypes: null,
+
+    /** 
+     * Property: eventHandler 
+     * {Function}  bound event handler attached to elements 
+     */
+    eventHandler: null,
+
+    /** 
+     * APIProperty: fallThrough 
+     * {Boolean} 
+     */
+    fallThrough: null,
+
+    /**
+     * Constructor: OpenLayers.Events
+     * Construct an OpenLayers.Events object.
+     *
+     * Parameters:
+     * object - {Object} The js object to which this Events object  is being
+     * added element - {DOMElement} A dom element to respond to browser events
+     * eventTypes - {Array(String)} Array of custom application events 
+     * fallThrough - {Boolean} Allow events to fall through after these have
+     *                         been handled?
+     */
+    initialize: function (object, element, eventTypes, fallThrough) {
+        this.object     = object;
+        this.element    = element;
+        this.eventTypes = eventTypes;
+        this.fallThrough = fallThrough;
+        this.listeners  = {};
+
+        // keep a bound copy of handleBrowserEvent() so that we can
+        // pass the same function to both Event.observe() and .stopObserving()
+        this.eventHandler = OpenLayers.Function.bindAsEventListener(
+            this.handleBrowserEvent, this
+        );
+
+        // if eventTypes is specified, create a listeners list for each 
+        // custom application event.
+        if (this.eventTypes != null) {
+            for (var i = 0; i < this.eventTypes.length; i++) {
+                this.addEventType(this.eventTypes[i]);
+            }
+        }
+        
+        // if a dom element is specified, add a listeners list 
+        // for browser events on the element and register them
+        if (this.element != null) {
+            this.attachToElement(element);
+        }
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function () {
+        if (this.element) {
+            OpenLayers.Event.stopObservingElement(this.element);
+        }
+        this.element = null;
+
+        this.listeners = null;
+        this.object = null;
+        this.eventTypes = null;
+        this.fallThrough = null;
+        this.eventHandler = null;
+    },
+
+    /**
+     * APIMethod: addEventType
+     * Add a new event type to this events object.
+     * If the event type has already been added, do nothing.
+     * 
+     * Parameters:
+     * eventName - {String}
+     */
+    addEventType: function(eventName) {
+        if (!this.listeners[eventName]) {
+            this.listeners[eventName] = [];
+        }
+    },
+
+    /**
+     * Method: attachToElement
+     *
+     * Parameters:
+     * element - {HTMLDOMElement} a DOM element to attach browser events to
+     */
+    attachToElement: function (element) {
+        for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
+            var eventType = this.BROWSER_EVENTS[i];
+
+            // every browser event has a corresponding application event 
+            // (whether it's listened for or not).
+            this.addEventType(eventType);
+            
+            // use Prototype to register the event cross-browser
+            OpenLayers.Event.observe(element, eventType, this.eventHandler);
+        }
+        // disable dragstart in IE so that mousedown/move/up works normally
+        OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
+    },
+
+    /**
+     * APIMethod: register
+     * Register an event on the events object.
+     *
+     * When the event is triggered, the 'func' function will be called, in the
+     * context of 'obj'. Imagine we were to register an event, specifying an 
+     * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the 
+     * context in the callback function will be our Bounds object. This means
+     * that within our callback function, we can access the properties and 
+     * methods of the Bounds object through the "this" variable. So our 
+     * callback could execute something like: 
+     * :    leftStr = "Left: " + this.left;
+     *   
+     *                   or
+     *  
+     * :    centerStr = "Center: " + this.getCenterLonLat();
+     *
+     * Parameters:
+     * type - {String} Name of the event to register
+     * obj - {Object} The object to bind the context to for the callback#.
+     *                     If no object is specified, default is the Events's 
+     *                     'object' property.
+     * func - {Function} The callback function. If no callback is 
+     *                        specified, this function does nothing.
+     * 
+     * 
+     */
+    register: function (type, obj, func) {
+
+        if (func != null) {
+            if (obj == null)  {
+                obj = this.object;
+            }
+            var listeners = this.listeners[type];
+            if (listeners != null) {
+                listeners.push( {obj: obj, func: func} );
+            }
+        }
+    },
+
+    /**
+     * APIMethod: registerPriority
+     * Same as register() but adds the new listener to the *front* of the
+     *     events queue instead of to the end.
+     *    
+     *     TODO: get rid of this in 3.0 - Decide whether listeners should be 
+     *     called in the order they were registered or in reverse order.
+     *
+     *
+     * Parameters:
+     * type - {String} Name of the event to register
+     * obj - {Object} The object to bind the context to for the callback#.
+     *                If no object is specified, default is the Events's 
+     *                'object' property.
+     * func - {Function} The callback function. If no callback is 
+     *                   specified, this function does nothing.
+     */
+    registerPriority: function (type, obj, func) {
+
+        if (func != null) {
+            if (obj == null)  {
+                obj = this.object;
+            }
+            var listeners = this.listeners[type];
+            if (listeners != null) {
+                listeners.unshift( {obj: obj, func: func} );
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: unregister
+     *
+     * Parameters:
+     * type - {String} 
+     * obj - {Object} If none specified, defaults to this.object
+     * func - {Function} 
+     */
+    unregister: function (type, obj, func) {
+        if (obj == null)  {
+            obj = this.object;
+        }
+        var listeners = this.listeners[type];
+        if (listeners != null) {
+            for (var i = 0; i < listeners.length; i++) {
+                if (listeners[i].obj == obj && listeners[i].func == func) {
+                    listeners.splice(i, 1);
+                    break;
+                }
+            }
+        }
+    },
+
+    /** 
+     * Method: remove
+     * Remove all listeners for a given event type. If type is not registered,
+     *     does nothing.
+     *
+     * Parameters:
+     * type - {String} 
+     */
+    remove: function(type) {
+        if (this.listeners[type] != null) {
+            this.listeners[type] = [];
+        }
+    },
+
+    /**
+     * APIMethod: triggerEvent
+     * Trigger a specified registered event
+     * 
+     * Parameters:
+     * type - {String} 
+     * evt - {Event} 
+     */
+    triggerEvent: function (type, evt) {
+
+        // prep evt object with object & div references
+        if (evt == null) {
+            evt = {};
+        }
+        evt.object = this.object;
+        evt.element = this.element;
+
+        // execute all callbacks registered for specified type
+        // get a clone of the listeners array to
+        // allow for splicing during callbacks
+        var listeners = (this.listeners[type]) ?
+                            this.listeners[type].slice() : null;
+        if ((listeners != null) && (listeners.length > 0)) {
+            for (var i = 0; i < listeners.length; i++) {
+                var callback = listeners[i];
+                var continueChain;
+                if (callback.obj != null) {
+                    // use the 'call' method to bind the context to callback.obj
+                    continueChain = callback.func.call(callback.obj, evt);
+                } else {
+                    continueChain = callback.func(evt);
+                }
+    
+                if ((continueChain != null) && (continueChain == false)) {
+                    // if callback returns false, execute no more callbacks.
+                    break;
+                }
+            }
+            // don't fall through to other DOM elements
+            if (!this.fallThrough) {           
+                OpenLayers.Event.stop(evt, true);
+            }
+        }
+    },
+
+    /**
+     * Method: handleBrowserEvent
+     * Basically just a wrapper to the triggerEvent() function, but takes 
+     *     care to set a property 'xy' on the event with the current mouse 
+     *     position.
+     *
+     * Parameters:
+     * evt - {Event} 
+     */
+    handleBrowserEvent: function (evt) {
+        evt.xy = this.getMousePosition(evt); 
+        this.triggerEvent(evt.type, evt)
+    },
+
+    /**
+     * Method: getMousePosition
+     * 
+     * Parameters:
+     * evt - {Event} 
+     * 
+     * Returns 
+     * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
+     *                      for offsets
+     */
+    getMousePosition: function (evt) {
+        if (!this.element.offsets) {
+            this.element.offsets = OpenLayers.Util.pagePosition(this.element);
+            this.element.offsets[0] += (document.documentElement.scrollLeft
+                         || document.body.scrollLeft);
+            this.element.offsets[1] += (document.documentElement.scrollTop
+                         || document.body.scrollTop);
+        }
+        return new OpenLayers.Pixel(
+            (evt.clientX + (document.documentElement.scrollLeft
+                         || document.body.scrollLeft)) - this.element.offsets[0]
+                         - (document.documentElement.clientLeft || 0), 
+            (evt.clientY + (document.documentElement.scrollTop
+                         || document.body.scrollTop)) - this.element.offsets[1]
+                         - (document.documentElement.clientTop || 0)
+        ); 
+    },
+
+    CLASS_NAME: "OpenLayers.Events"
+});
+/* ======================================================================
+    OpenLayers/Projection.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ * 
+ * Class: OpenLayers.Projection
+ * Class for coordinate transformations between coordinate systems.
+ * Depends on the proj4js library. If proj4js is not available, 
+ * then this is just an empty stub.
+ */
+OpenLayers.Projection = OpenLayers.Class({
+    
+    /**
+     * Constructor: OpenLayers.Projection
+     * This class offers several methods for interacting with a wrapped 
+     * pro4js projection object. 
+     *
+     * Parameters:
+     * options - {Object} An optional object with properties to set on the
+     *           format
+     *
+     * Returns:
+     * An instance of OpenLayers.Projection
+     */
+    initialize: function(projCode, options) {
+        OpenLayers.Util.extend(this, options);
+        this.projCode = projCode;
+        if (window.Proj4js) {
+            this.proj = new Proj4js.Proj(projCode);
+        }
+        
+    },
+    
+    /**
+     * APIMethod: getCode
+     * Get the string SRS code.
+     */
+    getCode: function() {
+        return this.proj ? this.proj.srsCode : this.projCode;
+    },
+    
+    /**
+     * APIMethod: getUnits
+     * Get the units string for the projection -- returns null if 
+     * proj4js is not available..
+     */
+    getUnits: function() {
+        return this.proj ? this.proj.units : null;
+    },
+
+    CLASS_NAME: "OpenLayers.Projection" 
+
+});     
+
+/**
+ * APIMethod: transform
+ * Read data from a string, and return an object whose type depends on the
+ * subclass. 
+ * 
+ * Parameters:
+ * point - {object} input horizontal coodinate
+ * sourceProj - {OpenLayers.Projection} source map coordinate system
+ * destProj - {OpenLayers.Projection} destination map coordinate system
+ *
+ * Returns:
+ * point - {object} trasnformed coordinate
+ */
+OpenLayers.Projection.transform = function(point, source, dest) {
+    if (source.proj && dest.proj) {
+        point = Proj4js.transform(source.proj, dest.proj, point);
+    }
+    return point;
+};
+/* ======================================================================
+    OpenLayers/Tile.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/*
+ * @requires OpenLayers/Util.js
+ *
+ * Class: OpenLayers.Tile 
+ * This is a class designed to designate a single tile, however
+ *     it is explicitly designed to do relatively little. Tiles store 
+ *     information about themselves -- such as the URL that they are related
+ *     to, and their size - but do not add themselves to the layer div 
+ *     automatically, for example. Create a new tile with the 
+ *     <OpenLayers.Tile> constructor, or a subclass. 
+ * 
+ * TBD 3.0 - remove reference to url in above paragraph
+ * 
+ */
+OpenLayers.Tile = OpenLayers.Class({
+    
+    /** 
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types
+     */
+    EVENT_TYPES: [ "loadstart", "loadend", "reload"],
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *                       events on the tile.
+     */
+    events: null,
+
+    /**
+     * Property: id 
+     * {String} null
+     */
+    id: null,
+    
+    /** 
+     * Property: layer 
+     * {<OpenLayers.Layer>} layer the tile is attached to 
+     */
+    layer: null,
+    
+    /**
+     * Property: url
+     * {String} url of the request.
+     *
+     * TBD 3.0 
+     * Deprecated. The base tile class does not need an url. This should be 
+     * handled in subclasses. Does not belong here.
+     */
+    url: null,
+
+    /** 
+     * APIProperty: bounds 
+     * {<OpenLayers.Bounds>} null
+     */
+    bounds: null,
+    
+    /** 
+     * Property: size 
+     * {<OpenLayers.Size>} null
+     */
+    size: null,
+    
+    /** 
+     * Property: position 
+     * {<OpenLayers.Pixel>} Top Left pixel of the tile
+     */    
+    position: null,
+
+    /**
+     * Property: isLoading
+     * {Boolean} Is the tile loading?
+     */
+    isLoading: false,
+    
+    /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
+     *             there is no need for the base tile class to have a url.
+     * 
+     * Constructor: OpenLayers.Tile
+     * Constructor for a new <OpenLayers.Tile> instance.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+     * position - {<OpenLayers.Pixel>}
+     * bounds - {<OpenLayers.Bounds>}
+     * url - {<String>}
+     * size - {<OpenLayers.Size>}
+     */   
+    initialize: function(layer, position, bounds, url, size) {
+        this.layer = layer;
+        this.position = position.clone();
+        this.bounds = bounds.clone();
+        this.url = url;
+        this.size = size.clone();
+
+        //give the tile a unique id based on its BBOX.
+        this.id = OpenLayers.Util.createUniqueID("Tile_");
+        
+        this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+    },
+    
+    /** 
+     * APIMethod: destroy
+     * Nullify references to prevent circular references and memory leaks.
+     */
+    destroy:function() {
+        this.layer  = null;
+        this.bounds = null;
+        this.size = null;
+        this.position = null;
+        
+        this.events.destroy();
+        this.events = null;
+    },
+
+    /**
+     * Method: draw
+     * Clear whatever is currently in the tile, then return whether or not 
+     *     it should actually be re-drawn.
+     * 
+     * Returns:
+     * {Boolean} Whether or not the tile should actually be drawn. Note that 
+     *     this is not really the best way of doing things, but such is 
+     *     the way the code has been developed. Subclasses call this and
+     *     depend on the return to know if they should draw or not.
+     */
+    draw: function() {
+        
+        //clear tile's contents and mark as not drawn
+        this.clear();
+        
+        var maxExtent = this.layer.maxExtent;
+        var withinMaxExtent = true;
+        if (this.layer.restrictedExtent) {
+          withinMaxExtent = (maxExtent &&
+                               this.bounds.intersectsBounds(maxExtent, false));
+        }
+ 
+        // The only case where we *wouldn't* want to draw the tile is if the 
+        // tile is outside its layer's maxExtent.
+        return (withinMaxExtent || this.layer.displayOutsideMaxExtent);
+    },
+    
+    /** 
+     * Method: moveTo
+     * Reposition the tile.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * position - {<OpenLayers.Pixel>}
+     * redraw - {Boolean} Call draw method on tile after moving.
+     *     Default is true
+     */
+    moveTo: function (bounds, position, redraw) {
+        if (redraw == null) {
+            redraw = true;
+        }
+
+        this.bounds = bounds.clone();
+        this.position = position.clone();
+        if (redraw) {
+            this.draw();
+        }
+    },
+
+    /** 
+     * Method: clear
+     * Clear the tile of any bounds/position-related data so that it can 
+     *     be reused in a new location. To be implemented by subclasses.
+     */
+    clear: function() {
+        // to be implemented by subclasses
+    },
+    
+    /**   
+     * Method: getBoundsFromBaseLayer
+     * Take the pixel locations of the corner of the tile, and pass them to 
+     *     the base layer and ask for the location of those pixels, so that 
+     *     displaying tiles over Google works fine.
+     *
+     * Parameters:
+     * position - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * bounds - {<OpenLayers.Bounds>} 
+     */
+    getBoundsFromBaseLayer: function(position) {
+        OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded", 
+                                                            this.layer.name)); 
+        var topLeft = this.layer.map.getLonLatFromLayerPx(position); 
+        var bottomRightPx = position.clone();
+        bottomRightPx.x += this.size.w;
+        bottomRightPx.y += this.size.h;
+        var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx); 
+        // Handle the case where the base layer wraps around the date line.
+        // Google does this, and it breaks WMS servers to request bounds in 
+        // that fashion.  
+        if (topLeft.lon > bottomRight.lon) {
+            if (topLeft.lon < 0) {
+                topLeft.lon = -180 - (topLeft.lon+180);
+            } else {
+                bottomRight.lon = 180+bottomRight.lon+180;
+            }        
+        }
+        bounds = new OpenLayers.Bounds(topLeft.lon, 
+                                       bottomRight.lat, 
+                                       bottomRight.lon, 
+                                       topLeft.lat);  
+        return bounds;
+    },        
+
+    CLASS_NAME: "OpenLayers.Tile"
+});
+/* ======================================================================
+    OpenLayers/Control/OverviewMap.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/** 
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Events.js
+ *
+ * Class: OpenLayers.Control.OverviewMap
+ * Create an overview map to display the extent of your main map and provide
+ * additional navigation control.  Create a new overview map with the
+ * <OpenLayers.Control.OverviewMap> constructor.
+ *
+ * Inerits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
+
+    /**
+     * Property: id
+     * {String} For div.id
+     */
+    id:  "OverviewMap",
+
+    /**
+     * Property: element
+     * {DOMElement} The DOM element that contains the overview map
+     */
+    element: null,
+    
+    /**
+     * APIProperty: ovmap
+     * {<OpenLayers.Map>} A reference to the overvew map itself.
+     */
+    ovmap: null,
+        
+    /**
+     * APIProperty: size
+     * {<OpenLayers.Size>} The overvew map size in pixels.  Note that this is
+     * the size of the map itself - the element that contains the map (default
+     * class name olControlOverviewMapElement) may have padding or other style
+     * attributes added via CSS.
+     */
+    size: new OpenLayers.Size(180, 90),
+
+    /**
+     * APIProperty: layers
+     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
+     * If none are sent at construction, the base layer for the main map is used.
+     */
+    layers: null,
+
+    /**
+     * APIProperty: minRatio
+     * {Float} The ratio of the overview map resolution to the main map
+     * resolution at which to zoom farther out on the overview map.
+     */
+    minRatio: 8,
+
+    /**
+     * APIProperty: maxRatio
+     * {Float} The ratio of the overview map resolution to the main map
+     * resolution at which to zoom farther in on the overview map.
+     */
+    maxRatio: 32,
+
+    /**
+     * APIProperty: mapOptions
+     * {Object} An object containing any non-default properties to be sent to
+     * the overview map's map constructor.  These should include any non-default
+     * options that the main map was constructed with.
+     */
+    mapOptions: null,
+
+    /**
+     * Constructor: OpenLayers.Control.OverviewMap
+     * Create a new overview map
+     *
+     * Parameters:
+     * object - {Object} Properties of this object will be set on the overview
+     * map object.  Note, to set options on the map object contained in this
+     * control, set <mapOptions> as one of the options properties.
+     */
+    initialize: function(options) {
+        this.layers = [];
+        OpenLayers.Control.prototype.initialize.apply(this, [options]);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Deconstruct the control
+     */
+    destroy: function() {
+        if (!this.mapDiv) { // we've already been destroyed
+            return;
+        }
+        this.mapDiv.removeChild(this.extentRectangle);
+        this.extentRectangle = null;
+        this.rectEvents.destroy();
+        this.rectEvents = null;
+
+        this.ovmap.destroy();
+        this.ovmap = null;
+        
+        this.element.removeChild(this.mapDiv);
+        this.mapDiv = null;
+        this.mapDivEvents.destroy(); 
+        this.mapDivEvents = null;
+
+        this.div.removeChild(this.element);
+        this.element = null;
+        this.elementEvents.destroy();
+        this.elementEvents = null;
+
+        if (this.maximizeDiv) {
+            OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+            this.div.removeChild(this.maximizeDiv);
+            this.maximizeDiv = null;
+        }
+        
+        if (this.minimizeDiv) {
+            OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+            this.div.removeChild(this.minimizeDiv);
+            this.minimizeDiv = null;
+        }
+        
+        this.map.events.unregister('moveend', this, this.update);
+        this.map.events.unregister("changebaselayer", this, 
+                                    this.baseLayerDraw);
+
+        OpenLayers.Control.prototype.destroy.apply(this, arguments);    
+    },
+
+    /**
+     * Method: draw
+     * Render the control in the browser.
+     */    
+    draw: function() {
+        OpenLayers.Control.prototype.draw.apply(this, arguments);
+        if(!(this.layers.length > 0)) {
+            if (this.map.baseLayer) {
+                var layer = this.map.baseLayer.clone();
+                this.layers = [layer];
+            } else {
+                this.map.events.register("changebaselayer", this, this.baseLayerDraw);
+                return this.div;
+            }
+        }
+
+        // create overview map DOM elements
+        this.element = document.createElement('div');
+        this.element.className = this.displayClass + 'Element';
+        this.element.style.display = 'none';
+
+        this.mapDiv = document.createElement('div');
+        this.mapDiv.style.width = this.size.w + 'px';
+        this.mapDiv.style.height = this.size.h + 'px';
+        this.mapDiv.style.position = 'relative';
+        this.mapDiv.style.overflow = 'hidden';
+        this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
+        
+        this.extentRectangle = document.createElement('div');
+        this.extentRectangle.style.position = 'absolute';
+        this.extentRectangle.style.zIndex = 1000;  //HACK
+        this.extentRectangle.style.overflow = 'hidden';
+        this.extentRectangle.style.backgroundImage = 'url(' +
+                                        OpenLayers.Util.getImagesLocation() +
+                                        'blank.gif)';
+        this.extentRectangle.className = this.displayClass+'ExtentRectangle';
+        this.mapDiv.appendChild(this.extentRectangle);
+                
+        this.element.appendChild(this.mapDiv);  
+
+        this.div.appendChild(this.element);
+
+        this.map.events.register('moveend', this, this.update);
+        
+        // Set up events.  The image div recenters the map on click.
+        // The extent rectangle can be dragged to recenter the map.
+        // If the mousedown happened elsewhere, then mousemove and mouseup
+        // should slip through.
+        this.elementEvents = new OpenLayers.Events(this, this.element);
+        this.elementEvents.register('mousedown', this, function(e) {
+            OpenLayers.Event.stop(e);
+        });
+        this.elementEvents.register('click', this, function(e) {
+            OpenLayers.Event.stop(e);
+        });
+        this.elementEvents.register('dblclick', this, function(e) {
+            OpenLayers.Event.stop(e);
+        });
+        this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
+                                                null, true);
+        this.rectEvents.register('mouseout', this, this.rectMouseOut);
+        this.rectEvents.register('mousedown', this, this.rectMouseDown);
+        this.rectEvents.register('mousemove', this, this.rectMouseMove);
+        this.rectEvents.register('mouseup', this, this.rectMouseUp);
+        this.rectEvents.register('click', this, function(e) {
+            OpenLayers.Event.stop(e);
+        });
+        this.rectEvents.register('dblclick', this, this.rectDblClick );
+        this.mapDivEvents = new OpenLayers.Events(this, this.mapDiv);
+        this.mapDivEvents.register('click', this, this.mapDivClick);
+
+        // Optionally add min/max buttons if the control will go in the
+        // map viewport.
+        if(!this.outsideViewport) {
+            this.div.className = this.displayClass + 'Container';
+            var imgLocation = OpenLayers.Util.getImagesLocation();
+            // maximize button div
+            var img = imgLocation + 'layer-switcher-maximize.png';
+            this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                        this.displayClass + 'MaximizeButton', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
+                                        'absolute');
+            this.maximizeDiv.style.display = 'none';
+            this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
+            OpenLayers.Event.observe(this.maximizeDiv, 'click', 
+                OpenLayers.Function.bindAsEventListener(this.maximizeControl,
+                                                        this)
+            );
+            this.div.appendChild(this.maximizeDiv);
+    
+            // minimize button div
+            var img = imgLocation + 'layer-switcher-minimize.png';
+            this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+                                        'OpenLayers_Control_minimizeDiv', 
+                                        null, 
+                                        new OpenLayers.Size(18,18), 
+                                        img, 
+                                        'absolute');
+            this.minimizeDiv.style.display = 'none';
+            this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
+            OpenLayers.Event.observe(this.minimizeDiv, 'click', 
+                OpenLayers.Function.bindAsEventListener(this.minimizeControl,
+                                                        this)
+            );
+            this.div.appendChild(this.minimizeDiv);
+            
+            var eventsToStop = ['dblclick','mousedown'];
+            
+            for (var i = 0; i < eventsToStop.length; i++) {
+
+                OpenLayers.Event.observe(this.maximizeDiv, 
+                                         eventsToStop[i], 
+                                         OpenLayers.Event.stop);
+
+                OpenLayers.Event.observe(this.minimizeDiv,
+                                         eventsToStop[i], 
+                                         OpenLayers.Event.stop);
+            }
+            
+            this.minimizeControl();
+        } else {
+            // show the overview map
+            this.element.style.display = '';
+        }
+        if(this.map.getExtent()) {
+            this.update();
+        }
+        return this.div;
+    },
+    
+    /**
+     * Method: baseLayerDraw
+     * Draw the base layer - called if unable to complete in the initial draw
+     */
+    baseLayerDraw: function() {
+        this.draw();
+        this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
+    },
+
+    /**
+     * Method: rectMouseOut
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    rectMouseOut: function (evt) {
+        if(this.rectDragStart != null) {
+            if(this.performedRectDrag) {
+                this.rectMouseMove(evt);
+                var rectPxBounds = this.getRectPxBounds(); 
+                // if we're off of the overview map, update the main map
+                // otherwise, keep moving the rect
+                if((rectPxBounds.top <= 0) || (rectPxBounds.left <= 0) || 
+                   (rectPxBounds.bottom >= this.size.h - this.hComp) || 
+                   (rectPxBounds.right >= this.size.w - this.wComp)) {
+                    this.updateMapToRect();
+                } else {
+                    return; 
+                }
+            }
+            document.onselectstart = null;
+            this.rectDragStart = null;
+        }
+    },
+
+    /**
+     * Method: rectMouseDown
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    rectMouseDown: function (evt) {
+        if(!OpenLayers.Event.isLeftClick(evt)) return;
+        this.rectDragStart = evt.xy.clone();
+        this.performedRectDrag = false;
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: rectMouseMove
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    rectMouseMove: function(evt) {
+        if(this.rectDragStart != null) {
+            var deltaX = this.rectDragStart.x - evt.xy.x;
+            var deltaY = this.rectDragStart.y - evt.xy.y;
+            var rectPxBounds = this.getRectPxBounds();
+            var rectTop = rectPxBounds.top;
+            var rectLeft = rectPxBounds.left;
+            var rectHeight = Math.abs(rectPxBounds.getHeight());
+            var rectWidth = rectPxBounds.getWidth();
+            // don't allow dragging off of parent element
+            var newTop = Math.max(0, (rectTop - deltaY));
+            newTop = Math.min(newTop,
+                              this.ovmap.size.h - this.hComp - rectHeight);
+            var newLeft = Math.max(0, (rectLeft - deltaX));
+            newLeft = Math.min(newLeft,
+                               this.ovmap.size.w - this.wComp - rectWidth);
+            this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+                                                       newTop + rectHeight,
+                                                       newLeft + rectWidth,
+                                                       newTop));
+            this.rectDragStart = evt.xy.clone();
+            this.performedRectDrag = true;
+            OpenLayers.Event.stop(evt);
+        }
+    },
+
+    /**
+     * Method: rectMouseUp
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    rectMouseUp: function(evt) {
+        if(!OpenLayers.Event.isLeftClick(evt)) return;
+        if(this.performedRectDrag) {
+            this.updateMapToRect();
+            OpenLayers.Event.stop(evt);
+        }        
+        document.onselectstart = null;
+        this.rectDragStart = null;
+    },
+    
+    /**
+     * Method: rectDblClick
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    rectDblClick: function(evt) {
+        this.performedRectDrag = false;
+        OpenLayers.Event.stop(evt);
+        this.updateOverview();
+    },
+
+    /**
+     * Method: mapDivClick
+     * Handle browser events
+     *
+     * Parameters:
+     * evt - {<OpenLayers.Event>} evt
+     */
+    mapDivClick: function(evt) {
+        var pxBounds = this.getRectPxBounds();
+        var pxCenter = pxBounds.getCenterPixel();
+        var deltaX = evt.xy.x - pxCenter.x;
+        var deltaY = evt.xy.y - pxCenter.y;
+        var top = pxBounds.top;
+        var left = pxBounds.left;
+        var height = Math.abs(pxBounds.getHeight());
+        var width = pxBounds.getWidth();
+        var newTop = Math.max(0, (top + deltaY));
+        newTop = Math.min(newTop, this.ovmap.size.h - height);
+        var newLeft = Math.max(0, (left + deltaX));
+        newLeft = Math.min(newLeft, this.ovmap.size.w - width);
+        this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+                                                   newTop + height,
+                                                   newLeft + width,
+                                                   newTop));
+        this.updateMapToRect();
+        OpenLayers.Event.stop(evt);
+    },
+
+    /**
+     * Method: maximizeControl
+     * Unhide the control.  Called when the control is in the map viewport.
+     *
+     * Parameters:
+     * e - {<OpenLayers.Event>}
+     */
+    maximizeControl: function(e) {
+        this.element.style.display = '';
+        this.showToggle(false);
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+
+    /**
+     * Method: minimizeControl
+     * Hide all the contents of the control, shrink the size, 
+     * add the maximize icon
+     * 
+     * Parameters:
+     * e - {<OpenLayers.Event>}
+     */
+    minimizeControl: function(e) {
+        this.element.style.display = 'none';
+        this.showToggle(true);
+        if (e != null) {
+            OpenLayers.Event.stop(e);                                            
+        }
+    },
+
+    /**
+     * Method: showToggle
+     * Hide/Show the toggle depending on whether the control is minimized
+     *
+     * Parameters:
+     * minimize - {Boolean} 
+     */
+    showToggle: function(minimize) {
+        this.maximizeDiv.style.display = minimize ? '' : 'none';
+        this.minimizeDiv.style.display = minimize ? 'none' : '';
+    },
+
+    /**
+     * Method: update
+     * Update the overview map after layers move.
+     */
+    update: function() {
+        if(this.ovmap == null) {
+            this.createMap();
+        }
+        
+        if(!this.isSuitableOverview()) {
+            this.updateOverview();
+        }
+        
+        // update extent rectangle
+        this.updateRectToMap();
+    },
+    
+    /**
+     * Method: isSuitableOverview
+     * Determines if the overview map is suitable given the extent and
+     * resolution of the main map.
+     */
+    isSuitableOverview: function() {
+        var mapExtent = this.map.getExtent();
+        var maxExtent = this.map.maxExtent;
+        var testExtent = new OpenLayers.Bounds(
+                                Math.max(mapExtent.left, maxExtent.left),
+                                Math.max(mapExtent.bottom, maxExtent.bottom),
+                                Math.min(mapExtent.right, maxExtent.right),
+                                Math.min(mapExtent.top, maxExtent.top));        
+        var resRatio = this.ovmap.getResolution() / this.map.getResolution();
+        return ((resRatio > this.minRatio) &&
+                (resRatio <= this.maxRatio) &&
+                (this.ovmap.getExtent().containsBounds(testExtent)));
+    },
+    
+    /**
+     * Method updateOverview
+     * Called by <update> if <isSuitableOverview> returns true
+     */
+    updateOverview: function() {
+        var mapRes = this.map.getResolution();
+        var targetRes = this.ovmap.getResolution();
+        var resRatio = targetRes / mapRes;
+        if(resRatio > this.maxRatio) {
+            // zoom in overview map
+            targetRes = this.minRatio * mapRes;            
+        } else if(resRatio <= this.minRatio) {
+            // zoom out overview map
+            targetRes = this.maxRatio * mapRes;
+        }
+        this.ovmap.setCenter(this.map.center,
+                            this.ovmap.getZoomForResolution(targetRes));
+        this.updateRectToMap();
+    },
+    
+    /**
+     * Method: createMap
+     * Construct the map that this control contains
+     */
+    createMap: function() {
+        // create the overview map
+        var options = OpenLayers.Util.extend(
+                        {controls: [], maxResolution: 'auto'}, this.mapOptions);
+        this.ovmap = new OpenLayers.Map(this.mapDiv, options);
+        this.ovmap.addLayers(this.layers);
+        this.ovmap.zoomToMaxExtent();
+        // check extent rectangle border width
+        this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-left-width')) +
+                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-right-width'));
+        this.wComp = (this.wComp) ? this.wComp : 2;
+        this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-top-width')) +
+                     parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+                                               'border-bottom-width'));
+        this.hComp = (this.hComp) ? this.hComp : 2;
+    },
+        
+    /**
+     * Method: updateRectToMap
+     * Updates the extent rectangle position and size to match the map extent
+     */
+    updateRectToMap: function() {
+        // The base layer for overview map needs to be in the same projection
+        // as the base layer for the main map.  This should be made more robust.
+        /*if(this.map.units != 'degrees') {
+            if(this.ovmap.getProjection() && (this.map.getProjection() != this.ovmap.getProjection())) {
+                alert(OpenLayers.String.translate("sameProjection"));
+            }
+        }*/
+        var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
+        if (pxBounds) {
+          this.setRectPxBounds(pxBounds);
+        }
+    },
+    
+    /**
+     * Method: updateMapToRect
+     * Updates the map extent to match the extent rectangle position and size
+     */
+    updateMapToRect: function() {
+        var pxBounds = this.getRectPxBounds();
+        var lonLatBounds = this.getMapBoundsFromRectBounds(pxBounds);
+        this.map.setCenter(lonLatBounds.getCenterLonLat(), this.map.zoom);
+    },
+    
+    /**
+     * Method: getRectPxBounds
+     * Get extent rectangle pixel bounds
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} A bounds which is the extent rectangle's pixel
+     * bounds (relative to the parent element)
+     */
+    getRectPxBounds: function() {
+        var top = parseInt(this.extentRectangle.style.top);
+        var left = parseInt(this.extentRectangle.style.left);
+        var height = parseInt(this.extentRectangle.style.height);
+        var width = parseInt(this.extentRectangle.style.width);
+        return new OpenLayers.Bounds(left, top + height, left + width, top);
+    },
+
+    /**
+     * Method: setRectPxBounds
+     * Set extent rectangle pixel bounds.
+     *
+     * Parameters:
+     * pxBounds - {<OpenLayers.Bounds>}
+     */
+    setRectPxBounds: function(pxBounds) {
+        var top = Math.max(pxBounds.top, 0);
+        var left = Math.max(pxBounds.left, 0);
+        var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
+                              this.ovmap.size.h - this.hComp);
+        var right = Math.min(pxBounds.left + pxBounds.getWidth(),
+                             this.ovmap.size.w - this.wComp);
+        this.extentRectangle.style.top = parseInt(top) + 'px';
+        this.extentRectangle.style.left = parseInt(left) + 'px';
+        this.extentRectangle.style.height = parseInt(Math.max(bottom - top, 0))+ 'px';
+        this.extentRectangle.style.width = parseInt(Math.max(right - left, 0)) + 'px';
+    },
+
+    /**
+     * Method: getRectBoundsFromMapBounds
+     * Get the rect bounds from the map bounds.
+     *
+     * Parameters:
+     * lonLatBounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
+     * translated into pixel bounds for the overview map
+     */
+    getRectBoundsFromMapBounds: function(lonLatBounds) {
+        var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
+                                                     lonLatBounds.bottom);
+        var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
+                                                   lonLatBounds.top);
+        var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
+        var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
+        var bounds = null;
+        if (leftBottomPx && rightTopPx) {
+            bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
+                                           rightTopPx.x, rightTopPx.y);
+        }
+        return bounds;
+    },
+
+    /**
+     * Method: getMapBoundsFromRectBounds
+     * Get the map bounds from the rect bounds.
+     *
+     * Parameters:
+     * pxBounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
+     * translated into lon/lat bounds for the overview map
+     */
+    getMapBoundsFromRectBounds: function(pxBounds) {
+        var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
+                                                pxBounds.bottom);
+        var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
+                                              pxBounds.top);
+        var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
+        var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
+        return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
+                                     rightTopLonLat.lon, rightTopLonLat.lat);
+    },
+
+    /**
+     * Method: getLonLatFromOverviewPx
+     * Get a map location from a pixel location
+     *
+     * Parameters:
+     * overviewMapPx - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} Location which is the passed-in overview map
+     * OpenLayers.Pixel, translated into lon/lat by the overview map
+     */
+    getLonLatFromOverviewPx: function(overviewMapPx) {
+        var size = this.ovmap.size;
+        var res  = this.ovmap.getResolution();
+        var center = this.ovmap.getExtent().getCenterLonLat();
+    
+        var delta_x = overviewMapPx.x - (size.w / 2);
+        var delta_y = overviewMapPx.y - (size.h / 2);
+        
+        return new OpenLayers.LonLat(center.lon + delta_x * res ,
+                                     center.lat - delta_y * res); 
+    },
+
+    /**
+     * Method: getOverviewPxFromLonLat
+     * Get a pixel location from a map location
+     *
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat, 
+     * translated into overview map pixels
+     */
+    getOverviewPxFromLonLat: function(lonlat) {
+        var res  = this.ovmap.getResolution();
+        var extent = this.ovmap.getExtent();
+        var px = null;
+        if (extent) {
+            px = new OpenLayers.Pixel(
+                        Math.round(1/res * (lonlat.lon - extent.left)),
+                        Math.round(1/res * (extent.top - lonlat.lat)));
+        } 
+        return px;
+    },
+
+    CLASS_NAME: 'OpenLayers.Control.OverviewMap'
+});
+/* ======================================================================
+    OpenLayers/Handler.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Events.js
+ * 
+ * Class: OpenLayers.Handler
+ * Base class to construct a higher-level handler for event sequences.  All
+ *     handlers have activate and deactivate methods.  In addition, they have
+ *     methods named like browser events.  When a handler is activated, any
+ *     additional methods named like a browser event is registered as a
+ *     listener for the corresponding event.  When a handler is deactivated,
+ *     those same methods are unregistered as event listeners.
+ *
+ * Handlers also typically have a callbacks object with keys named like
+ *     the abstracted events or event sequences that they are in charge of
+ *     handling.  The controls that wrap handlers define the methods that
+ *     correspond to these abstract events - so instead of listening for
+ *     individual browser events, they only listen for the abstract events
+ *     defined by the handler.
+ *     
+ * Handlers are created by controls, which ultimately have the responsibility
+ *     of making changes to the the state of the application.  Handlers
+ *     themselves may make temporary changes, but in general are expected to
+ *     return the application in the same state that they found it.
+ */
+OpenLayers.Handler = OpenLayers.Class({
+
+    /**
+     * Property: id
+     * {String}
+     */
+    id: null,
+        
+    /**
+     * APIProperty: control
+     * {<OpenLayers.Control>}. The control that initialized this handler.  The
+     *     control is assumed to have a valid map property - that map is used
+     *     in the handler's own setMap method.
+     */
+    control: null,
+
+    /**
+     * Property: map
+     * {<OpenLayers.Map>}
+     */
+    map: null,
+
+    /**
+     * APIProperty: keyMask
+     * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
+     *     constants to construct a keyMask.  The keyMask is used by
+     *     <checkModifiers>.  If the keyMask matches the combination of keys
+     *     down on an event, checkModifiers returns true.
+     *
+     * Example:
+     * (code)
+     *     // handler only responds if the Shift key is down
+     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
+     *
+     *     // handler only responds if Ctrl-Shift is down
+     *     handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
+     *                       OpenLayers.Handler.MOD_CTRL;
+     * (end)
+     */
+    keyMask: null,
+
+    /**
+     * Property: active
+     * {Boolean}
+     */
+    active: false,
+    
+    /**
+     * Property: evt
+     * {Event} This property references the last event handled by the handler.
+     *     Note that this property is not part of the stable API.  Use of the
+     *     evt property should be restricted to controls in the library
+     *     or other applications that are willing to update with changes to
+     *     the OpenLayers code.
+     */
+    evt: null,
+
+    /**
+     * Constructor: OpenLayers.Handler
+     * Construct a handler.
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that initialized this
+     *     handler.  The control is assumed to have a valid map property; that
+     *     map is used in the handler's own setMap method.
+     * callbacks - {Object} An object whose properties correspond to abstracted
+     *     events or sequences of browser events.  The values for these
+     *     properties are functions defined by the control that get called by
+     *     the handler.
+     * options - {Object} An optional object whose properties will be set on
+     *     the handler.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Util.extend(this, options);
+        this.control = control;
+        this.callbacks = callbacks;
+        if (control.map) {
+            this.setMap(control.map); 
+        }
+
+        OpenLayers.Util.extend(this, options);
+        
+        this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+    },
+    
+    /**
+     * Method: setMap
+     */
+    setMap: function (map) {
+        this.map = map;
+    },
+
+    /**
+     * Method: checkModifiers
+     * Check the keyMask on the handler.  If no <keyMask> is set, this always
+     *     returns true.  If a <keyMask> is set and it matches the combination
+     *     of keys down on an event, this returns true.
+     *
+     * Returns:
+     * {Boolean} The keyMask matches the keys down on an event.
+     */
+    checkModifiers: function (evt) {
+        if(this.keyMask == null) {
+            return true;
+        }
+        /* calculate the keyboard modifier mask for this event */
+        var keyModifiers =
+            (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
+            (evt.ctrlKey  ? OpenLayers.Handler.MOD_CTRL  : 0) |
+            (evt.altKey   ? OpenLayers.Handler.MOD_ALT   : 0);
+    
+        /* if it differs from the handler object's key mask,
+           bail out of the event handler */
+        return (keyModifiers == this.keyMask);
+    },
+
+    /**
+     * APIMethod: activate
+     * Turn on the handler.  Returns false if the handler was already active.
+     * 
+     * Returns: 
+     * {Boolean} The handler was activated.
+     */
+    activate: function() {
+        if(this.active) {
+            return false;
+        }
+        // register for event handlers defined on this class.
+        var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+        for (var i = 0; i < events.length; i++) {
+            if (this[events[i]]) {
+                this.register(events[i], this[events[i]]); 
+            }
+        } 
+        this.active = true;
+        return true;
+    },
+    
+    /**
+     * APIMethod: deactivate
+     * Turn off the handler.  Returns false if the handler was already inactive.
+     * 
+     * Returns:
+     * {Boolean} The handler was deactivated.
+     */
+    deactivate: function() {
+        if(!this.active) {
+            return false;
+        }
+        // unregister event handlers defined on this class.
+        var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+        for (var i = 0; i < events.length; i++) {
+            if (this[events[i]]) {
+                this.unregister(events[i], this[events[i]]); 
+            }
+        } 
+        this.active = false;
+        return true;
+    },
+
+    /**
+    * Method: callback
+    * Trigger the control's named callback with the given arguments
+    *
+    * Parameters:
+    * name - {String} The key for the callback that is one of the properties
+    *     of the handler's callbacks object.
+    * args - {Array(*)} An array of arguments (any type) with which to call 
+    *     the callback (defined by the control).
+    */
+    callback: function (name, args) {
+        if (this.callbacks[name]) {
+            this.callbacks[name].apply(this.control, args);
+        }
+    },
+
+    /**
+    * Method: register
+    * register an event on the map
+    */
+    register: function (name, method) {
+        // TODO: deal with registerPriority in 3.0
+        this.map.events.registerPriority(name, this, method);
+        this.map.events.registerPriority(name, this, this.setEvent);
+    },
+
+    /**
+    * Method: unregister
+    * unregister an event from the map
+    */
+    unregister: function (name, method) {
+        this.map.events.unregister(name, this, method);   
+        this.map.events.unregister(name, this, this.setEvent);
+    },
+    
+    /**
+     * Method: setEvent
+     * With each registered browser event, the handler sets its own evt
+     *     property.  This property can be accessed by controls if needed
+     *     to get more information about the event that the handler is
+     *     processing.
+     *
+     * This allows modifier keys on the event to be checked (alt, shift,
+     *     and ctrl cannot be checked with the keyboard handler).  For a
+     *     control to determine which modifier keys are associated with the
+     *     event that a handler is currently processing, it should access
+     *     (code)handler.evt.altKey || handler.evt.shiftKey ||
+     *     handler.evt.ctrlKey(end).
+     *
+     * Parameters:
+     * evt - {Event} The browser event.
+     */
+    setEvent: function(evt) {
+        this.evt = evt;
+        return true;
+    },
+
+    /**
+     * Method: destroy
+     * Deconstruct the handler.
+     */
+    destroy: function () {
+        // unregister event listeners
+        this.deactivate();
+        // eliminate circular references
+        this.control = this.map = null;        
+    },
+
+    CLASS_NAME: "OpenLayers.Handler"
+});
+
+/**
+ * Constant: OpenLayers.Handler.MOD_NONE
+ * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
+ */
+OpenLayers.Handler.MOD_NONE  = 0;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_SHIFT
+ * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
+ */
+OpenLayers.Handler.MOD_SHIFT = 1;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_CTRL
+ * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
+ */
+OpenLayers.Handler.MOD_CTRL  = 2;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_ALT
+ * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
+ */
+OpenLayers.Handler.MOD_ALT   = 4;
+
+
+/* ======================================================================
+    OpenLayers/Map.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Events.js
+ * 
+ * Class: OpenLayers.Map
+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.
+ * Create a new map with the <OpenLayers.Map> constructor.
+ * 
+ * On their own maps do not provide much functionality.  To extend a map
+ * it's necessary to add controls (<OpenLayers.Control>) and 
+ * layers (<OpenLayers.Layer>) to the map. 
+ */
+OpenLayers.Map = OpenLayers.Class({
+    
+    /**
+     * Constant: Z_INDEX_BASE
+     * {Object} Base z-indexes for different classes of thing 
+     */
+    Z_INDEX_BASE: { BaseLayer: 100, Overlay: 325, Popup: 750, Control: 1000 },
+
+    /**
+     * Constant: EVENT_TYPES
+     * {Array(String)} supported application event types
+     */
+    EVENT_TYPES: [ 
+        "addlayer", "removelayer", "changelayer", "movestart", "move", 
+        "moveend", "zoomend", "popupopen", "popupclose",
+        "addmarker", "removemarker", "clearmarkers", "mouseover",
+        "mouseout", "mousemove", "dragstart", "drag", "dragend",
+        "changebaselayer"],
+
+    /**
+     * Property: id
+     * {String} Unique identifier for the map
+     */
+    id: null,
+    
+    /**
+     * APIProperty: events
+     * {<OpenLayers.Events>} An events object that handles all 
+     *                       events on the map
+     */
+    events: null,
+
+    /**
+     * APIProperty: div
+     * {DOMElement} The element that contains the map
+     */
+    div: null,
+
+    /**
+     * Property: size
+     * {<OpenLayers.Size>} Size of the main div (this.div)
+     */
+    size: null,
+    
+    /**
+     * Property: viewPortDiv
+     * {HTMLDivElement} The element that represents the map viewport
+     */
+    viewPortDiv: null,
+
+    /**
+     * Property: layerContainerOrigin
+     * {<OpenLayers.LonLat>} The lonlat at which the later container was
+     *                       re-initialized (on-zoom)
+     */
+    layerContainerOrigin: null,
+
+    /**
+     * Property: layerContainerDiv
+     * {HTMLDivElement} The element that contains the layers.
+     */
+    layerContainerDiv: null,
+
+    /**
+     * Property: layers
+     * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
+     */
+    layers: null,
+
+    /**
+     * Property: controls
+     * {Array(<OpenLayers.Control>)} List of controls associated with the map
+     */
+    controls: null,
+
+    /**
+     * Property: popups
+     * {Array(<OpenLayers.Popup>)} List of popups associated with the map
+     */
+    popups: null,
+
+    /**
+     * APIProperty: baseLayer
+     * {<OpenLayers.Layer>} The currently selected base layer.  This determines
+     * min/max zoom level, projection, etc.
+     */
+    baseLayer: null,
+    
+    /**
+     * Property: center
+     * {<OpenLayers.LonLat>} The current center of the map
+     */
+    center: null,
+
+    /**
+     * Property: zoom
+     * {Integer} The current zoom level of the map
+     */
+    zoom: 0,    
+
+    /**
+     * Property: viewRequestID
+     * {String} Used to store a unique identifier that changes when the map 
+     *          view changes. viewRequestID should be used when adding data 
+     *          asynchronously to the map: viewRequestID is incremented when 
+     *          you initiate your request (right now during changing of 
+     *          baselayers and changing of zooms). It is stored here in the 
+     *          map and also in the data that will be coming back 
+     *          asynchronously. Before displaying this data on request 
+     *          completion, we check that the viewRequestID of the data is 
+     *          still the same as that of the map. Fix for #480
+     */
+    viewRequestID: 0,
+
+  // Options
+
+    /**
+     * APIProperty: tileSize
+     * {<OpenLayers.Size>} Set in the map options to override the default tile
+     *                     size for this map.
+     */
+    tileSize: null,
+
+    /**
+     * APIProperty: projection
+     * {String} Set in the map options to override the default projection 
+     *          string this map - also set maxExtent, maxResolution, and 
+     *          units if appropriate.
+     */
+    projection: "EPSG:4326",    
+        
+    /**
+     * APIProperty: units
+     * {String} The map units.  Defaults to 'degrees'.  Possible values are
+     *          'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+     */
+    units: 'degrees',
+
+    /**
+     * APIProperty: resolutions
+     * {Array(Float)} A list of map resolutions (map units per pixel) in 
+     *     descending order.  If this is not set in the layer constructor, it 
+     *     will be set based on other resolution related properties 
+     *     (maxExtent, maxResolution, maxScale, etc.).
+     */
+    resolutions: null,
+
+    /**
+     * APIProperty: maxResolution
+     * {Float} Default max is 360 deg / 256 px, which corresponds to
+     *          zoom level 0 on gmaps.  Specify a different value in the map 
+     *          options if you are not using a geographic projection and 
+     *          displaying the whole world.
+     */
+    maxResolution: 1.40625,
+
+    /**
+     * APIProperty: minResolution
+     * {Float}
+     */
+    minResolution: null,
+
+    /**
+     * APIProperty: maxScale
+     * {Float}
+     */
+    maxScale: null,
+
+    /**
+     * APIProperty: minScale
+     * {Float}
+     */
+    minScale: null,
+
+    /**
+     * APIProperty: maxExtent
+     * {<OpenLayers.Bounds>} The maximum extent for the map.  Defaults to the
+     *                       whole world in decimal degrees 
+     *                       (-180, -90, 180, 90).  Specify a different
+     *                        extent in the map options if you are not using a 
+     *                        geographic projection and displaying the whole 
+     *                        world.
+     */
+    maxExtent: null,
+    
+    /**
+     * APIProperty: minExtent
+     * {<OpenLayers.Bounds>}
+     */
+    minExtent: null,
+    
+    /**
+     * APIProperty: restrictedExtent
+     * {<OpenLayers.Bounds>} Limit map navigation to this extent where possible.
+     *     If a non-null restrictedExtent is set, panning will be restricted
+     *     to the given bounds.  In addition, zooming to a resolution that
+     *     displays more than the restricted extent will center the map
+     *     on the restricted extent.  If you wish to limit the zoom level
+     *     or resolution, use maxResolution.
+     */
+    restrictedExtent: 'auto',
+
+    /**
+     * APIProperty: numZoomLevels
+     * {Integer} Number of zoom levels for the map.  Defaults to 16.  Set a
+     *           different value in the map options if needed.
+     */
+    numZoomLevels: 16,
+
+    /**
+     * APIProperty: theme
+     * {String} Relative path to a CSS file from which to load theme styles.
+     *          Specify null in the map options (e.g. {theme: null}) if you 
+     *          want to get cascading style declarations - by putting links to 
+     *          stylesheets or style declarations directly in your page.
+     */
+    theme: null,
+
+    /**
+     * APIProperty: fallThrough
+     * {Boolean} Should OpenLayers allow events on the map to fall through to
+     *           other elements on the page, or should it swallow them? (#457)
+     *           Default is to swallow them.
+     */
+    fallThrough: false,
+
+    /**
+     * Constructor: OpenLayers.Map
+     * Constructor for a new OpenLayers.Map instance.
+     *
+     * Parameters:
+     * div - {String} Id of an element in your page that will contain the map.
+     * options - {Object} Optional object with properties to tag onto the map.
+     *
+     * Examples:
+     * (code)
+     * // create a map with default options in an element with the id "map1"
+     * var map = new OpenLayers.Map("map1");
+     *
+     * // create a map with non-default options in an element with id "map2"
+     * var options = {
+     *     maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+     *     maxResolution: 156543,
+     *     units: 'meters',
+     *     projection: "EPSG:41001"
+     * };
+     * var map = new OpenLayers.Map("map2", options);
+     * (end)
+     */    
+    initialize: function (div, options) {
+        
+        //set the default options
+        this.setOptions(options);
+
+        this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
+
+        this.div = OpenLayers.Util.getElement(div);
+
+        // the viewPortDiv is the outermost div we modify
+        var id = this.div.id + "_OpenLayers_ViewPort";
+        this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
+                                                     "relative", null,
+                                                     "hidden");
+        this.viewPortDiv.style.width = "100%";
+        this.viewPortDiv.style.height = "100%";
+        this.viewPortDiv.className = "olMapViewport";
+        this.div.appendChild(this.viewPortDiv);
+
+        // the layerContainerDiv is the one that holds all the layers
+        id = this.div.id + "_OpenLayers_Container";
+        this.layerContainerDiv = OpenLayers.Util.createDiv(id);
+        this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
+        
+        this.viewPortDiv.appendChild(this.layerContainerDiv);
+
+        this.events = new OpenLayers.Events(this, 
+                                            this.div, 
+                                            this.EVENT_TYPES, 
+                                            this.fallThrough);
+        this.updateSize();
+ 
+        // update the map size and location before the map moves
+        this.events.register("movestart", this, this.updateSize);
+
+        // Because Mozilla does not support the "resize" event for elements 
+        // other than "window", we need to put a hack here. 
+        if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
+            // If IE, register the resize on the div
+            this.events.register("resize", this, this.updateSize);
+        } else {
+            // Else updateSize on catching the window's resize
+            //  Note that this is ok, as updateSize() does nothing if the 
+            //  map's size has not actually changed.
+            OpenLayers.Event.observe(window, 'resize',
+                            OpenLayers.Function.bind(this.updateSize, this));
+        }
+        
+        // only append link stylesheet if the theme property is set
+        if(this.theme) {
+            // check existing links for equivalent url
+            var addNode = true;
+            var nodes = document.getElementsByTagName('link');
+            for(var i=0; i<nodes.length; ++i) {
+                if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
+                                                   this.theme)) {
+                    addNode = false;
+                    break;
+                }
+            }
+            // only add a new node if one with an equivalent url hasn't already
+            // been added
+            if(addNode) {
+                var cssNode = document.createElement('link');
+                cssNode.setAttribute('rel', 'stylesheet');
+                cssNode.setAttribute('type', 'text/css');
+                cssNode.setAttribute('href', this.theme);
+                document.getElementsByTagName('head')[0].appendChild(cssNode);
+            }
+        }
+
+        this.layers = [];
+        
+        if (this.controls == null) {
+            if (OpenLayers.Control != null) { // running full or lite?
+                this.controls = [ new OpenLayers.Control.Navigation(),
+                                  new OpenLayers.Control.PanZoom(),
+                                  new OpenLayers.Control.ArgParser(),
+                                  new OpenLayers.Control.Attribution()
+                                ];
+            } else {
+                this.controls = [];
+            }
+        }
+
+        for(var i=0; i < this.controls.length; i++) {
+            this.addControlToMap(this.controls[i]);
+        }
+
+        this.popups = [];
+
+        this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
+        
+
+        // always call map.destroy()
+        OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
+
+    },
+
+    /**
+     * Method: unloadDestroy
+     * Function that is called to destroy the map on page unload. stored here
+     *     so that if map is manually destroyed, we can unregister this.
+     */
+    unloadDestroy: null,
+
+    /**
+     * APIMethod: destroy
+     * Destroy this map
+     */
+    destroy:function() {
+        // if unloadDestroy is null, we've already been destroyed
+        if (!this.unloadDestroy) {
+            return false;
+        }
+
+        // map has been destroyed. dont do it again!
+        OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
+        this.unloadDestroy = null;
+
+        if (this.layers != null) {
+            for (var i = this.layers.length - 1; i>=0; --i) {
+                //pass 'false' to destroy so that map wont try to set a new 
+                // baselayer after each baselayer is removed
+                this.layers[i].destroy(false);
+            } 
+            this.layers = null;
+        }
+        if (this.controls != null) {
+            for (var i = this.controls.length - 1; i>=0; --i) {
+                this.controls[i].destroy();
+            } 
+            this.controls = null;
+        }
+        if (this.viewPortDiv) {
+            this.div.removeChild(this.viewPortDiv);
+        }
+        this.viewPortDiv = null;
+
+        this.events.destroy();
+        this.events = null;
+
+    },
+
+    /**
+     * APIMethod: setOptions
+     * Change the map options
+     *
+     * Parameters:
+     * options - {Object} Hashtable of options to tag to the map
+     */
+    setOptions: function(options) {
+
+        // Simple-type defaults are set in class definition. 
+        //  Now set complex-type defaults 
+        this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
+                                            OpenLayers.Map.TILE_HEIGHT);
+        
+        this.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+
+        this.theme = OpenLayers._getScriptLocation() + 
+                             'theme/default/style.css'; 
+
+        // now add the options declared by the user
+        //  (these will override defaults)
+        OpenLayers.Util.extend(this, options);
+    },
+
+    /**
+     * APIMethod: getTileSize
+     * Get the tile size for the map
+     *
+     * Returns:
+     * {<OpenLayers.Size>}
+     */
+     getTileSize: function() {
+         return this.tileSize;
+     },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Layer Functions                     */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Layers to and from the Map           */
+  /*                                                      */
+  /********************************************************/         
+
+    /**
+     * APIMethod: getLayer
+     * Get a layer based on its id
+     *
+     * Parameter:
+     * id - {String} A layer id
+     *
+     * Returns:
+     * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's 
+     *                      layer collection, or null if not found.
+     */
+    getLayer: function(id) {
+        var foundLayer = null;
+        for (var i = 0; i < this.layers.length; i++) {
+            var layer = this.layers[i];
+            if (layer.id == id) {
+                foundLayer = layer;
+            }
+        }
+        return foundLayer;
+    },
+
+    /**
+    * Method: setLayerZIndex
+    * 
+    * Parameters:
+    * layer - {<OpenLayers.Layer>} 
+    * zIdx - {int} 
+    */    
+    setLayerZIndex: function (layer, zIdx) {
+        layer.setZIndex(
+            this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
+            + zIdx * 5 );
+    },
+
+    /**
+    * APIMethod: addLayer
+    *
+    * Parameters:
+    * layer - {<OpenLayers.Layer>} 
+    */    
+    addLayer: function (layer) {
+        for(var i=0; i < this.layers.length; i++) {
+            if (this.layers[i] == layer) {
+                OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded", layer.name));
+                return false;
+            }
+        }    
+        
+        layer.div.style.overflow = "";
+        this.setLayerZIndex(layer, this.layers.length);
+
+        if (layer.isFixed) {
+            this.viewPortDiv.appendChild(layer.div);
+        } else {
+            this.layerContainerDiv.appendChild(layer.div);
+        }
+        this.layers.push(layer);
+        layer.setMap(this);
+
+        if (layer.isBaseLayer)  {
+            if (this.baseLayer == null) {
+                // set the first baselaye we add as the baselayer
+                this.setBaseLayer(layer);
+            } else {
+                layer.setVisibility(false);
+            }
+        } else {
+            layer.redraw();
+        }
+
+        this.events.triggerEvent("addlayer");
+    },
+
+    /**
+    * APIMethod: addLayers 
+    *
+    * Parameters:
+    * layers - Array({<OpenLayers.Layer>}) 
+    */    
+    addLayers: function (layers) {
+        for (var i = 0; i <  layers.length; i++) {
+            this.addLayer(layers[i]);
+        }
+    },
+
+    /** 
+     * APIMethod: removeLayer
+     * Removes a layer from the map by removing its visual element (the 
+     *   layer.div property), then removing it from the map's internal list 
+     *   of layers, setting the layer's map property to null. 
+     * 
+     *   a "removelayer" event is triggered.
+     * 
+     *   very worthy of mention is that simply removing a layer from a map
+     *   will not cause the removal of any popups which may have been created
+     *   by the layer. this is due to the fact that it was decided at some
+     *   point that popups would not belong to layers. thus there is no way 
+     *   for us to know here to which layer the popup belongs.
+     *    
+     *     A simple solution to this is simply to call destroy() on the layer.
+     *     the default OpenLayers.Layer class's destroy() function
+     *     automatically takes care to remove itself from whatever map it has
+     *     been attached to. 
+     * 
+     *     The correct solution is for the layer itself to register an 
+     *     event-handler on "removelayer" and when it is called, if it 
+     *     recognizes itself as the layer being removed, then it cycles through
+     *     its own personal list of popups, removing them from the map.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * setNewBaseLayer - {Boolean} Default is true
+     */
+    removeLayer: function(layer, setNewBaseLayer) {
+        if (setNewBaseLayer == null) {
+            setNewBaseLayer = true;
+        }
+
+        if (layer.isFixed) {
+            this.viewPortDiv.removeChild(layer.div);
+        } else {
+            this.layerContainerDiv.removeChild(layer.div);
+        }
+        OpenLayers.Util.removeItem(this.layers, layer);
+        layer.removeMap(this);
+        layer.map = null;
+
+        // if we removed the base layer, need to set a new one
+        if (setNewBaseLayer && (this.baseLayer == layer)) {
+            this.baseLayer = null;
+            for(i=0; i < this.layers.length; i++) {
+                var iLayer = this.layers[i];
+                if (iLayer.isBaseLayer) {
+                    this.setBaseLayer(iLayer);
+                    break;
+                }
+            }
+        }
+        this.events.triggerEvent("removelayer");
+    },
+
+    /**
+     * APIMethod: getNumLayers
+     * 
+     * Returns:
+     * {Int} The number of layers attached to the map.
+     */
+    getNumLayers: function () {
+        return this.layers.length;
+    },
+
+    /** 
+     * APIMethod: getLayerIndex
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>}
+     *
+     * Returns:
+     * {Integer} The current (zero-based) index of the given layer in the map's
+     *           layer stack. Returns -1 if the layer isn't on the map.
+     */
+    getLayerIndex: function (layer) {
+        return OpenLayers.Util.indexOf(this.layers, layer);
+    },
+    
+    /** 
+     * APIMethod: setLayerIndex
+     * Move the given layer to the specified (zero-based) index in the layer
+     *     list, changing its z-index in the map display. Use
+     *     map.getLayerIndex() to find out the current index of a layer. Note
+     *     that this cannot (or at least should not) be effectively used to
+     *     raise base layers above overlays.
+     *
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} 
+     * idx - {int} 
+     */
+    setLayerIndex: function (layer, idx) {
+        var base = this.getLayerIndex(layer);
+        if (idx < 0) {
+            idx = 0;
+        } else if (idx > this.layers.length) {
+            idx = this.layers.length;
+        }
+        if (base != idx) {
+            this.layers.splice(base, 1);
+            this.layers.splice(idx, 0, layer);
+            for (var i = 0; i < this.layers.length; i++) {
+                this.setLayerZIndex(this.layers[i], i);
+            }
+            this.events.triggerEvent("changelayer");
+        }
+    },
+
+    /** 
+     * APIMethod: raiseLayer
+     * Change the index of the given layer by delta. If delta is positive, 
+     *     the layer is moved up the map's layer stack; if delta is negative,
+     *     the layer is moved down.  Again, note that this cannot (or at least
+     *     should not) be effectively used to raise base layers above overlays.
+     *
+     * Paremeters:
+     * layer - {<OpenLayers.Layer>} 
+     * idx - {int} 
+     */
+    raiseLayer: function (layer, delta) {
+        var idx = this.getLayerIndex(layer) + delta;
+        this.setLayerIndex(layer, idx);
+    },
+    
+    /** 
+     * APIMethod: setBaseLayer
+     * Allows user to specify one of the currently-loaded layers as the Map's
+     *     new base layer.
+     * 
+     * Parameters:
+     * newBaseLayer - {<OpenLayers.Layer>}
+     */
+    setBaseLayer: function(newBaseLayer) {
+        var oldExtent = null;
+        if(this.baseLayer) {
+            oldExtent = this.baseLayer.getExtent();
+        }
+
+        if (newBaseLayer != this.baseLayer) {
+          
+            // is newBaseLayer an already loaded layer?m
+            if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
+
+                // make the old base layer invisible 
+                if (this.baseLayer != null) {
+                    this.baseLayer.setVisibility(false);
+                }
+
+                // set new baselayer and make it visible
+                this.baseLayer = newBaseLayer;
+                
+                //copy over projection and extent information
+                this.maxExtent = newBaseLayer.maxExtent;
+                this.minExtent = newBaseLayer.minExtent;
+                this.maxScale = newBaseLayer.maxScale;
+                this.minScale = newBaseLayer.minScale;
+                this.maxResolution = newBaseLayer.maxResolution;
+                this.minResolution = newBaseLayer.minResolution;
+                this.units = newBaseLayer.units;
+                this.projection = newBaseLayer.projection;
+                
+                // Increment viewRequestID since the baseLayer is 
+                // changing. This is used by tiles to check if they should 
+                // draw themselves.
+                this.viewRequestID++;
+                this.baseLayer.visibility = true;
+
+                //redraw all layers
+                var center = this.getCenter();
+                if (center != null) {
+                    if (oldExtent == null) {
+                        // simply set center but force zoom change
+                        this.setCenter(center, this.getZoom(), false, true);
+                    } else {
+                        // zoom to oldExtent *and* force zoom change
+                        this.setCenter(oldExtent.getCenterLonLat(), 
+                                       this.getZoomForExtent(oldExtent),
+                                       false, true);
+                    }
+                }
+
+                this.events.triggerEvent("changebaselayer");
+            }        
+        }
+    },
+
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Control Functions                    */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Controls to and from the Map         */
+  /*                                                      */
+  /********************************************************/         
+
+    /**
+     * APIMethod: addControl
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>}
+     * px - {<OpenLayers.Pixel>}
+     */    
+    addControl: function (control, px) {
+        this.controls.push(control);
+        this.addControlToMap(control, px);
+    },
+
+    /**
+     * Method: addControlToMap
+     * 
+     * Parameters:
+     * 
+     * control - {<OpenLayers.Control>}
+     * px - {<OpenLayers.Pixel>}
+     */    
+    addControlToMap: function (control, px) {
+        // If a control doesn't have a div at this point, it belongs in the
+        // viewport.
+        control.outsideViewport = (control.div != null);
+        control.setMap(this);
+        var div = control.draw(px);
+        if (div) {
+            if(!control.outsideViewport) {
+                div.style.zIndex = this.Z_INDEX_BASE['Control'] +
+                                    this.controls.length;
+                this.viewPortDiv.appendChild( div );
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: getControl
+     * 
+     * Parameters:
+     * id - {String} ID of the control to return.
+     * 
+     * Returns:
+     * {<OpenLayers.Control>} The control from the map's list of controls 
+     *                        which has a matching 'id'. If none found, 
+     *                        returns null.
+     */    
+    getControl: function (id) {
+        var returnControl = null;
+        for(var i=0; i < this.controls.length; i++) {
+            var control = this.controls[i];
+            if (control.id == id) {
+                returnControl = control;
+                break;
+            }
+        }
+        return returnControl;
+    },
+    
+    /** 
+     * APIMethod: removeControl
+     * Remove a control from the map. Removes the control both from the map 
+     *     object's internal array of controls, as well as from the map's 
+     *     viewPort (assuming the control was not added outsideViewport)
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control to remove.
+     */    
+    removeControl: function (control) {
+        //make sure control is non-null and actually part of our map
+        if ( (control) && (control == this.getControl(control.id)) ) {
+            if (!control.outsideViewport) {
+                this.viewPortDiv.removeChild(control.div)
+            }
+            OpenLayers.Util.removeItem(this.controls, control);
+        }
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Popup Functions                     */
+  /*                                                      */
+  /*     The following functions deal with adding and     */
+  /*        removing Popups to and from the Map           */
+  /*                                                      */
+  /********************************************************/         
+
+    /** 
+     * APIMethod: addPopup
+     * 
+     * Parameters:
+     * popup - {<OpenLayers.Popup>}
+     * exclusive - {Boolean} If true, closes all other popups first
+     */
+    addPopup: function(popup, exclusive) {
+
+        if (exclusive) {
+            //remove all other popups from screen
+            for(var i=0; i < this.popups.length; i++) {
+                this.removePopup(this.popups[i]);
+            }
+        }
+
+        popup.map = this;
+        this.popups.push(popup);
+        var popupDiv = popup.draw();
+        if (popupDiv) {
+            popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +
+                                    this.popups.length;
+            this.layerContainerDiv.appendChild(popupDiv);
+        }
+    },
+    
+    /** 
+    * APIMethod: removePopup
+    * 
+    * Parameters:
+    * popup - {<OpenLayers.Popup>}
+    */
+    removePopup: function(popup) {
+        OpenLayers.Util.removeItem(this.popups, popup);
+        if (popup.div) {
+            try { this.layerContainerDiv.removeChild(popup.div); }
+            catch (e) { } // Popups sometimes apparently get disconnected
+                      // from the layerContainerDiv, and cause complaints.
+        }
+        popup.map = null;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*              Container Div Functions                 */
+  /*                                                      */
+  /*   The following functions deal with the access to    */
+  /*    and maintenance of the size of the container div  */
+  /*                                                      */
+  /********************************************************/     
+
+    /**
+     * APIMethod: getSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the 
+     *                     size, in pixels, of the div into which OpenLayers 
+     *                     has been loaded. 
+     *                     Note - A clone() of this locally cached variable is
+     *                     returned, so as not to allow users to modify it.
+     */
+    getSize: function () {
+        var size = null;
+        if (this.size != null) {
+            size = this.size.clone();
+        }
+        return size;
+    },
+
+    /**
+     * APIMethod: updateSize
+     * This function should be called by any external code which dynamically
+     *     changes the size of the map div (because mozilla wont let us catch 
+     *     the "onresize" for an element)
+     */
+    updateSize: function() {
+        // the div might have moved on the page, also
+        this.events.element.offsets = null;
+        var newSize = this.getCurrentSize();
+        var oldSize = this.getSize();
+        if (oldSize == null)
+            this.size = oldSize = newSize;
+        if (!newSize.equals(oldSize)) {
+            
+            // store the new size
+            this.size = newSize;
+
+            //notify layers of mapresize
+            for(var i=0; i < this.layers.length; i++) {
+                this.layers[i].onMapResize();                
+            }
+
+            if (this.baseLayer != null) {
+                var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
+                var centerLL = this.getLonLatFromViewPortPx(center);
+                var zoom = this.getZoom();
+                this.zoom = null;
+                this.setCenter(this.getCenter(), zoom);
+            }
+
+        }
+    },
+    
+    /**
+     * Method: getCurrentSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions 
+     *                     of the map div
+     */
+    getCurrentSize: function() {
+
+        var size = new OpenLayers.Size(this.div.clientWidth, 
+                                       this.div.clientHeight);
+
+        // Workaround for the fact that hidden elements return 0 for size.
+        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+            var dim = OpenLayers.Element.getDimensions(this.div);
+            size.w = dim.width;
+            size.h = dim.height;
+        }
+        if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+            size.w = parseInt(this.div.style.width);
+            size.h = parseInt(this.div.style.height);
+        }
+        return size;
+    },
+
+    /** 
+     * Method: calculateBounds
+     * 
+     * Parameters:
+     * center - {<OpenLayers.LonLat>} Default is this.getCenter()
+     * resolution - {float} Default is this.getResolution() 
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A bounds based on resolution, center, and 
+     *                       current mapsize.
+     */
+    calculateBounds: function(center, resolution) {
+
+        var extent = null;
+        
+        if (center == null) {
+            center = this.getCenter();
+        }                
+        if (resolution == null) {
+            resolution = this.getResolution();
+        }
+    
+        if ((center != null) && (resolution != null)) {
+
+            var size = this.getSize();
+            var w_deg = size.w * resolution;
+            var h_deg = size.h * resolution;
+        
+            extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+                                           center.lat - h_deg / 2,
+                                           center.lon + w_deg / 2,
+                                           center.lat + h_deg / 2);
+        
+        }
+
+        return extent;
+    },
+
+
+  /********************************************************/
+  /*                                                      */
+  /*            Zoom, Center, Pan Functions               */
+  /*                                                      */
+  /*    The following functions handle the validation,    */
+  /*   getting and setting of the Zoom Level and Center   */
+  /*       as well as the panning of the Map              */
+  /*                                                      */
+  /********************************************************/
+    /**
+     * APIMethod: getCenter
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>}
+     */
+    getCenter: function () {
+        return this.center;
+    },
+
+
+    /**
+     * APIMethod: getZoom
+     * 
+     * Returns:
+     * {Integer}
+     */
+    getZoom: function () {
+        return this.zoom;
+    },
+    
+    /** 
+     * APIMethod: pan
+     * Allows user to pan by a value of screen pixels
+     * 
+     * Parameters:
+     * dx - {Integer}
+     * dy - {Integer}
+     */
+    pan: function(dx, dy) {
+
+        // getCenter
+        var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
+
+        // adjust
+        var newCenterPx = centerPx.add(dx, dy);
+        
+        // only call setCenter if there has been a change
+        if (!newCenterPx.equals(centerPx)) {
+            var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
+            this.setCenter(newCenterLonLat);
+        }
+
+   },
+
+    /**
+     * APIMethod: setCenter
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * zoom - {Integer}
+     * dragging - {Boolean} Specifies whether or not to trigger 
+     *                      movestart/end events
+     * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom 
+     *                             change events (needed on baseLayer change)
+     *
+     * TBD: reconsider forceZoomChange in 3.0
+     */
+    setCenter: function (lonlat, zoom, dragging, forceZoomChange) {
+
+        if (!this.center && !this.isValidLonLat(lonlat)) {
+            lonlat = this.maxExtent.getCenterLonLat();
+        }
+
+        if (this.restrictedExtent && this.restrictedExtent != 'auto') {
+            // In 3.0, decide if we want to change interpretation of maxExtent.
+            if(lonlat == null) { 
+                lonlat = this.getCenter(); 
+            }
+            if(zoom == null) { 
+                zoom = this.getZoom(); 
+            }
+            var resolution = null;
+            if(this.baseLayer != null) {
+                resolution = this.baseLayer.resolutions[zoom];
+            }
+            var extent = this.calculateBounds(lonlat, resolution); 
+            if(!this.restrictedExtent.containsBounds(extent)) {
+                var maxCenter = this.restrictedExtent.getCenterLonLat(); 
+                if(extent.getWidth() > this.restrictedExtent.getWidth()) { 
+                    lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); 
+                } else if(extent.left < this.restrictedExtent.left) {
+                    lonlat = lonlat.add(this.restrictedExtent.left -
+                                        extent.left, 0); 
+                } else if(extent.right > this.restrictedExtent.right) { 
+                    lonlat = lonlat.add(this.restrictedExtent.right -
+                                        extent.right, 0); 
+                } 
+                if(extent.getHeight() > this.restrictedExtent.getHeight()) { 
+                    lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); 
+                } else if(extent.bottom < this.restrictedExtent.bottom) { 
+                    lonlat = lonlat.add(0, this.restrictedExtent.bottom -
+                                        extent.bottom); 
+                } 
+                else if(extent.top > this.restrictedExtent.top) { 
+                    lonlat = lonlat.add(0, this.restrictedExtent.top -
+                                        extent.top); 
+                } 
+            }
+        }
+        
+        var zoomChanged = forceZoomChange || (
+                            (this.isValidZoomLevel(zoom)) && 
+                            (zoom != this.getZoom()) );
+
+        var centerChanged = !lonlat.equals(this.center);
+        if (this.restrictedExtent == 'auto') {
+          centerChanged = this.isValidLonLat(lonlat) && centerChanged;
+        }
+
+        // if neither center nor zoom will change, no need to do anything
+        if (zoomChanged || centerChanged || !dragging) {
+
+            if (!dragging) { this.events.triggerEvent("movestart"); }
+
+            if (centerChanged) {
+                if ((!zoomChanged) && (this.center)) { 
+                    // if zoom hasnt changed, just slide layerContainer
+                    //  (must be done before setting this.center to new value)
+                    this.centerLayerContainer(lonlat);
+                }
+                this.center = lonlat.clone();
+            }
+
+            // (re)set the layerContainerDiv's location
+            if ((zoomChanged) || (this.layerContainerOrigin == null)) {
+                this.layerContainerOrigin = this.center.clone();
+                this.layerContainerDiv.style.left = "0px";
+                this.layerContainerDiv.style.top  = "0px";
+            }
+
+            if (zoomChanged) {
+                this.zoom = zoom;
+                // zoom level has changed, increment viewRequestID.
+                this.viewRequestID++;
+            }    
+            
+            var bounds = this.getExtent();
+            
+            //send the move call to the baselayer and all the overlays    
+            this.baseLayer.moveTo(bounds, zoomChanged, dragging);
+            
+            bounds = this.baseLayer.getExtent();
+            
+            for (var i = 0; i < this.layers.length; i++) {
+                var layer = this.layers[i];
+                if (!layer.isBaseLayer) {
+                    
+                    var moveLayer;
+                    var inRange = layer.calculateInRange();
+                    if (layer.inRange != inRange) {
+                        // Layer property has changed. We are going 
+                        // to call moveLayer so that the layer can be turned
+                        // off or on.   
+                        layer.inRange = inRange;
+                        moveLayer = true;
+                        this.events.triggerEvent("changelayer");
+                    } else {
+                        // If nothing has changed, then we only move the layer
+                        // if it is visible and inrange.
+                        moveLayer = (layer.visibility && layer.inRange);
+                    }
+
+                    if (moveLayer) {
+                        layer.moveTo(bounds, zoomChanged, dragging);
+                    }
+                }                
+            }
+            
+            if (zoomChanged) {
+                //redraw popups
+                for (var i = 0; i < this.popups.length; i++) {
+                    this.popups[i].updatePosition();
+                }
+            }    
+            
+            this.events.triggerEvent("move");
+    
+            if (zoomChanged) { this.events.triggerEvent("zoomend"); }
+        }
+
+        // even if nothing was done, we want to notify of this
+        if (!dragging) { this.events.triggerEvent("moveend"); }
+    },
+
+    /** 
+     * Method: centerLayerContainer
+     * This function takes care to recenter the layerContainerDiv.
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     */
+    centerLayerContainer: function (lonlat) {
+
+        var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
+        var newPx = this.getViewPortPxFromLonLat(lonlat);
+
+        if ((originPx != null) && (newPx != null)) {
+            this.layerContainerDiv.style.left = (originPx.x - newPx.x) + "px";
+            this.layerContainerDiv.style.top  = (originPx.y - newPx.y) + "px";
+        }
+    },
+
+    /**
+     * Method: isValidZoomLevel
+     * 
+     * Parameters:
+     * zoomLevel - {Integer}
+     * 
+     * Returns:
+     * {Boolean} Whether or not the zoom level passed in is non-null and 
+     *           within the min/max range of zoom levels.
+     */
+    isValidZoomLevel: function(zoomLevel) {
+       return ( (zoomLevel != null) &&
+                (zoomLevel >= 0) && 
+                (zoomLevel < this.getNumZoomLevels()) );
+    },
+    
+    /**
+     * Method: isValidLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {Boolean} Whether or not the lonlat passed in is non-null and within
+     *           the maxExtent bounds
+     */
+    isValidLonLat: function(lonlat) {
+        var valid = false;
+        if (lonlat != null) {
+            var maxExtent = this.getMaxExtent();
+            valid = maxExtent.containsLonLat(lonlat);        
+        }
+        return valid;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Layer Options                        */
+  /*                                                      */
+  /*    Accessor functions to Layer Options parameters    */
+  /*                                                      */
+  /********************************************************/
+    
+    /**
+     * APIMethod: getProjection
+     * 
+     * Returns:
+     * {String} The Projection of the base layer.
+     */
+    getProjection: function() {
+        var projection = null;
+        if (this.baseLayer != null) {
+            projection = this.baseLayer.projection;
+        }
+        return projection;
+    },
+    
+    /**
+     * APIMethod: getMaxResolution
+     * 
+     * Returns:
+     * {String} The Map's Maximum Resolution
+     */
+    getMaxResolution: function() {
+        var maxResolution = null;
+        if (this.baseLayer != null) {
+            maxResolution = this.baseLayer.maxResolution;
+        }
+        return maxResolution;
+    },
+        
+    /**
+     * APIMethod: getMaxExtent
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getMaxExtent: function () {
+        var maxExtent = null;
+        if (this.baseLayer != null) {
+            maxExtent = this.baseLayer.maxExtent;
+        }        
+        return maxExtent;
+    },
+    
+    /**
+     * APIMethod: getNumZoomLevels
+     * 
+     * Returns:
+     * {Integer} The total number of zoom levels that can be displayed by the 
+     *           current baseLayer.
+     */
+    getNumZoomLevels: function() {
+        var numZoomLevels = null;
+        if (this.baseLayer != null) {
+            numZoomLevels = this.baseLayer.numZoomLevels;
+        }
+        return numZoomLevels;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Baselayer Functions                  */
+  /*                                                      */
+  /*    The following functions, all publicly exposed     */
+  /*       in the API?, are all merely wrappers to the    */
+  /*       the same calls on whatever layer is set as     */
+  /*                the current base layer                */
+  /*                                                      */
+  /********************************************************/
+
+    /**
+     * APIMethod: getExtent
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *                       bounds of the current viewPort. 
+     *                       If no baselayer is set, returns null.
+     */
+    getExtent: function () {
+        var extent = null;
+        if (this.baseLayer != null) {
+            extent = this.baseLayer.getExtent();
+        }
+        return extent;
+    },
+    
+    /**
+     * APIMethod: getResolution
+     * 
+     * Returns:
+     * {Float} The current resolution of the map. 
+     *         If no baselayer is set, returns null.
+     */
+    getResolution: function () {
+        var resolution = null;
+        if (this.baseLayer != null) {
+            resolution = this.baseLayer.getResolution();
+        }
+        return resolution;
+    },
+
+     /**
+      * APIMethod: getScale
+      * 
+      * Returns:
+      * {Float} The current scale denominator of the map. 
+      *         If no baselayer is set, returns null.
+      */
+    getScale: function () {
+        var scale = null;
+        if (this.baseLayer != null) {
+            var res = this.getResolution();
+            var units = this.baseLayer.units;
+            scale = OpenLayers.Util.getScaleFromResolution(res, units);
+        }
+        return scale;
+    },
+
+
+    /**
+     * APIMethod: getZoomForExtent
+     * 
+     * Parameters: 
+     * bounds - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {Integer} A suitable zoom level for the specified bounds.
+     *           If no baselayer is set, returns null.
+     */
+    getZoomForExtent: function (bounds) {
+        var zoom = null;
+        if (this.baseLayer != null) {
+            zoom = this.baseLayer.getZoomForExtent(bounds);
+        }
+        return zoom;
+    },
+
+    /**
+     * APIMethod: getZoomForResolution
+     * 
+     * Parameter:
+     * resolution - {Float}
+     * 
+     * Returns:
+     * {Integer} A suitable zoom level for the specified resolution.
+     *           If no baselayer is set, returns null.
+     */
+    getZoomForResolution: function(resolution) {
+        var zoom = null;
+        if (this.baseLayer != null) {
+            zoom = this.baseLayer.getZoomForResolution(resolution);
+        }
+        return zoom;
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                  Zooming Functions                   */
+  /*                                                      */
+  /*    The following functions, all publicly exposed     */
+  /*       in the API, are all merely wrappers to the     */
+  /*               the setCenter() function               */
+  /*                                                      */
+  /********************************************************/
+  
+    /** 
+     * APIMethod: zoomTo
+     * Zoom to a specific zoom level
+     * 
+     * Parameters:
+     * zoom - {Integer}
+     */
+    zoomTo: function(zoom) {
+        if (this.isValidZoomLevel(zoom)) {
+            this.setCenter(null, zoom);
+        }
+    },
+    
+    /**
+     * APIMethod: zoomIn
+     * 
+     * Parameters:
+     * zoom - {int}
+     */
+    zoomIn: function() {
+        this.zoomTo(this.getZoom() + 1);
+    },
+    
+    /**
+     * APIMethod: zoomOut
+     * 
+     * Parameters:
+     * zoom - {int}
+     */
+    zoomOut: function() {
+        this.zoomTo(this.getZoom() - 1);
+    },
+
+    /**
+     * APIMethod: zoomToExtent
+     * Zoom to the passed in bounds, recenter
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    zoomToExtent: function(bounds) {
+        var center = bounds.getCenterLonLat();
+        if (this.baseLayer.wrapDateLine) {
+            var maxExtent = this.getMaxExtent();
+
+            //fix straddling bounds (in the case of a bbox that straddles the 
+            // dateline, it's left and right boundaries will appear backwards. 
+            // we fix this by allowing a right value that is greater than the
+            // max value at the dateline -- this allows us to pass a valid 
+            // bounds to calculate zoom)
+            //
+            bounds = bounds.clone();
+            while (bounds.right < bounds.left) {
+                bounds.right += maxExtent.getWidth();
+            }
+            //if the bounds was straddling (see above), then the center point 
+            // we got from it was wrong. So we take our new bounds and ask it
+            // for the center. Because our new bounds is at least partially 
+            // outside the bounds of maxExtent, the new calculated center 
+            // might also be. We don't want to pass a bad center value to 
+            // setCenter, so we have it wrap itself across the date line.
+            //
+            center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
+        }
+        this.setCenter(center, this.getZoomForExtent(bounds));
+    },
+
+    /** 
+     * APIMethod: zoomToMaxExtent
+     * Zoom to the full extent and recenter.
+     */
+    zoomToMaxExtent: function() {
+        this.zoomToExtent(this.getMaxExtent());
+    },
+
+    /** 
+     * APIMethod: zoomToScale
+     * Zoom to a specified scale 
+     * 
+     * Parameters:
+     * scale - {float}
+     */
+    zoomToScale: function(scale) {
+        var res = OpenLayers.Util.getResolutionFromScale(scale, 
+                                                         this.baseLayer.units);
+        var size = this.getSize();
+        var w_deg = size.w * res;
+        var h_deg = size.h * res;
+        var center = this.getCenter();
+
+        var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+                                           center.lat - h_deg / 2,
+                                           center.lon + w_deg / 2,
+                                           center.lat + h_deg / 2);
+        this.zoomToExtent(extent);
+    },
+    
+  /********************************************************/
+  /*                                                      */
+  /*             Translation Functions                    */
+  /*                                                      */
+  /*      The following functions translate between       */
+  /*           LonLat, LayerPx, and ViewPortPx            */
+  /*                                                      */
+  /********************************************************/
+      
+  //
+  // TRANSLATION: LonLat <-> ViewPortPx
+  //
+
+    /**
+     * APIMethod: getLonLatFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view 
+     *                       port <OpenLayers.Pixel>, translated into lon/lat
+     *                       by the current base layer.
+     */
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        var lonlat = null; 
+        if (this.baseLayer != null) {
+            lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
+        }
+        return lonlat;
+    },
+
+    /**
+     * APIMethod: getViewPortPxFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into view port 
+     *                      pixels by the current base layer.
+     */
+    getViewPortPxFromLonLat: function (lonlat) {
+        var px = null; 
+        if (this.baseLayer != null) {
+            px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
+        }
+        return px;
+    },
+
+    
+  //
+  // CONVENIENCE TRANSLATION FUNCTIONS FOR API
+  //
+
+    /**
+     * APIMethod: getLonLatFromPixel
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
+     *                       OpenLayers.Pixel, translated into lon/lat by the 
+     *                       current base layer
+     */
+    getLonLatFromPixel: function (px) {
+        return this.getLonLatFromViewPortPx(px);
+    },
+
+    /**
+     * APIMethod: getPixelFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     * 
+     * Returns: 
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the 
+     *                      <OpenLayers.LonLat> translated into view port 
+     *                      pixels by the current base layer.
+     */
+    getPixelFromLonLat: function (lonlat) {
+        return this.getViewPortPxFromLonLat(lonlat);
+    },
+
+
+
+  //
+  // TRANSLATION: ViewPortPx <-> LayerPx
+  //
+
+    /**
+     * APIMethod: getViewPortPxFromLayerPx
+     * 
+     * Parameters:
+     * layerPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel 
+     *                      coordinates
+     */
+    getViewPortPxFromLayerPx:function(layerPx) {
+        var viewPortPx = null;
+        if (layerPx != null) {
+            var dX = parseInt(this.layerContainerDiv.style.left);
+            var dY = parseInt(this.layerContainerDiv.style.top);
+            viewPortPx = layerPx.add(dX, dY);            
+        }
+        return viewPortPx;
+    },
+    
+    /**
+     * APIMethod: getLayerPxFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     * 
+     * Returns:
+     * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel 
+     *                      coordinates
+     */
+    getLayerPxFromViewPortPx:function(viewPortPx) {
+        var layerPx = null;
+        if (viewPortPx != null) {
+            var dX = -parseInt(this.layerContainerDiv.style.left);
+            var dY = -parseInt(this.layerContainerDiv.style.top);
+            layerPx = viewPortPx.add(dX, dY);
+            if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
+                layerPx = null;
+            }
+        }
+        return layerPx;
+    },
+    
+  //
+  // TRANSLATION: LonLat <-> LayerPx
+  //
+
+    /**
+     * APIMethod: getLonLatFromLayerPx
+     * 
+     * Parameters:
+     * px - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>}
+     */
+    getLonLatFromLayerPx: function (px) {
+       //adjust for displacement of layerContainerDiv
+       px = this.getViewPortPxFromLayerPx(px);
+       return this.getLonLatFromViewPortPx(px);         
+    },
+    
+    /**
+     * APIMethod: getLayerPxFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>} lonlat
+     *
+     * Returns:
+     * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in 
+     *                      <OpenLayers.LonLat>, translated into layer pixels 
+     *                      by the current base layer
+     */
+    getLayerPxFromLonLat: function (lonlat) {
+       //adjust for displacement of layerContainerDiv
+       var px = this.getViewPortPxFromLonLat(lonlat);
+       return this.getLayerPxFromViewPortPx(px);         
+    },
+
+    CLASS_NAME: "OpenLayers.Map"
+});
+
+/**
+ * Constant: TILE_WIDTH
+ * {Integer} 256 Default tile width (unless otherwise specified)
+ */
+OpenLayers.Map.TILE_WIDTH = 256;
+/**
+ * Constant: TILE_HEIGHT
+ * {Integer} 256 Default tile height (unless otherwise specified)
+ */
+OpenLayers.Map.TILE_HEIGHT = 256;
+/* ======================================================================
+    OpenLayers/Marker.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ * 
+ * Class: OpenLayers.Marker
+ * Instances of OpenLayers.Marker are a combination of a 
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.  
+ *
+ * Markers are generally added to a special layer called
+ * <OpenLayers.Layer.Markers>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(10,17);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+    
+    /** 
+     * Property: icon 
+     * {<OpenLayers.Icon>} The icon used by this marker.
+     */
+    icon: null,
+
+    /** 
+     * Property: lonlat 
+     * {<OpenLayers.LonLat>} location of object
+     */
+    lonlat: null,
+    
+    /** 
+     * Property: events 
+     * {<OpenLayers.Events>} the event handler.
+     */
+    events: null,
+    
+    /** 
+     * Property: map 
+     * {<OpenLayers.Map>} the map this marker is attached to
+     */
+    map: null,
+    
+    /** 
+     * Constructor: OpenLayers.Marker
+     * Paraemeters:
+     * icon - {<OpenLayers.Icon>}  the icon for this marker
+     * lonlat - {<OpenLayers.LonLat>} the position of this marker
+     */
+    initialize: function(lonlat, icon) {
+        this.lonlat = lonlat;
+        
+        var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+        if (this.icon == null) {
+            this.icon = newIcon;
+        } else {
+            this.icon.url = newIcon.url;
+            this.icon.size = newIcon.size;
+            this.icon.offset = newIcon.offset;
+            this.icon.calculateOffset = newIcon.calculateOffset;
+        }
+        this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
+    },
+    
+    /**
+     * APIMethod: destroy
+     * Destroy the marker. You must first remove the marker from any 
+     * layer which it has been added to, or you will get buggy behavior.
+     * (This can not be done within the marker since the marker does not
+     * know which layer it is attached to.)
+     */
+    destroy: function() {
+        this.map = null;
+
+        this.events.destroy();
+        this.events = null;
+
+        if (this.icon != null) {
+            this.icon.destroy();
+            this.icon = null;
+        }
+    },
+    
+    /** 
+    * Method: draw
+    * Calls draw on the icon, and returns that output.
+    * 
+    * Parameters:
+    * px - {<OpenLayers.Pixel>}
+    * 
+    * Returns:
+    * {DOMElement} A new DOM Image with this marker's icon set at the 
+    * location passed-in
+    */
+    draw: function(px) {
+        return this.icon.draw(px);
+    }, 
+
+    /**
+    * Method: moveTo
+    * Move the marker to the new location.
+    *
+    * Parameters:
+    * px - {<OpenLayers.Pixel>} the pixel position to move to
+    */
+    moveTo: function (px) {
+        if ((px != null) && (this.icon != null)) {
+            this.icon.moveTo(px);
+        }           
+        this.lonlat = this.map.getLonLatFromLayerPx(px);
+    },
+
+    /**
+     * Method: onScreen
+     *
+     * Returns:
+     * {Boolean} Whether or not the marker is currently visible on screen.
+     */
+    onScreen:function() {
+        
+        var onScreen = false;
+        if (this.map) {
+            var screenBounds = this.map.getExtent();
+            onScreen = screenBounds.containsLonLat(this.lonlat);
+        }    
+        return onScreen;
+    },
+    
+    /**
+     * Method: inflate
+     * Englarges the markers icon by the specified ratio.
+     *
+     * Parameters:
+     * inflate - {float} the ratio to enlarge the marker by (passing 2
+     *                   will double the size).
+     */
+    inflate: function(inflate) {
+        if (this.icon) {
+            var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
+                                              this.icon.size.h * inflate);
+            this.icon.setSize(newSize);
+        }        
+    },
+    
+    /** 
+     * Method: setOpacity
+     * Change the opacity of the marker by changin the opacity of 
+     *   its icon
+     * 
+     * Parameters:
+     * opacity - {float}  Specified as fraction (0.4, etc)
+     */
+    setOpacity: function(opacity) {
+        this.icon.setOpacity(opacity);
+    },
+
+    /** 
+     * Method: display
+     * Hide or show the icon
+     * 
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.icon.display(display);
+    },
+
+    CLASS_NAME: "OpenLayers.Marker"
+});
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ * 
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+    var url = OpenLayers.Util.getImagesLocation() + "marker.png";
+    var size = new OpenLayers.Size(21, 25);
+    var calculateOffset = function(size) {
+                    return new OpenLayers.Pixel(-(size.w/2), -size.h);
+                 };
+
+    return new OpenLayers.Icon(url, size, null, calculateOffset);        
+};
+    
+
+/* ======================================================================
+    OpenLayers/Tile/Image.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile.js
+ * 
+ * Class: OpenLayers.Tile.Image
+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles
+ * used by various layers.  Create a new image tile with the
+ * <OpenLayers.Tile.Image> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+
+    /** 
+     * Property: url
+     * {String} The URL of the image being requested. No default. Filled in by
+     * layer.getURL() function. 
+     */
+    url: null,
+    
+    /** 
+     * Property: imgDiv
+     * {DOMElement} The div element which wraps the image.
+     */
+    imgDiv: null,
+
+    /**
+     * Property: frame
+     * {DOMElement} The image element is appended to the frame.  Any gutter on
+     * the image will be hidden behind the frame. 
+     */ 
+    frame: null, 
+
+    /** TBD 3.0 - reorder the parameters to the init function to remove 
+     *             URL. the getUrl() function on the layer gets called on 
+     *             each draw(), so no need to specify it here.
+     * 
+     * Constructor: OpenLayers.Tile.Image
+     * Constructor for a new <OpenLayers.Tile.Image> instance.
+     * 
+     * Parameters:
+     * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+     * position - {<OpenLayers.Pixel>}
+     * bounds - {<OpenLayers.Bounds>}
+     * url - {<String>} Deprecated. Remove me in 3.0.
+     * size - {<OpenLayers.Size>}
+     */   
+    initialize: function(layer, position, bounds, url, size) {
+        OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+
+        this.url = url; //deprecated remove me
+        
+        this.frame = document.createElement('div'); 
+        this.frame.style.overflow = 'hidden'; 
+        this.frame.style.position = 'absolute'; 
+    },
+
+    /** 
+     * APIMethod: destroy
+     * nullify references to prevent circular references and memory leaks
+     */
+    destroy: function() {
+        if (this.imgDiv != null)  {
+            OpenLayers.Event.stopObservingElement(this.imgDiv.id);
+            if (this.imgDiv.parentNode == this.frame) {
+                this.frame.removeChild(this.imgDiv);
+                this.imgDiv.map = null;
+            }
+        }
+        this.imgDiv = null;
+        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
+            this.layer.div.removeChild(this.frame); 
+        }
+        this.frame = null; 
+        OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+    },
+
+    /**
+     * Method: draw
+     * Check that a tile should be drawn, and draw it.
+     * 
+     * Returns:
+     * {Boolean} Always returns true.
+     */
+    draw:function() {
+        if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+            this.bounds = this.getBoundsFromBaseLayer(this.position);
+        }
+        if (!OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
+            return false;    
+        }
+        
+        if (this.isLoading) {
+            //if we're already loading, send 'reload' instead of 'loadstart'.
+            this.events.triggerEvent("reload"); 
+        } else {
+            this.isLoading = true;
+            this.events.triggerEvent("loadstart");
+        }
+        
+        if (this.imgDiv == null) {
+            this.initImgDiv();
+        }
+
+        this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+        
+        this.url = this.layer.getURL(this.bounds);
+        // position the frame 
+        OpenLayers.Util.modifyDOMElement(this.frame, 
+                                         null, this.position, this.size);   
+
+        var imageSize = this.layer.getImageSize(); 
+        if (this.layer.alpha) {
+            OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
+                    null, null, imageSize, this.url);
+        } else {
+            this.imgDiv.src = this.url;
+            OpenLayers.Util.modifyDOMElement(this.imgDiv,
+                    null, null, imageSize) ;
+        }
+        return true;
+    },
+
+    /** 
+     * Method: clear
+     *  Clear the tile of any bounds/position-related data so that it can 
+     *   be reused in a new location.
+     */
+    clear: function() {
+        if(this.imgDiv) {
+            this.imgDiv.style.display = "none";
+        }
+    },
+
+    /**
+     * Method: initImgDiv
+     * Creates the imgDiv property on the tile.
+     */
+    initImgDiv: function() {
+        
+        var offset = this.layer.imageOffset; 
+        var size = this.layer.getImageSize(); 
+     
+        if (this.layer.alpha) {
+            this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
+                                                           offset,
+                                                           size,
+                                                           null,
+                                                           "relative",
+                                                           null,
+                                                           null,
+                                                           null,
+                                                           true);
+        } else {
+            this.imgDiv = OpenLayers.Util.createImage(null,
+                                                      offset,
+                                                      size,
+                                                      null,
+                                                      "relative",
+                                                      null,
+                                                      null,
+                                                      true);
+        }
+        
+        this.imgDiv.className = 'olTileImage';
+
+        /* checkImgURL used to be used to called as a work around, but it
+           ended up hiding problems instead of solving them and broke things
+           like relative URLs. See discussion on the dev list:
+           http://openlayers.org/pipermail/dev/2007-January/000205.html
+
+        OpenLayers.Event.observe( this.imgDiv, "load",
+            OpenLayers.Function.bind(this.checkImgURL, this) );
+        */
+        this.frame.appendChild(this.imgDiv); 
+        this.layer.div.appendChild(this.frame); 
+
+        if(this.layer.opacity != null) {
+            
+            OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
+                                             null, null, null, 
+                                             this.layer.opacity);
+        }
+
+        // we need this reference to check back the viewRequestID
+        this.imgDiv.map = this.layer.map;
+
+        //bind a listener to the onload of the image div so that we 
+        // can register when a tile has finished loading.
+        var onload = function() {
+            
+            //normally isLoading should always be true here but there are some 
+            // right funky conditions where loading and then reloading a tile
+            // with the same url *really*fast*. this check prevents sending 
+            // a 'loadend' if the msg has already been sent
+            //
+            if (this.isLoading) { 
+                this.isLoading = false; 
+                this.events.triggerEvent("loadend"); 
+            }
+        }
+        OpenLayers.Event.observe(this.imgDiv, 'load',
+                                 OpenLayers.Function.bind(onload, this));
+
+    },
+
+    /**
+     * Method: checkImgURL
+     * Make sure that the image that just loaded is the one this tile is meant
+     * to display, since panning/zooming might have changed the tile's URL in
+     * the meantime. If the tile URL did change before the image loaded, set
+     * the imgDiv display to 'none', as either (a) it will be reset to visible
+     * when the new URL loads in the image, or (b) we don't want to display
+     * this tile after all because its new bounds are outside our maxExtent.
+     * 
+     * This function should no longer  be neccesary with the improvements to
+     * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
+     * caused problems in 2.2, but it's possible that with the improved 
+     * isEquivilant URL function, this might be neccesary at some point.
+     * 
+     * See discussion in the thread at 
+     * http://openlayers.org/pipermail/dev/2007-January/000205.html
+     */
+    checkImgURL: function () {
+        // Sometimes our image will load after it has already been removed
+        // from the map, in which case this check is not needed.  
+        if (this.layer) {
+            var loaded = this.layer.alpha ? this.imgDiv.firstChild.src : this.imgDiv.src;
+            if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
+                this.imgDiv.style.display = "none";
+            }
+        }
+    },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Tile.Image"
+  }
+);
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Click
+ * A handler for mouse clicks.  The intention of this handler is to give
+ *     controls more flexibility with handling clicks.  Browsers trigger
+ *     click events twice for a double-click.  In addition, the mousedown,
+ *     mousemove, mouseup sequence fires a click event.  With this handler,
+ *     controls can decide whether to ignore clicks associated with a double
+ *     click.  By setting a <pixelTolerance>, controls can also ignore clicks
+ *     that include a drag.  Create a new instance with the
+ *     <OpenLayers.Handler.Click> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler> 
+ */
+OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
+
+    /**
+     * APIProperty: delay
+     * {Number} Number of milliseconds between clicks before the event is
+     *     considered a double-click.
+     */
+    delay: 300,
+    
+    /**
+     * APIProperty: single
+     * {Boolean} Handle single clicks.  Default is true.  If false, clicks
+     * will not be reported.  If true, single-clicks will be reported.
+     */
+    single: true,
+    
+    /**
+     * APIProperty: double
+     * {Boolean} Handle double-clicks.  Default is false.
+     */
+    'double': false,
+    
+    /**
+     * APIProperty: pixelTolerance
+     * {Number} Maximum number of pixels between mouseup and mousedown for an
+     *     event to be considered a click.  Default is 0.  If set to an
+     *     integer value, clicks with a drag greater than the value will be
+     *     ignored.  This property can only be set when the handler is
+     *     constructed.
+     */
+    pixelTolerance: 0,
+    
+    /**
+     * APIProperty: stopSingle
+     * {Boolean} Stop other listeners from being notified of clicks.  Default
+     *     is false.  If true, any click listeners registered before this one
+     *     will not be notified of *any* click event (associated with double
+     *     or single clicks).
+     */
+    stopSingle: false,
+    
+    /**
+     * APIProperty: stopDouble
+     * {Boolean} Stop other listeners from being notified of double-clicks.
+     *     Default is false.  If true, any click listeners registered before
+     *     this one will not be notified of *any* double-click events.
+     * 
+     * The one caveat with stopDouble is that given a map with two click
+     *     handlers, one with stopDouble true and the other with stopSingle
+     *     true, the stopSingle handler should be activated last to get
+     *     uniform cross-browser performance.  Since IE triggers one click
+     *     with a dblclick and FF triggers two, if a stopSingle handler is
+     *     activated first, all it gets in IE is a single click when the
+     *     second handler stops propagation on the dblclick.
+     */
+    stopDouble: false,
+
+    /**
+     * Property: timerId
+     * {Number} The id of the timeout waiting to clear the <delayedEvent>.
+     */
+    timerId: null,
+    
+    /**
+     * Property: down
+     * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
+     */
+    down: null,
+    
+    /**
+     * Constructor: OpenLayers.Handler.Click
+     * Create a new click handler.
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that is making use of
+     *     this handler.  If a handler is being used without a control, the
+     *     handler's setMap method must be overridden to deal properly with
+     *     the map.
+     * callbacks - {Object} An object with keys corresponding to callbacks
+     *     that will be called by the handler. The callbacks should
+     *     expect to recieve a single argument, the click event.
+     *     Callbacks for 'click' and 'dblclick' are supported.
+     * options - {Object} Optional object whose properties will be set on the
+     *     handler.
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        // optionally register for mouseup and mousedown
+        if(this.pixelTolerance != null) {
+            this.mousedown = function(evt) {
+                this.down = evt.xy;
+                return true;
+            };
+        }
+    },
+    
+    /**
+     * Method: mousedown
+     * Handle mousedown.  Only registered as a listener if pixelTolerance is
+     *     a non-zero value at construction.
+     *
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    mousedown: null,
+    
+    /**
+     * Method: dblclick
+     * Handle dblclick.  For a dblclick, we get two clicks in some browsers
+     *     (FF) and one in others (IE).  So we need to always register for
+     *     dblclick to properly handle single clicks.
+     *     
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    dblclick: function(evt) {
+        if(this.passesTolerance(evt)) {
+            if(this["double"]) {
+                this.callback('dblclick', [evt]);
+            }
+            this.clearTimer();
+        }
+        return !this.stopDouble;
+    },
+    
+    /**
+     * Method: click
+     * Handle click.
+     *
+     * Returns:
+     * {Boolean} Continue propagating this event.
+     */
+    click: function(evt) {
+        if(this.passesTolerance(evt)) {
+            if(this.timerId != null) {
+                // already received a click
+                this.clearTimer();
+            } else {
+                // set the timer, send evt only if single is true
+                var clickEvent = this.single ? OpenLayers.Util.extend({},evt):null;
+                this.timerId = window.setTimeout(
+                    OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
+                    this.delay
+                );
+            }
+        }
+        return !this.stopSingle;
+    },
+    
+    /**
+     * Method: passesTolerance
+     * Determine whether the event is within the optional pixel tolerance.  Note
+     *     that the pixel tolerance check only works if mousedown events get to
+     *     the listeners registered here.  If they are stopped by other elements,
+     *     the <pixelTolerance> will have no effect here (this method will always
+     *     return true).
+     *
+     * Returns:
+     * {Boolean} The click is within the pixel tolerance (if specified).
+     */
+    passesTolerance: function(evt) {
+        var passes = true;
+        if(this.pixelTolerance != null && this.down) {
+            var dpx = Math.sqrt(
+                Math.pow(this.down.x - evt.xy.x, 2) +
+                Math.pow(this.down.y - evt.xy.y, 2)
+            );
+            if(dpx > this.pixelTolerance) {
+                passes = false;
+            }
+        }
+        return passes;
+    },
+
+    /**
+     * Method: clearTimer
+     * Clear the timer and set <timerId> to null.
+     */
+    clearTimer: function() {
+        if(this.timerId != null) {
+            window.clearTimeout(this.timerId);
+            this.timerId = null;
+        }
+    },
+    
+    /**
+     * Method: delayedCall
+     * Sets <timerId> to null.  And optionally triggers the click callback if
+     *     evt is set.
+     */
+    delayedCall: function(evt) {
+        this.timerId = null;
+        if(evt) {
+            this.callback('click', [evt]);
+        }
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Deactivate the handler.
+     *
+     * Returns:
+     * {Boolean} The handler was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.clearTimer();
+            this.down = null;
+            deactivated = true;
+        }
+        return deactivated;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Click"
+});
+/* ======================================================================
+    OpenLayers/Handler/Drag.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * 
+ * Class: OpenLayers.Handler.Drag
+ * The drag handler is used to deal with sequences of browser events related
+ *     to dragging.  The handler is used by controls that want to know when
+ *     a drag sequence begins, when a drag is happening, and when it has
+ *     finished.
+ *
+ * Controls that use the drag handler typically construct it with callbacks
+ *     for 'down', 'move', and 'done'.  Callbacks for these keys are called
+ *     when the drag begins, with each move, and when the drag is done.  In
+ *     addition, controls can have callbacks keyed to 'up' and 'out' if they
+ *     care to differentiate between the types of events that correspond with
+ *     the end of a drag sequence.
+ *
+ * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
+  
+    /** 
+     * Property: started
+     * {Boolean} When a mousedown event is received, we want to record it, but
+     *     not set 'dragging' until the mouse moves after starting. 
+     */
+    started: false,
+    
+    /** 
+     * Property: dragging 
+     * {Boolean} 
+     */
+    dragging: false,
+
+    /** 
+     * Property: last
+     * {<OpenLayers.Pixel>} The last pixel location of the drag.
+     */
+    last: null,
+
+    /** 
+     * Property: start
+     * {<OpenLayers.Pixel>} The first pixel location of the drag.
+     */
+    start: null,
+
+    /**
+     * Property: oldOnselectstart
+     * {Function}
+     */
+    oldOnselectstart: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Drag
+     * Returns OpenLayers.Handler.Drag
+     * 
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that is making use of
+     *     this handler.  If a handler is being used without a control, the
+     *     handlers setMap method must be overridden to deal properly with
+     *     the map.
+     * callbacks - {Object} An object containing a single function to be
+     *     called when the drag operation is finished. The callback should
+     *     expect to recieve a single argument, the pixel location of the event.
+     *     Callbacks for 'move' and 'done' are supported. You can also speficy
+     *     callbacks for 'down', 'up', and 'out' to respond to those events.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+    },
+    
+    /**
+     * The four methods below (down, move, up, and out) are used by subclasses
+     *     to do their own processing related to these mouse events.
+     */
+    
+    /**
+     * Method: down
+     * This method is called during the handling of the mouse down event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse down event
+     */
+    down: function(evt) {
+    },
+    
+    /**
+     * Method: move
+     * This method is called during the handling of the mouse move event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse move event
+     *
+     */
+    move: function(evt) {
+    },
+
+    /**
+     * Method: up
+     * This method is called during the handling of the mouse up event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse up event
+     */
+    up: function(evt) {
+    },
+
+    /**
+     * Method: out
+     * This method is called during the handling of the mouse out event.
+     *     Subclasses can do their own processing here.
+     *
+     * Parameters:
+     * evt - {Event} The mouse out event
+     */
+    out: function(evt) {
+    },
+
+    /**
+     * The methods below are part of the magic of event handling.  Because
+     *     they are named like browser events, they are registered as listeners
+     *     for the events they represent.
+     */
+
+    /**
+     * Method: mousedown
+     * Handle mousedown events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mousedown: function (evt) {
+        var propagate = true;
+        this.dragging = false;
+        if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
+            this.started = true;
+            this.start = evt.xy;
+            this.last = evt.xy;
+            // TBD replace with CSS classes
+            this.map.div.style.cursor = "move";
+            this.down(evt);
+            this.callback("down", [evt.xy]);
+            OpenLayers.Event.stop(evt);
+            
+            if(!this.oldOnselectstart) {
+                this.oldOnselectstart = document.onselectstart;
+                document.onselectstart = function() {return false;}
+            }
+            
+            propagate = false;
+        } else {
+            this.started = false;
+            this.start = null;
+            this.last = null;
+        }
+        return propagate;
+    },
+
+    /**
+     * Method: mousemove
+     * Handle mousemove events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mousemove: function (evt) {
+        if (this.started) {
+            if(evt.xy.x != this.last.x || evt.xy.y != this.last.y) {
+                this.dragging = true;
+                this.move(evt);
+                this.callback("move", [evt.xy]);
+                if(!this.oldOnselectstart) {
+                    this.oldOnselectstart = document.onselectstart;
+                    document.onselectstart = function() {return false;}
+                }
+                this.last = evt.xy;
+            }
+        }
+        return true;
+    },
+
+    /**
+     * Method: mouseup
+     * Handle mouseup events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mouseup: function (evt) {
+        if (this.started) {
+            this.started = false;
+            this.dragging = false;
+            // TBD replace with CSS classes
+            this.map.div.style.cursor = "";
+            this.up(evt);
+            this.callback("up", [evt.xy]);
+            this.callback("done", [evt.xy]);
+            document.onselectstart = this.oldOnselectstart;
+        }
+        return true;
+    },
+
+    /**
+     * Method: mouseout
+     * Handle mouseout events
+     *
+     * Parameters:
+     * evt - {Event} 
+     *
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    mouseout: function (evt) {
+        if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+            this.started = false; 
+            this.dragging = false;
+            // TBD replace with CSS classes
+            this.map.div.style.cursor = "";
+            this.out(evt);
+            this.callback("out", []);
+            if(document.onselectstart) {
+                document.onselectstart = this.oldOnselectstart;
+            }
+            this.callback("done", [evt.xy])
+        }
+        return true;
+    },
+
+    /**
+     * Method: click
+     * The drag handler captures the click event.  If something else registers
+     *     for clicks on the same element, its listener will not be called 
+     *     after a drag.
+     * 
+     * Parameters: 
+     * evt - {Event} 
+     * 
+     * Returns:
+     * {Boolean} Let the event propagate.
+     */
+    click: function (evt) {
+        // let the click event propagate only if the mouse moved
+        return (this.start == this.last);
+    },
+
+    /**
+     * Method: activate
+     * Activate the handler.
+     * 
+     * Returns:
+     * {Boolean} The handler was successfully activated.
+     */
+    activate: function() {
+        var activated = false;
+        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragging = false;
+            activated = true;
+        }
+        return activated;
+    },
+
+    /**
+     * Method: deactivate 
+     * Deactivate the handler.
+     * 
+     * Returns:
+     * {Boolean} The handler was successfully deactivated.
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.started = false;
+            this.dragging = false;
+            this.start = null;
+            this.last = null;
+            deactivated = true;
+        }
+        return deactivated;
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Drag"
+});
+/* ======================================================================
+    OpenLayers/Handler/MouseWheel.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ *
+ * Class: OpenLayers.Handler.MouseWheel
+ * Handler for wheel up/down events.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
+    /** 
+     * Property: wheelListener 
+     * {function} 
+     */
+    wheelListener: null,
+
+    /** 
+     * Property: mousePosition
+     * {<OpenLayers.Pixel>} mousePosition is necessary because
+     * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
+     * value from the last mousemove.
+     */
+    mousePosition: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.MouseWheel
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} 
+     * callbacks - {Object} An object containing a single function to be
+     *                          called when the drag operation is finished.
+     *                          The callback should expect to recieve a single
+     *                          argument, the point geometry.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        this.wheelListener = OpenLayers.Function.bindAsEventListener(
+            this.onWheelEvent, this
+        );
+    },
+
+    /**
+     * Method: destroy
+     */    
+    destroy: function() {
+        OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+        this.wheelListener = null;
+    },
+
+    /**
+     *  Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+     */
+
+    /** 
+     * Method: onWheelEvent
+     * Catch the wheel event and handle it xbrowserly
+     * 
+     * Parameters:
+     * e - {Event} 
+     */
+    onWheelEvent: function(e){
+        // first check keyboard modifiers
+        if (!this.checkModifiers(e)) return;
+
+        // first determine whether or not the wheeling was inside the map
+        var inMap = false;
+        var elem = OpenLayers.Event.element(e);
+        while(elem != null) {
+            if (this.map && elem == this.map.div) {
+                inMap = true;
+                break;
+            }
+            elem = elem.parentNode;
+        }
+        
+        if (inMap) {
+            var delta = 0;
+            if (!e) {
+                e = window.event;
+            }
+            if (e.wheelDelta) {
+                delta = e.wheelDelta/120; 
+                if (window.opera) {
+                    delta = -delta;
+                }
+            } else if (e.detail) {
+                delta = -e.detail / 3;
+            }
+            if (delta) {
+                // add the mouse position to the event because mozilla has a bug
+                // with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
+                // getLonLatFromViewPortPx(e) returns wrong values
+                if (this.mousePosition) {
+                    e.xy = this.mousePosition;
+                } 
+                if (!e.xy) {
+                    // If the mouse hasn't moved over the map yet, then
+                    // we don't have a mouse position (in FF), so we just
+                    // act as if the mouse was at the center of the map.
+                    // Note that we can tell we are in the map -- and 
+                    // this.map is ensured to be true above.
+                    e.xy = this.map.getPixelFromLonLat(this.map.getCenter());
+                }
+                if (delta < 0) {
+                   this.callback("down", [e, delta]);
+                } else {
+                   this.callback("up", [e, delta]);
+                }
+            }
+            
+            //only wheel the map, not the window
+            OpenLayers.Event.stop(e);
+        }
+    },
+
+    /**
+     * Method: mousemove
+     * Update the stored mousePosition on every move.
+     * 
+     * Parameters:
+     * evt - {Event} The browser event
+     *
+     * Returns: 
+     * {Boolean} Allow event propagation
+     */
+    mousemove: function (evt) {
+        this.mousePosition = evt.xy;
+    },
+
+    /**
+     * Method: activate 
+     */
+    activate: function (evt) {
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            //register mousewheel events specifically on the window and document
+            var wheelListener = this.wheelListener;
+            OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
+            OpenLayers.Event.observe(window, "mousewheel", wheelListener);
+            OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Method: deactivate 
+     */
+    deactivate: function (evt) {
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            // unregister mousewheel events specifically on the window and document
+            var wheelListener = this.wheelListener;
+            OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
+            OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
+            OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.MouseWheel"
+});
+/* ======================================================================
+    OpenLayers/Layer.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Map.js
+ * 
+ * Class: OpenLayers.Layer
+ */
+OpenLayers.Layer = OpenLayers.Class({
+
+    /**
+     * APIProperty: id
+     * {String}
+     */
+    id: null,
+
+    /** 
+     * APIProperty: name
+     * {String}
+     */
+    name: null,
+
+    /** 
+     * APIProperty: div
+     * {DOMElement}
+     */
+    div: null,
+
+    /** 
+     * Constant: EVENT_TYPES
+     * {Array(String)} Supported application event types
+     */
+    EVENT_TYPES: [ "loadstart", "loadend", "loadcancel", "visibilitychanged"],
+        
+    /**
+     * APIProperty: events``
+     * {<OpenLayers.Events>}
+     */
+    events: null,
+
+    /**
+     * APIProperty: map
+     * {<OpenLayers.Map>} This variable is set when the layer is added to 
+     *     the map, via the accessor function setMap().
+     */
+    map: null,
+    
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} Whether or not the layer is a base layer. This should be set 
+     *     individually by all subclasses. Default is false
+     */
+    isBaseLayer: false,
+ 
+    /**
+     * Property: alpha
+     * {Boolean} The layer's images have an alpha channel.  Default is false. 
+     */
+    alpha: false,
+
+    /** 
+     * APIProperty: displayInLayerSwitcher
+     * {Boolean} Display the layer's name in the layer switcher.  Default is
+     *     true.
+     */
+    displayInLayerSwitcher: true,
+
+    /**
+     * APIProperty: visibility
+     * {Boolean} The layer should be displayed in the map.  Default is true.
+     */
+    visibility: true,
+
+    /**
+     * APIProperty: attribution
+     * {String} Attribution string, displayed when an 
+     *     <OpenLayers.Control.Attribution> has been added to the map.
+     */
+    attribution: null, 
+
+    /** 
+     * Property: inRange
+     * {Boolean} The current map resolution is within the layer's min/max 
+     *     range. This is set in <OpenLayers.Map.setCenter> whenever the zoom 
+     *     changes.
+     */
+    inRange: false,
+    
+    /**
+     * Propery: imageSize
+     * {<OpenLayers.Size>} For layers with a gutter, the image is larger than 
+     *     the tile by twice the gutter in each dimension.
+     */
+    imageSize: null,
+    
+    /**
+     * Property: imageOffset
+     * {<OpenLayers.Pixel>} For layers with a gutter, the image offset 
+     *     represents displacement due to the gutter.
+     */
+    imageOffset: null,
+
+  // OPTIONS
+
+    /** 
+     * Property: options
+     * {Object} An optional object whose properties will be set on the layer.
+     *     Any of the layer properties can be set as a property of the options
+     *     object and sent to the constructor when the layer is created.
+     */
+    options: null,
+
+    /**
+     * APIProperty: gutter
+     * {Integer} Determines the width (in pixels) of the gutter around image
+     *     tiles to ignore.  By setting this property to a non-zero value,
+     *     images will be requested that are wider and taller than the tile
+     *     size by a value of 2 x gutter.  This allows artifacts of rendering
+     *     at tile edges to be ignored.  Set a gutter value that is equal to
+     *     half the size of the widest symbol that needs to be displayed.
+     *     Defaults to zero.  Non-tiled layers always have zero gutter.
+     */ 
+    gutter: 0, 
+
+    /**
+     * APIProperty: projection
+     * {String} Set in the layer options to override the default projection
+     *     string this layer - also set maxExtent, maxResolution, and units if
+     *     appropriate.
+     */
+    projection: null,    
+    
+    /**
+     * APIProperty: units
+     * {String} The layer map units.  Defaults to 'degrees'.  Possible values
+     *     are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+     */
+    units: null,
+
+    /**
+     * APIProperty: scales
+     * {Array}  An array of map scales in descending order.  The values in the
+     *     array correspond to the map scale denominator.  Note that these
+     *     values only make sense if the display (monitor) resolution of the
+     *     client is correctly guessed by whomever is configuring the
+     *     application.  In addition, the units property must also be set.
+     *     Use <resolutions> instead wherever possible.
+     */
+    scales: null,
+
+    /**
+     * APIProperty: resolutions
+     * {Array} A list of map resolutions (map units per pixel) in descending
+     *     order.  If this is not set in the layer constructor, it will be set
+     *     based on other resolution related properties (maxExtent,
+     *     maxResolution, maxScale, etc.).
+     */
+    resolutions: null,
+    
+    /**
+     * APIProperty: maxExtent
+     * {<OpenLayers.Bounds>}  The center of these bounds will not stray outside
+     *     of the viewport extent during panning.  In addition, if
+     *     <displayOutsideMaxExtent> is set to false, data will not be
+     *     requested that falls completely outside of these bounds.
+     */
+    maxExtent: null,
+    
+    /**
+     * APIProperty: minExtent
+     * {<OpenLayers.Bounds>}
+     */
+    minExtent: null,
+    
+    /**
+     * APIProperty: maxResolution
+     * {Float} Default max is 360 deg / 256 px, which corresponds to
+     *     zoom level 0 on gmaps.  Specify a different value in the layer 
+     *     options if you are not using a geographic projection and 
+     *     displaying the whole world.
+     */
+    maxResolution: null,
+
+    /**
+     * APIProperty: minResolution
+     * {Float}
+     */
+    minResolution: null,
+
+    /**
+     * APIProperty: numZoomLevels
+     * {Integer}
+     */
+    numZoomLevels: null,
+   
+    /**
+     * APIProperty: minScale
+     * {Float}
+     */
+    minScale: null,
+    
+    /**
+     * APIProperty: maxScale
+     * {Float}
+     */
+    maxScale: null,
+
+    /**
+     * APIProperty: displayOutsideMaxExtent
+     * {Boolean} Request map tiles that are completely outside of the max 
+     *     extent for this layer. Defaults to false.
+     */
+    displayOutsideMaxExtent: false,
+
+    /**
+     * APIProperty: wrapDateLine
+     * {Boolean} #487 for more info.   
+     */
+    wrapDateLine: false,
+    
+    
+    /**
+     * Constructor: OpenLayers.Layer
+     *
+     * Parameters:
+     * name - {String} The layer name
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+
+        this.addOptions(options);
+
+        this.name = name;
+        
+        if (this.id == null) {
+
+            this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+
+            this.div = OpenLayers.Util.createDiv();
+            this.div.style.width = "100%";
+            this.div.style.height = "100%";
+            this.div.id = this.id;
+
+            this.events = new OpenLayers.Events(this, this.div, 
+                                                this.EVENT_TYPES);
+        }
+
+        if (this.wrapDateLine) {
+            this.displayOutsideMaxExtent = true;
+        }
+    },
+    
+    /**
+     * Method: destroy
+     * Destroy is a destructor: this is to alleviate cyclic references which
+     *     the Javascript garbage cleaner can not take care of on its own.
+     *
+     * Parameters:
+     * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
+     *     been destroyed.  Default is true.
+     */
+    destroy: function(setNewBaseLayer) {
+        if (setNewBaseLayer == null) {
+            setNewBaseLayer = true;
+        }
+        if (this.map != null) {
+            this.map.removeLayer(this, setNewBaseLayer);
+        }
+        this.map = null;
+        this.name = null;
+        this.div = null;
+        this.options = null;
+
+        if (this.events) {
+            this.events.destroy();
+        }
+        this.events = null;
+    },
+    
+   /**
+    * Method: clone
+    *
+    * Parameters:
+    * obj - {<OpenLayers.Layer>} The layer to be cloned
+    *
+    * Returns:
+    * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
+    */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer(this.name, this.options);
+        } 
+        
+        // catch any randomly tagged-on properties
+        OpenLayers.Util.applyDefaults(obj, this);
+        
+        // a cloned layer should never have its map property set
+        //  because it has not been added to a map yet. 
+        obj.map = null;
+        
+        return obj;
+    },
+    
+    /** 
+     * APIMethod: setName
+     * Sets the new layer name for this layer.  Can trigger a changelayer event
+     *     on the map.
+     *
+     * Parameters:
+     * newName - {String} The new name.
+     */
+    setName: function(newName) {
+        if (newName != this.name) {
+            this.name = newName;
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer");
+            }
+        }
+    },    
+    
+   /**
+    * APIMethod: addOptions
+    * 
+    * Parameters:
+    * newOptions - {Object}
+    */
+    addOptions: function (newOptions) {
+        
+        if (this.options == null) {
+            this.options = {};
+        }
+        
+        // update our copy for clone
+        OpenLayers.Util.extend(this.options, newOptions);
+
+        // add new options to this
+        OpenLayers.Util.extend(this, newOptions);
+    },
+    
+    /**
+     * APIMethod: onMapResize
+     * This function can be implemented by subclasses
+     */
+    onMapResize: function() {
+        //this function can be implemented by subclasses  
+    },
+
+    /**
+     * APIMethod: redraw
+     * Redraws the layer.  Returns true if the layer was redrawn, false if not.
+     *
+     * Returns:
+     * {Boolean} The layer was redrawn.
+     */
+    redraw: function() {
+        var redrawn = false;
+        if (this.map) {
+
+            // min/max Range may have changed
+            this.inRange = this.calculateInRange();
+
+            // map's center might not yet be set
+            var extent = this.getExtent();
+
+            if (extent && this.inRange && this.visibility) {
+                this.moveTo(extent, true, false);
+                redrawn = true;
+            }
+        }
+        return redrawn;
+    },
+
+    /**
+     * Method: moveTo
+     * 
+     * Parameters:
+     * bound - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
+     *     do some init work in that case.
+     * dragging - {Boolean}
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        var display = this.visibility;
+        if (!this.isBaseLayer) {
+            display = display && this.inRange;
+        }
+        this.display(display);
+    },
+
+    /**
+     * Method: setMap
+     * Set the map property for the layer. This is done through an accessor
+     *     so that subclasses can override this and take special action once 
+     *     they have their map variable set. 
+     * 
+     *     Here we take care to bring over any of the necessary default 
+     *     properties from the map. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    setMap: function(map) {
+        if (this.map == null) {
+        
+            this.map = map;
+            
+            // grab some essential layer data from the map if it hasn't already
+            //  been set
+            this.maxExtent = this.maxExtent || this.map.maxExtent;
+            this.projection = this.projection || this.map.projection;
+            
+            if (this.projection && typeof this.projection == "string") {
+                this.projection = new OpenLayers.Projection(this.projection);
+            }
+            
+            // Check the projection to see if we can get units -- if not, refer
+            // to properties.
+            this.units = this.projection.getUnits() ||
+                         this.units || this.map.units;
+            
+            this.initResolutions();
+            
+            if (!this.isBaseLayer) {
+                this.inRange = this.calculateInRange();
+                var show = ((this.visibility) && (this.inRange));
+                this.div.style.display = show ? "" : "none";
+            }
+            
+            // deal with gutters
+            this.setTileSize();
+        }
+    },
+    
+    /**
+     * APIMethod: removeMap
+     * Just as setMap() allows each layer the possibility to take a 
+     *     personalized action on being added to the map, removeMap() allows
+     *     each layer to take a personalized action on being removed from it. 
+     *     For now, this will be mostly unused, except for the EventPane layer,
+     *     which needs this hook so that it can remove the special invisible
+     *     pane. 
+     * 
+     * Parameters:
+     * map - {<OpenLayers.Map>}
+     */
+    removeMap: function(map) {
+        //to be overridden by subclasses
+    },
+    
+    /**
+     * APIMethod: getImageSize
+     * 
+     * Returns:
+     * {<OpenLayers.Size>} The size that the image should be, taking into 
+     *     account gutters.
+     */ 
+    getImageSize: function() { 
+        return (this.imageSize || this.tileSize); 
+    },    
+  
+    /**
+     * APIMethod: setTileSize
+     * Set the tile size based on the map size.  This also sets layer.imageSize
+     *     and layer.imageOffset for use by Tile.Image.
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setTileSize: function(size) {
+        var tileSize = (size) ? size :
+                                ((this.tileSize) ? this.tileSize :
+                                                   this.map.getTileSize());
+        this.tileSize = tileSize;
+        if(this.gutter) {
+          // layers with gutters need non-null tile sizes
+          //if(tileSize == null) {
+          //    OpenLayers.console.error("Error in layer.setMap() for " +
+          //                              this.name + ": layers with " +
+          //                              "gutters need non-null tile sizes");
+          //}
+            this.imageOffset = new OpenLayers.Pixel(-this.gutter, 
+                                                    -this.gutter); 
+            this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), 
+                                                 tileSize.h + (2*this.gutter)); 
+        }
+    },
+
+    /**
+     * APIMethod: getVisibility
+     * 
+     * Returns:
+     * {Boolean} The layer should be displayed (if in range).
+     */
+    getVisibility: function() {
+        return this.visibility;
+    },
+
+    /** 
+     * APIMethod: setVisibility
+     * Set the visibility flag for the layer and hide/show & redraw 
+     *     accordingly. Fire event unless otherwise specified
+     * 
+     * Note that visibility is no longer simply whether or not the layer's
+     *     style.display is set to "block". Now we store a 'visibility' state 
+     *     property on the layer class, this allows us to remember whether or 
+     *     not we *desire* for a layer to be visible. In the case where the 
+     *     map's resolution is out of the layer's range, this desire may be 
+     *     subverted.
+     * 
+     * Parameters:
+     * visible - {Boolean} Whether or not to display the layer (if in range)
+     */
+    setVisibility: function(visibility) {
+        if (visibility != this.visibility) {
+            this.visibility = visibility;
+            this.display(visibility);
+            this.redraw();
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer");
+            }
+            this.events.triggerEvent("visibilitychanged");
+        }
+    },
+
+    /** 
+     * APIMethod: display
+     * Hide or show the Layer
+     * 
+     * Parameters:
+     * display - {Boolean}
+     */
+    display: function(display) {
+        if (display != (this.div.style.display != "none")) {
+            this.div.style.display = (display) ? "block" : "none";
+        }
+    },
+
+    /**
+     * Method: calculateInRange
+     * 
+     * Returns:
+     * {Boolean} The layer is displayable at the current map's current
+     *     resolution.
+     */
+    calculateInRange: function() {
+        var inRange = false;
+        if (this.map) {
+            var resolution = this.map.getResolution();
+            inRange = ( (resolution >= this.minResolution) &&
+                        (resolution <= this.maxResolution) );
+        }
+        return inRange;
+    },
+
+    /** 
+     * APIMethod: setIsBaseLayer
+     * 
+     * Parameters:
+     * isBaseLayer - {Boolean}
+     */
+    setIsBaseLayer: function(isBaseLayer) {
+        if (isBaseLayer != this.isBaseLayer) {
+            this.isBaseLayer = isBaseLayer;
+            if (this.map != null) {
+                this.map.events.triggerEvent("changelayer");
+            }
+        }
+    },
+
+  /********************************************************/
+  /*                                                      */
+  /*                 Baselayer Functions                  */
+  /*                                                      */
+  /********************************************************/
+  
+    /** 
+     * Method: initResolutions
+     * This method's responsibility is to set up the 'resolutions' array 
+     *     for the layer -- this array is what the layer will use to interface
+     *     between the zoom levels of the map and the resolution display 
+     *     of the layer.
+     * 
+     * The user has several options that determine how the array is set up.
+     *  
+     * For a detailed explanation, see the following wiki from the 
+     *     openlayers.org homepage:
+     *     http://trac.openlayers.org/wiki/SettingZoomLevels
+     */
+    initResolutions: function() {
+
+        // These are the relevant options which are used for calculating 
+        //  resolutions information.
+        //
+        var props = new Array(
+          'projection', 'units',
+          'scales', 'resolutions',
+          'maxScale', 'minScale', 
+          'maxResolution', 'minResolution', 
+          'minExtent', 'maxExtent',
+          'numZoomLevels', 'maxZoomLevel'
+        );
+
+        // First we create a new object where we will store all of the 
+        //  resolution-related properties that we find in either the layer's
+        //  'options' array or from the map.
+        //
+        var confProps = {};        
+        for(var i=0; i < props.length; i++) {
+            var property = props[i];
+            confProps[property] = this.options[property] || this.map[property];
+        }
+        
+        // If numZoomLevels hasn't been set and the maxZoomLevel *has*, 
+        //  then use maxZoomLevel to calculate numZoomLevels
+        //
+        if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
+            confProps.numZoomLevels = confProps.maxZoomLevel + 1;
+        }
+
+        // First off, we take whatever hodge-podge of values we have and 
+        //  calculate/distill them down into a resolutions[] array
+        //
+        if ((confProps.scales != null) || (confProps.resolutions != null)) {
+          //preset levels
+            if (confProps.scales != null) {
+                confProps.resolutions = [];
+                for(var i = 0; i < confProps.scales.length; i++) {
+                    var scale = confProps.scales[i];
+                    confProps.resolutions[i] = 
+                       OpenLayers.Util.getResolutionFromScale(scale, 
+                                                              confProps.units);
+                }
+            }
+            confProps.numZoomLevels = confProps.resolutions.length;
+
+        } else {
+          //maxResolution and numZoomLevels based calculation
+            
+            confProps.resolutions = [];
+            
+            // determine maxResolution
+            if (confProps.minScale) {
+                confProps.maxResolution = 
+                    OpenLayers.Util.getResolutionFromScale(confProps.minScale, 
+                                                           confProps.units);
+            } else if (confProps.maxResolution == "auto") {
+                var viewSize = this.map.getSize();
+                var wRes = confProps.maxExtent.getWidth() / viewSize.w;
+                var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
+                confProps.maxResolution = Math.max(wRes, hRes);
+            } 
+
+            // determine minResolution
+            if (confProps.maxScale != null) {           
+                confProps.minResolution = 
+                    OpenLayers.Util.getResolutionFromScale(confProps.maxScale);
+            } else if ( (confProps.minResolution == "auto") && 
+                        (confProps.minExtent != null) ) {
+                var viewSize = this.map.getSize();
+                var wRes = confProps.minExtent.getWidth() / viewSize.w;
+                var hRes = confProps.minExtent.getHeight()/ viewSize.h;
+                confProps.minResolution = Math.max(wRes, hRes);
+            } 
+
+            // determine numZoomLevels
+            if (confProps.minResolution != null) {
+                var ratio = confProps.maxResolution / confProps.minResolution;
+                confProps.numZoomLevels = 
+                    Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+            }
+            
+            // now we have numZoomLevels and maxResolution, 
+            //  we can populate the resolutions array
+            for (var i=0; i < confProps.numZoomLevels; i++) {
+                var res = confProps.maxResolution / Math.pow(2, i)
+                confProps.resolutions.push(res);
+            }    
+        }
+        
+        //sort resolutions array ascendingly
+        //
+        confProps.resolutions.sort( function(a, b) { return(b-a); } );
+
+        // now set our newly calculated values back to the layer 
+        //  Note: We specifically do *not* set them to layer.options, which we 
+        //        will preserve as it was when we added this layer to the map. 
+        //        this way cloned layers reset themselves to new map div 
+        //        dimensions)
+        //
+
+        this.resolutions = confProps.resolutions;
+        this.maxResolution = confProps.resolutions[0];
+        var lastIndex = confProps.resolutions.length - 1;
+        this.minResolution = confProps.resolutions[lastIndex];
+        
+        this.scales = [];
+        for(var i = 0; i < confProps.resolutions.length; i++) {
+            this.scales[i] = 
+               OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i], 
+                                                      confProps.units);
+        }
+        this.minScale = this.scales[0];
+        this.maxScale = this.scales[this.scales.length - 1];
+        
+        this.numZoomLevels = confProps.numZoomLevels;
+    },
+
+    /**
+     * APIMethod: getResolution
+     * 
+     * Returns:
+     * {Float} The currently selected resolution of the map, taken from the
+     *     resolutions array, indexed by current zoom level.
+     */
+    getResolution: function() {
+        var zoom = this.map.getZoom();
+        return this.resolutions[zoom];
+    },
+
+    /** 
+     * APIMethod: getExtent
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat 
+     *     bounds of the current viewPort.
+     */
+    getExtent: function() {
+        // just use stock map calculateBounds function -- passing no arguments
+        //  means it will user map's current center & resolution
+        //
+        return this.map.calculateBounds();
+    },
+
+    /**
+     * APIMethod: getZoomForExtent
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     that still contains the passed-in extent. We do this by calculating
+     *     the ideal resolution for the given exteng (based on the map size)
+     *     and then find the closest resolution to this ideal resolution.
+     */
+    getZoomForExtent: function(extent) {
+        var viewSize = this.map.getSize();
+        var idealResolution = Math.max( extent.getWidth()  / viewSize.w,
+                                        extent.getHeight() / viewSize.h );
+
+        return this.getZoomForResolution(idealResolution);
+    },
+    
+    /** 
+     * Method: getDataExtent
+     * Calculates the max extent which includes all of the data for the layer.
+     *     This function is to be implemented by subclasses.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        //to be implemented by subclasses
+    },
+
+    /**
+     * APIMethod: getZoomForResolution
+     * Get the index for the closest resolution in the layers resolutions array.
+     * 
+     * Parameters:
+     * resolution - {Float} Map units per pixel.
+     * 
+     * Returns:
+     * {Integer} The index of the zoomLevel (entry in the resolutions array) 
+     *     that is the closest to the passed-in resolution.
+     */
+    getZoomForResolution: function(resolution) {
+        var zoom, diff;
+        var minDiff = Number.POSITIVE_INFINITY;
+        for(var i=0; i < this.resolutions.length; i++) {
+            diff = Math.abs(this.resolutions[i] - resolution);
+            if(diff < minDiff) {
+                zoom = i;
+                minDiff = diff;
+            } else if(diff > minDiff) {
+                break;
+            }
+        }
+        return zoom;
+    },
+    
+    /**
+     * APIMethod: getLonLatFromViewPortPx
+     * 
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>}
+     *
+     * Returns:
+     * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in 
+     *     view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
+     */
+    getLonLatFromViewPortPx: function (viewPortPx) {
+        var lonlat = null;
+        if (viewPortPx != null) {
+            var size = this.map.getSize();
+            var center = this.map.getCenter();
+            if (center) {
+                var res  = this.map.getResolution();
+        
+                var delta_x = viewPortPx.x - (size.w / 2);
+                var delta_y = viewPortPx.y - (size.h / 2);
+            
+                lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
+                                             center.lat - delta_y * res); 
+
+                if (this.wrapDateLine) {
+                    lonlat = lonlat.wrapDateLine(this.maxExtent);
+                }
+            } // else { DEBUG STATEMENT }
+        }
+        return lonlat;
+    },
+
+    /**
+     * APIMethod: getViewPortPxFromLonLat
+     * 
+     * Parameters:
+     * lonlat - {<OpenLayers.LonLat>}
+     *
+     * Returns: 
+     * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in 
+     *     <OpenLayers.LonLat>,translated into view port pixels.
+     */
+    getViewPortPxFromLonLat: function (lonlat) {
+        var px = null; 
+        if (lonlat != null) {
+            var resolution = this.map.getResolution();
+            var extent = this.map.getExtent();
+            px = new OpenLayers.Pixel(
+                Math.round(1/resolution * (lonlat.lon - extent.left)),
+                Math.round(1/resolution * (extent.top - lonlat.lat))
+            );    
+        }
+        return px;
+    },
+    
+    /**
+     * APIMethod: setOpacity
+     * Sets the opacity for the entire layer (all images)
+     * 
+     * Parameter:
+     * opacity - {Float}
+     */
+    setOpacity: function(opacity) {
+        if (opacity != this.opacity) {
+            this.opacity = opacity;
+            for(var i=0; i<this.div.childNodes.length; ++i) {
+                var element = this.div.childNodes[i].firstChild;
+                OpenLayers.Util.modifyDOMElement(element, null, null, null, 
+                                                 null, null, null, opacity);
+            }
+        }
+    },
+
+    /**
+     * Method: setZIndex
+     * 
+     * Parameters: 
+     * zIndex - {Integer}
+     */    
+    setZIndex: function (zIndex) {
+        this.div.style.zIndex = zIndex;
+    },
+
+    /**
+     * Method: adjustBounds
+     * This function will take a bounds, and if wrapDateLine option is set
+     *     on the layer, it will return a bounds which is wrapped around the 
+     *     world. We do not wrap for bounds which *cross* the 
+     *     maxExtent.left/right, only bounds which are entirely to the left 
+     *     or entirely to the right.
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    adjustBounds: function (bounds) {
+
+        if (this.gutter) {
+            // Adjust the extent of a bounds in map units by the 
+            // layer's gutter in pixels.
+            var mapGutter = this.gutter * this.map.getResolution();
+            bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
+                                           bounds.bottom - mapGutter,
+                                           bounds.right + mapGutter,
+                                           bounds.top + mapGutter);
+        }
+
+        if (this.wrapDateLine) {
+            // wrap around the date line, within the limits of rounding error
+            var wrappingOptions = { 
+                'rightTolerance':this.getResolution()
+            };    
+            bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
+                              
+        }
+        return bounds;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer"
+});
+/* ======================================================================
+    OpenLayers/Marker/Box.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Marker.js
+ *
+ * Class: OpenLayers.Marker.Box
+ *
+ * Inherits from:
+ *  - <OpenLayers.Marker> 
+ */
+OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
+
+    /** 
+     * Property: bounds 
+     * {<OpenLayers.Bounds>} 
+     */
+    bounds: null,
+
+    /** 
+     * Property: div 
+     * {DOMElement} 
+     */
+    div: null,
+    
+    /** 
+     * Constructor: OpenLayers.Marker.Box
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * borderColor - {String} 
+     * borderWidth - {int} 
+     */
+    initialize: function(bounds, borderColor, borderWidth) {
+        this.bounds = bounds;
+        this.div    = OpenLayers.Util.createDiv();
+        this.div.style.overflow = 'hidden';
+        this.events = new OpenLayers.Events(this, this.div, null);
+        this.setBorder(borderColor, borderWidth);
+    },
+
+    /**
+     * Method: destroy 
+     */    
+    destroy: function() {
+
+        this.bounds = null;
+        this.div = null;
+
+        OpenLayers.Marker.prototype.destroy.apply(this, arguments);
+    },
+
+    /** 
+     * Method: setBorder
+     * Allow the user to change the box's color and border width
+     * 
+     * Parameters:
+     * color - {String} Default is "red"
+     * width - {int} Default is 2
+     */
+    setBorder: function (color, width) {
+        if (!color) {
+            color = "red";
+        }
+        if (!width) {
+            width = 2;
+        }
+        this.div.style.border = width + "px solid " + color;
+    },
+    
+    /** 
+    * Method: draw
+    * 
+    * Parameters:
+    * px - {<OpenLayers.Pixel>} 
+    * sz - {<OpenLayers.Size>} 
+    * 
+    * Returns: 
+    * {DOMElement} A new DOM Image with this marker´s icon set at the 
+    *         location passed-in
+    */
+    draw: function(px, sz) {
+        OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
+        return this.div;
+    }, 
+
+    /**
+     * Method: onScreen
+     * 
+     * Rreturn:
+     * {Boolean} Whether or not the marker is currently visible on screen.
+     */
+    onScreen:function() {
+        var onScreen = false;
+        if (this.map) {
+            var screenBounds = this.map.getExtent();
+            onScreen = screenBounds.containsBounds(this.bounds, true, true);
+        }    
+        return onScreen;
+    },
+    
+    /**
+     * Method: display
+     * Hide or show the icon
+     * 
+     * Parameters:
+     * display - {Boolean} 
+     */
+    display: function(display) {
+        this.div.style.display = (display) ? "" : "none";
+    },
+
+    CLASS_NAME: "OpenLayers.Marker.Box"
+});
+
+/* ======================================================================
+    OpenLayers/Control/DragPan.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ *
+ * Class: OpenLayers.Control.DragPan
+ * DragPan control.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
+
+    /** 
+     * Property: type
+     * {OpenLayers.Control.TYPES}
+     */
+    type: OpenLayers.Control.TYPE_TOOL,
+    
+    /**
+     * Property: panned
+     * {Boolean} The map moved.
+     */
+    panned: false,
+    
+    /**
+     * Method: draw
+     * Creates a Drag handler, using <OpenLayers.Control.PanMap.panMap> and
+     * <OpenLayers.Control.PanMap.panMapDone> as callbacks.
+     */    
+    draw: function() {
+        this.handler = new OpenLayers.Handler.Drag(this,
+                            {"move": this.panMap, "done": this.panMapDone});
+    },
+
+    /**
+    * Method: panMap
+    *
+    * Parameters:
+    * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+    */
+    panMap: function(xy) {
+        this.panned = true;
+        var deltaX = this.handler.last.x - xy.x;
+        var deltaY = this.handler.last.y - xy.y;
+        var size = this.map.getSize();
+        var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
+                                         size.h / 2 + deltaY);
+        var newCenter = this.map.getLonLatFromViewPortPx( newXY );
+        this.map.setCenter(newCenter, null, this.handler.dragging);
+    },
+    
+    /**
+     * Method: panMapDone
+     * Finish the panning operation.  Only call setCenter (through <panMap>)
+     *     if the map has actually been moved.
+     *
+     * Parameters:
+     * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+     */
+    panMapDone: function(xy) {
+        if(this.panned) {
+            this.panMap(xy);
+            this.panned = false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.DragPan"
+});
+/* ======================================================================
+    OpenLayers/Handler/Box.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Handler/Drag.js
+ * 
+ * Class: OpenLayers.Handler.Box
+ * Handler for dragging a rectangle across the map.  Box is displayed 
+ * on mouse down, moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Handler> 
+ */
+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
+
+    /** 
+     * Property: dragHandler 
+     * {<OpenLayers.Handler.Drag>} 
+     */
+    dragHandler: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.Box
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} 
+     * callbacks - {Object} An object containing a single function to be
+     *                          called when the drag operation is finished.
+     *                          The callback should expect to recieve a single
+     *                          argument, the point geometry.
+     * options - {Object} 
+     */
+    initialize: function(control, callbacks, options) {
+        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+        var callbacks = {
+            "down": this.startBox, 
+            "move": this.moveBox, 
+            "out":  this.removeBox,
+            "up":   this.endBox
+        };
+        this.dragHandler = new OpenLayers.Handler.Drag(
+                                this, callbacks, {keyMask: this.keyMask});
+    },
+
+    /**
+     * Method: setMap
+     */
+    setMap: function (map) {
+        OpenLayers.Handler.prototype.setMap.apply(this, arguments);
+        if (this.dragHandler) {
+            this.dragHandler.setMap(map);
+        }
+    },
+
+    /**
+    * Method: startBox
+    *
+    * Parameters:
+    * evt - {Event} 
+    */
+    startBox: function (xy) {
+        this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+                                                 this.dragHandler.start,
+                                                 null,
+                                                 null,
+                                                 "absolute",
+                                                 "2px solid red");
+        this.zoomBox.style.backgroundColor = "white";
+        this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
+        this.zoomBox.style.opacity = "0.50";
+        this.zoomBox.style.fontSize = "1px";
+        this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+        this.map.viewPortDiv.appendChild(this.zoomBox);
+
+        // TBD: use CSS classes instead
+        this.map.div.style.cursor = "crosshair";
+    },
+
+    /**
+    * Method: moveBox
+    */
+    moveBox: function (xy) {
+        var deltaX = Math.abs(this.dragHandler.start.x - xy.x);
+        var deltaY = Math.abs(this.dragHandler.start.y - xy.y);
+        this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+        this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+        if (xy.x < this.dragHandler.start.x) {
+            this.zoomBox.style.left = xy.x+"px";
+        }
+        if (xy.y < this.dragHandler.start.y) {
+            this.zoomBox.style.top = xy.y+"px";
+        }
+    },
+
+    /**
+    * Method: endBox
+    */
+    endBox: function(end) {
+        var result;
+        if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||    
+            Math.abs(this.dragHandler.start.y - end.y) > 5) {   
+            var start = this.dragHandler.start;
+            var top = Math.min(start.y, end.y);
+            var bottom = Math.max(start.y, end.y);
+            var left = Math.min(start.x, end.x);
+            var right = Math.max(start.x, end.x);
+            result = new OpenLayers.Bounds(left, bottom, right, top);
+        } else {
+            result = this.dragHandler.start.clone(); // i.e. OL.Pixel
+        } 
+        this.removeBox();
+
+        // TBD: use CSS classes instead
+        this.map.div.style.cursor = "";
+
+        this.callback("done", [result]);
+    },
+
+    /**
+     * Method: removeBox
+     * Remove the zoombox from the screen and nullify our reference to it.
+     */
+    removeBox: function() {
+        this.map.viewPortDiv.removeChild(this.zoomBox);
+        this.zoomBox = null;
+    },
+
+    /**
+     * Method: activate
+     */
+    activate: function () {
+        if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            this.dragHandler.activate();
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    /**
+     * Method: deactivate
+     */
+    deactivate: function () {
+        if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+            this.dragHandler.deactivate();
+            return true;
+        } else {
+            return false;
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Handler.Box"
+});
+/* ======================================================================
+    OpenLayers/Layer/HTTPRequest.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ * 
+ * Class: OpenLayers.Layer.HTTPRequest
+ * 
+ * Inherits from: 
+ *  - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
+
+    /** 
+     * Constant: URL_HASH_FACTOR
+     * {Float} Used to hash URL param strings for multi-WMS server selection.
+     *         Set to the Golden Ratio per Knuth's recommendation.
+     */
+    URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
+
+    /** 
+     * Property: url
+     * {Array(String) or String} This is either an array of url strings or 
+     *                           a single url string. 
+     */
+    url: null,
+
+    /** 
+     * Property: params
+     * {Object} Hashtable of key/value parameters
+     */
+    params: null,
+    
+    /** 
+     * APIProperty: reproject
+     * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+     * for information on the replacement for this functionality. 
+     * {Boolean} Whether layer should reproject itself based on base layer 
+     *           locations. This allows reprojection onto commercial layers. 
+     *           Default is false: Most layers can't reproject, but layers 
+     *           which can create non-square geographic pixels can, like WMS.
+     *           
+     */
+    reproject: false,
+
+    /**
+     * Constructor: OpenLayers.Layer.HTTPRequest
+     * 
+     * Parameters:
+     * name - {String}
+     * url - {Array(String) or String}
+     * params - {Object}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = arguments;
+        newArguments = [name, options];
+        OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
+        this.url = url;
+        this.params = OpenLayers.Util.extend( {}, params);
+    },
+
+    /**
+     * APIMethod: destroy
+     */
+    destroy: function() {
+        this.url = null;
+        this.params = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments); 
+    },
+    
+    /**
+     * APIMethod: clone
+     * 
+     * Parameters:
+     * obj - {Object}
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this 
+     *                                  <OpenLayers.Layer.HTTPRequest>
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.HTTPRequest(this.name,
+                                                   this.url,
+                                                   this.params,
+                                                   this.options);
+        }
+        
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+        
+        return obj;
+    },
+
+    /** 
+     * APIMethod: setUrl
+     * 
+     * Parameters:
+     * newUrl - {String}
+     */
+    setUrl: function(newUrl) {
+        this.url = newUrl;
+    },
+
+    /**
+     * APIMethod: mergeNewParams
+     * 
+     * Parameters:
+     * newParams - {Object}
+     */
+    mergeNewParams:function(newParams) {
+        this.params = OpenLayers.Util.extend(this.params, newParams);
+        this.redraw();
+    },
+    
+    /**
+     * Method: selectUrl
+     * selectUrl() implements the standard floating-point multiplicative
+     *     hash function described by Knuth, and hashes the contents of the 
+     *     given param string into a float between 0 and 1. This float is then
+     *     scaled to the size of the provided urls array, and used to select
+     *     a URL.
+     *
+     * Parameters:
+     * paramString - {String}
+     * urls - {Array(String)}
+     * 
+     * Returns:
+     * {String} An entry from the urls array, deterministically selected based
+     *          on the paramString.
+     */
+    selectUrl: function(paramString, urls) {
+        var product = 1;
+        for (var i = 0; i < paramString.length; i++) { 
+            product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR; 
+            product -= Math.floor(product); 
+        }
+        return urls[Math.floor(product * urls.length)];
+    },
+
+    /** 
+     * Method: getFullRequestString
+     * Combine url with layer's params and these newParams. 
+     *   
+     *    does checking on the serverPath variable, allowing for cases when it 
+     *     is supplied with trailing ? or &, as well as cases where not. 
+     *
+     *    return in formatted string like this:
+     *        "server?key1=value1&key2=value2&key3=value3"
+     * 
+     * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
+     *
+     * Parameters:
+     * newParams - {Object}
+     * altUrl - {String} Use this as the url instead of the layer's url
+     *   
+     * Returns: 
+     * {String}
+     */
+    getFullRequestString:function(newParams, altUrl) {
+
+        // if not altUrl passed in, use layer's url
+        var url = altUrl || this.url;
+        
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // if url is not a string, it should be an array of strings, 
+        // in which case we will deterministically select one of them in 
+        // order to evenly distribute requests to different urls.
+        //
+        if (url instanceof Array) {
+            url = this.selectUrl(paramsString, url);
+        }   
+ 
+        // ignore parameters that are already in the url search string
+        var urlParams = 
+            OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // requestString always starts with url
+        var requestString = url;        
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have 
+                    // paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
+});
+/* ======================================================================
+    OpenLayers/Layer/Markers.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ * 
+ * Class: OpenLayers.Layer.Markers
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer> 
+ */
+OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
+    
+    /** 
+     * APIProperty: isBaseLayer 
+     * {Boolean} Markers layer is never a base layer.  
+     */
+    isBaseLayer: false,
+    
+    /** 
+     * Property: markers 
+     * Array({<OpenLayers.Marker>}) internal marker list 
+     */
+    markers: null,
+
+
+    /** 
+     * Property: drawn 
+     * {Boolean} internal state of drawing. This is a workaround for the fact
+     * that the map does not call moveTo with a zoomChanged when the map is
+     * first starting up. This lets us catch the case where we have *never*
+     * drawn the layer, and draw it even if the zoom hasn't changed.
+     */
+    drawn: false,
+    
+    /**
+     * Constructor: OpenLayers.Layer.Markers 
+     * Create a Markers layer.
+     *
+     * Parameters:
+     * name - {String} 
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+        this.markers = [];
+    },
+    
+    /**
+     * APIMethod: destroy 
+     */
+    destroy: function() {
+        this.clearMarkers();
+        this.markers = null;
+        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+    },
+
+    
+    /** 
+     * Method: moveTo
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} 
+     * zoomChanged - {Boolean} 
+     * dragging - {Boolean} 
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+        if (zoomChanged || !this.drawn) {
+            for(i=0; i < this.markers.length; i++) {
+                this.drawMarker(this.markers[i]);
+            }
+            this.drawn = true;
+        }
+    },
+
+    /**
+     * APIMethod: addMarker
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    addMarker: function(marker) {
+        this.markers.push(marker);
+        if (this.map && this.map.getExtent()) {
+            marker.map = this.map;
+            this.drawMarker(marker);
+        }
+    },
+
+    /**
+     * APIMethod: removeMarker
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    removeMarker: function(marker) {
+        OpenLayers.Util.removeItem(this.markers, marker);
+        if ((marker.icon != null) && (marker.icon.imageDiv != null) &&
+            (marker.icon.imageDiv.parentNode == this.div) ) {
+            this.div.removeChild(marker.icon.imageDiv);    
+            marker.drawn = false;
+        }
+    },
+
+    /**
+     * Method: clearMarkers
+     * This method removes all markers from a layer. The markers are not
+     * destroyed by this function, but are removed from the list of markers.
+     */
+    clearMarkers: function() {
+        if (this.markers != null) {
+            while(this.markers.length > 0) {
+                this.removeMarker(this.markers[0]);
+            }
+        }
+    },
+
+    /** 
+     * Method: drawMarker
+     * Calculate the pixel location for the marker, create it, and 
+     *    add it to the layer's div
+     *
+     * Parameters:
+     * marker - {<OpenLayers.Marker>} 
+     */
+    drawMarker: function(marker) {
+        var px = this.map.getLayerPxFromLonLat(marker.lonlat);
+        if (px == null) {
+            marker.display(false);
+        } else {
+            var markerImg = marker.draw(px);
+            if (!marker.drawn) {
+                this.div.appendChild(markerImg);
+                marker.drawn = true;
+            }
+        }
+    },
+    
+    /** 
+     * APIMethod: getDataExtent
+     * Calculates the max extent which includes all of the markers.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>}
+     */
+    getDataExtent: function () {
+        var maxExtent = null;
+        
+        if ( this.markers && (this.markers.length > 0)) {
+            var maxExtent = new OpenLayers.Bounds();
+            for(var i=0; i < this.markers.length; i++) {
+                var marker = this.markers[i];
+                maxExtent.extend(marker.lonlat);
+            }
+        }
+
+        return maxExtent;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.Markers"
+});
+/* ======================================================================
+    OpenLayers/Control/ZoomBox.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Box.js
+ *
+ * Class: OpenLayers.Control.ZoomBox
+ *
+ * Inherits from:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
+    /**
+     * Property: type
+     * {OpenLayers.Control.TYPE}
+     */
+    type: OpenLayers.Control.TYPE_TOOL,
+
+    /**
+     * Method: draw
+     */    
+    draw: function() {
+        this.handler = new OpenLayers.Handler.Box( this,
+                            {done: this.zoomBox}, {keyMask: this.keyMask} );
+    },
+
+    /**
+     * Method: zoomBox
+     *
+     * Parameters:
+     * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
+     */
+    zoomBox: function (position) {
+        if (position instanceof OpenLayers.Bounds) {
+            var minXY = this.map.getLonLatFromPixel(
+                            new OpenLayers.Pixel(position.left, position.bottom));
+            var maxXY = this.map.getLonLatFromPixel(
+                            new OpenLayers.Pixel(position.right, position.top));
+            var bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
+                                               maxXY.lon, maxXY.lat);
+            this.map.zoomToExtent(bounds);
+        } else { // it's a pixel
+            this.map.setCenter(this.map.getLonLatFromPixel(position),
+                               this.map.getZoom() + 1);
+        }
+    },
+
+    CLASS_NAME: "OpenLayers.Control.ZoomBox"
+});
+/* ======================================================================
+    OpenLayers/Layer/Grid.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/HTTPRequest.js
+ * 
+ * Class: OpenLayers.Layer.Grid
+ * Base class for layers that use a lattice of tiles.  Create a new grid
+ * layer with the <OpenLayers.Layer.Grid> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.HTTPRequest>
+ */
+OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+    
+    /**
+     * APIProperty: tileSize
+     * {<OpenLayers.Size>}
+     */
+    tileSize: null,
+    
+    /**
+     * Property: grid
+     * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is 
+     *     an array of tiles.
+     */
+    grid: null,
+
+    /**
+     * APIProperty: singleTile
+     * {Boolean} Moves the layer into single-tile mode, meaning that one tile 
+     *     will be loaded. The tile's size will be determined by the 'ratio'
+     *     property. When the tile is dragged such that it does not cover the 
+     *     entire viewport, it is reloaded.
+     */
+    singleTile: false,
+
+    /** APIProperty: ratio
+     *  {Float} Used only when in single-tile mode, this specifies the 
+     *          ratio of the size of the single tile to the size of the map.
+     */
+    ratio: 1.5,
+
+    /**
+     * APIProperty: buffer
+     * {Integer} Used only when in gridded mode, this specifies the number of 
+     *           extra rows and colums of tiles on each side which will
+     *           surround the minimum grid tiles to cover the map.
+     */
+    buffer: 2,
+
+    /**
+     * APIProperty: numLoadingTiles
+     * {Integer} How many tiles are still loading?
+     */
+    numLoadingTiles: 0,
+
+    /**
+     * Constructor: OpenLayers.Layer.Grid
+     * Create a new grid layer
+     *
+     * Parameters:
+     * name - {String}
+     * url - {String}
+     * params - {Object}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, 
+                                                                arguments);
+        
+        //grid layers will trigger 'tileloaded' when each new tile is 
+        // loaded, as a means of progress update to listeners.
+        // listeners can access 'numLoadingTiles' if they wish to keep track
+        // of the loading progress
+        //
+        this.events.addEventType("tileloaded");
+
+        this.grid = [];
+    },
+
+    /**
+     * APIMethod: destroy
+     * Deconstruct the layer and clear the grid.
+     */
+    destroy: function() {
+        this.clearGrid();
+        this.grid = null;
+        this.tileSize = null;
+        OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); 
+    },
+
+    /**
+     * Method: clearGrid
+     * Go through and remove all tiles from the grid, calling
+     *    destroy() on each of them to kill circular references
+     */
+    clearGrid:function() {
+        if (this.grid) {
+            for(var iRow=0; iRow < this.grid.length; iRow++) {
+                var row = this.grid[iRow];
+                for(var iCol=0; iCol < row.length; iCol++) {
+                    var tile = row[iCol];
+                    this.removeTileMonitoringHooks(tile);
+                    tile.destroy();
+                }
+            }
+            this.grid = [];
+        }
+    },
+
+    /**
+     * APIMethod: clone
+     * Create a clone of this layer
+     *
+     * Parameters:
+     * obj - {Object} Is this ever used?
+     * 
+     * Returns:
+     * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.Grid(this.name,
+                                            this.url,
+                                            this.params,
+                                            this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+        if (this.tileSize != null) {
+            obj.tileSize = this.tileSize.clone();
+        }
+        
+        // we do not want to copy reference to grid, so we make a new array
+        obj.grid = [];
+
+        return obj;
+    },    
+
+    /**
+     * Method: moveTo
+     * This function is called whenever the map is moved. All the moving
+     * of actual 'tiles' is done by the map, but moveTo's role is to accept
+     * a bounds and make sure the data that that bounds requires is pre-loaded.
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * zoomChanged - {Boolean}
+     * dragging - {Boolean}
+     */
+    moveTo:function(bounds, zoomChanged, dragging) {
+        OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
+        
+        bounds = bounds || this.map.getExtent();
+
+        if (bounds != null) {
+             
+            // if grid is empty or zoom has changed, we *must* re-tile
+            var forceReTile = !this.grid.length || zoomChanged;
+
+            // total bounds of the tiles
+            var tilesBounds = this.getTilesBounds();            
+      
+            if (this.singleTile) {
+                
+                // We want to redraw whenever even the slightest part of the 
+                //  current bounds is not contained by our tile.
+                //  (thus, we do not specify partial -- its default is false)
+                if ( forceReTile || 
+                     (!dragging && !tilesBounds.containsBounds(bounds))) {
+                    this.initSingleTile(bounds);
+                }
+            } else {
+             
+                // if the bounds have changed such that they are not even 
+                //  *partially* contained by our tiles (IE user has 
+                //  programmatically panned to the other side of the earth) 
+                //  then we want to reTile (thus, partial true).  
+                //
+                if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
+                    this.initGriddedTiles(bounds);
+                } else {
+                    //we might have to shift our buffer tiles
+                    this.moveGriddedTiles(bounds);
+                }
+            }
+        }
+    },
+    
+    /**
+     * APIMethod: setTileSize
+     * Check if we are in singleTile mode and if so, set the size as a ratio
+     *     of the map size (as specified by the layer's 'ratio' property).
+     * 
+     * Parameters:
+     * size - {<OpenLayers.Size>}
+     */
+    setTileSize: function(size) { 
+        if (this.singleTile) {
+            var size = this.map.getSize().clone();
+            size.h = parseInt(size.h * this.ratio);
+            size.w = parseInt(size.w * this.ratio);
+        } 
+        OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+    },
+        
+    /**
+     * Method: getGridBounds
+     * Deprecated. This function will be removed in 3.0. Please use 
+     *     getTilesBounds() instead.
+     * 
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+     * currently loaded tiles (including those partially or not at all seen 
+     * onscreen)
+     */
+    getGridBounds: function() {
+        var msg = "The getGridBounds() function is deprecated. It will be " +
+                  "removed in 3.0. Please use getTilesBounds() instead.";
+        OpenLayers.Console.warn(msg);
+        return this.getTilesBounds();
+    },
+
+    /**
+     * APIMethod: getTilesBounds
+     * Return the bounds of the tile grid.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+     *     currently loaded tiles (including those partially or not at all seen 
+     *     onscreen).
+     */
+    getTilesBounds: function() {    
+        var bounds = null; 
+        
+        if (this.grid.length) {
+            var bottom = this.grid.length - 1;
+            var bottomLeftTile = this.grid[bottom][0];
+    
+            var right = this.grid[0].length - 1; 
+            var topRightTile = this.grid[0][right];
+    
+            bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left, 
+                                           bottomLeftTile.bounds.bottom,
+                                           topRightTile.bounds.right, 
+                                           topRightTile.bounds.top);
+            
+        }   
+        return bounds;
+    },
+
+    /**
+     * Method: initSingleTile
+     * 
+     * Parameters: 
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    initSingleTile: function(bounds) {
+
+        //determine new tile bounds
+        var center = bounds.getCenterLonLat();
+        var tileWidth = bounds.getWidth() * this.ratio;
+        var tileHeight = bounds.getHeight() * this.ratio;
+                                       
+        var tileBounds = 
+            new OpenLayers.Bounds(center.lon - (tileWidth/2),
+                                  center.lat - (tileHeight/2),
+                                  center.lon + (tileWidth/2),
+                                  center.lat + (tileHeight/2));
+  
+        var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+        var px = this.map.getLayerPxFromLonLat(ul);
+
+        if (!this.grid.length) {
+            this.grid[0] = [];
+        }
+
+        var tile = this.grid[0][0];
+        if (!tile) {
+            tile = this.addTile(tileBounds, px);
+            
+            this.addTileMonitoringHooks(tile);
+            tile.draw();
+            this.grid[0][0] = tile;
+        } else {
+            tile.moveTo(tileBounds, px);
+        }           
+        
+        //remove all but our single tile
+        this.removeExcessTiles(1,1);
+    },
+
+    /**
+     * Method: initGriddedTiles
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    initGriddedTiles:function(bounds) {
+        
+        // work out mininum number of rows and columns; this is the number of
+        // tiles required to cover the viewport plus at least one for panning
+
+        var viewSize = this.map.getSize();
+        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 
+                      Math.max(1, 2 * this.buffer);
+        var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
+                      Math.max(1, 2 * this.buffer);
+        
+        var extent = this.map.getMaxExtent();
+        var resolution = this.map.getResolution();
+        var tilelon = resolution * this.tileSize.w;
+        var tilelat = resolution * this.tileSize.h;
+        
+        var offsetlon = bounds.left - extent.left;
+        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+        var tilecolremain = offsetlon/tilelon - tilecol;
+        var tileoffsetx = -tilecolremain * this.tileSize.w;
+        var tileoffsetlon = extent.left + tilecol * tilelon;
+        
+        var offsetlat = bounds.top - (extent.bottom + tilelat);  
+        var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+        var tilerowremain = tilerow - offsetlat/tilelat;
+        var tileoffsety = -tilerowremain * this.tileSize.h;
+        var tileoffsetlat = extent.bottom + tilerow * tilelat;
+        
+        tileoffsetx = Math.round(tileoffsetx); // heaven help us
+        tileoffsety = Math.round(tileoffsety);
+
+        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+        var startX = tileoffsetx; 
+        var startLon = tileoffsetlon;
+
+        var rowidx = 0;
+    
+        do {
+            var row = this.grid[rowidx++];
+            if (!row) {
+                row = [];
+                this.grid.push(row);
+            }
+
+            tileoffsetlon = startLon;
+            tileoffsetx = startX;
+            var colidx = 0;
+ 
+            do {
+                var tileBounds = 
+                    new OpenLayers.Bounds(tileoffsetlon, 
+                                          tileoffsetlat, 
+                                          tileoffsetlon + tilelon,
+                                          tileoffsetlat + tilelat);
+
+                var x = tileoffsetx;
+                x -= parseInt(this.map.layerContainerDiv.style.left);
+
+                var y = tileoffsety;
+                y -= parseInt(this.map.layerContainerDiv.style.top);
+
+                var px = new OpenLayers.Pixel(x, y);
+                var tile = row[colidx++];
+                if (!tile) {
+                    tile = this.addTile(tileBounds, px);
+                    this.addTileMonitoringHooks(tile);
+                    row.push(tile);
+                } else {
+                    tile.moveTo(tileBounds, px, false);
+                }
+     
+                tileoffsetlon += tilelon;       
+                tileoffsetx += this.tileSize.w;
+            } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+                     || colidx < minCols)  
+             
+            tileoffsetlat -= tilelat;
+            tileoffsety += this.tileSize.h;
+        } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+                || rowidx < minRows)
+        
+        //shave off exceess rows and colums
+        this.removeExcessTiles(rowidx, colidx);
+
+        //now actually draw the tiles
+        this.spiralTileLoad();
+    },
+    
+    /**
+     * Method: spiralTileLoad
+     *   Starts at the top right corner of the grid and proceeds in a spiral 
+     *    towards the center, adding tiles one at a time to the beginning of a 
+     *    queue. 
+     * 
+     *   Once all the grid's tiles have been added to the queue, we go back 
+     *    and iterate through the queue (thus reversing the spiral order from 
+     *    outside-in to inside-out), calling draw() on each tile. 
+     */
+    spiralTileLoad: function() {
+        var tileQueue = [];
+ 
+        var directions = ["right", "down", "left", "up"];
+
+        var iRow = 0;
+        var iCell = -1;
+        var direction = OpenLayers.Util.indexOf(directions, "right");
+        var directionsTried = 0;
+        
+        while( directionsTried < directions.length) {
+
+            var testRow = iRow;
+            var testCell = iCell;
+
+            switch (directions[direction]) {
+                case "right":
+                    testCell++;
+                    break;
+                case "down":
+                    testRow++;
+                    break;
+                case "left":
+                    testCell--;
+                    break;
+                case "up":
+                    testRow--;
+                    break;
+            } 
+    
+            // if the test grid coordinates are within the bounds of the 
+            //  grid, get a reference to the tile.
+            var tile = null;
+            if ((testRow < this.grid.length) && (testRow >= 0) &&
+                (testCell < this.grid[0].length) && (testCell >= 0)) {
+                tile = this.grid[testRow][testCell];
+            }
+            
+            if ((tile != null) && (!tile.queued)) {
+                //add tile to beginning of queue, mark it as queued.
+                tileQueue.unshift(tile);
+                tile.queued = true;
+                
+                //restart the directions counter and take on the new coords
+                directionsTried = 0;
+                iRow = testRow;
+                iCell = testCell;
+            } else {
+                //need to try to load a tile in a different direction
+                direction = (direction + 1) % 4;
+                directionsTried++;
+            }
+        } 
+        
+        // now we go through and draw the tiles in forward order
+        for(var i=0; i < tileQueue.length; i++) {
+            var tile = tileQueue[i];
+            tile.draw();
+            //mark tile as unqueued for the next time (since tiles are reused)
+            tile.queued = false;       
+        }
+    },
+
+    /**
+     * APIMethod: addTile
+     * Gives subclasses of Grid the opportunity to create an 
+     * OpenLayer.Tile of their choosing. The implementer should initialize 
+     * the new tile and take whatever steps necessary to display it.
+     *
+     * Parameters
+     * bounds - {<OpenLayers.Bounds>}
+     *
+     * Returns:
+     * {<OpenLayers.Tile>} The added OpenLayers.Tile
+     */
+    addTile:function(bounds, position) {
+        // Should be implemented by subclasses
+    },
+    
+    /** 
+     * Method: addTileMonitoringHooks
+     * This function takes a tile as input and adds the appropriate hooks to 
+     *     the tile so that the layer can keep track of the loading tiles.
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    addTileMonitoringHooks: function(tile) {
+        
+        tile.onLoadStart = function() {
+            //if that was first tile then trigger a 'loadstart' on the layer
+            if (this.numLoadingTiles == 0) {
+                this.events.triggerEvent("loadstart");
+            }
+            this.numLoadingTiles++;
+        };
+        tile.events.register("loadstart", this, tile.onLoadStart);
+      
+        tile.onLoadEnd = function() {
+            this.numLoadingTiles--;
+            this.events.triggerEvent("tileloaded");
+            //if that was the last tile, then trigger a 'loadend' on the layer
+            if (this.numLoadingTiles == 0) {
+                this.events.triggerEvent("loadend");
+            }
+        };
+        tile.events.register("loadend", this, tile.onLoadEnd);
+    },
+
+    /** 
+     * Method: removeTileMonitoringHooks
+     * This function takes a tile as input and removes the tile hooks 
+     *     that were added in addTileMonitoringHooks()
+     * 
+     * Parameters: 
+     * tile - {<OpenLayers.Tile>}
+     */
+    removeTileMonitoringHooks: function(tile) {
+        tile.events.unregister("loadstart", this, tile.onLoadStart);
+        tile.events.unregister("loadend", this, tile.onLoadEnd);
+    },
+    
+    /**
+     * Method: moveGriddedTiles
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    moveGriddedTiles: function(bounds) {
+        var buffer = this.buffer || 1;
+        while (true) {
+            var tlLayer = this.grid[0][0].position;
+            var tlViewPort = 
+                this.map.getViewPortPxFromLayerPx(tlLayer);
+            if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
+                this.shiftColumn(true);
+            } else if (tlViewPort.x < -this.tileSize.w * buffer) {
+                this.shiftColumn(false);
+            } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
+                this.shiftRow(true);
+            } else if (tlViewPort.y < -this.tileSize.h * buffer) {
+                this.shiftRow(false);
+            } else {
+                break;
+            }
+        };
+    },
+
+    /**
+     * Method: shiftRow
+     * Shifty grid work
+     *
+     * Parameters:
+     * prepend - {Boolean} if true, prepend to beginning.
+     *                          if false, then append to end
+     */
+    shiftRow:function(prepend) {
+        var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
+        var modelRow = this.grid[modelRowIndex];
+
+        var resolution = this.map.getResolution();
+        var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
+        var deltaLat = resolution * -deltaY;
+
+        var row = (prepend) ? this.grid.pop() : this.grid.shift();
+
+        for (var i=0; i < modelRow.length; i++) {
+            var modelTile = modelRow[i];
+            var bounds = modelTile.bounds.clone();
+            var position = modelTile.position.clone();
+            bounds.bottom = bounds.bottom + deltaLat;
+            bounds.top = bounds.top + deltaLat;
+            position.y = position.y + deltaY;
+            row[i].moveTo(bounds, position);
+        }
+
+        if (prepend) {
+            this.grid.unshift(row);
+        } else {
+            this.grid.push(row);
+        }
+    },
+
+    /**
+     * Method: shiftColumn
+     * Shift grid work in the other dimension
+     *
+     * Parameters:
+     * prepend - {Boolean} if true, prepend to beginning.
+     *                          if false, then append to end
+     */
+    shiftColumn: function(prepend) {
+        var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
+        var resolution = this.map.getResolution();
+        var deltaLon = resolution * deltaX;
+
+        for (var i=0; i<this.grid.length; i++) {
+            var row = this.grid[i];
+            var modelTileIndex = (prepend) ? 0 : (row.length - 1);
+            var modelTile = row[modelTileIndex];
+            
+            var bounds = modelTile.bounds.clone();
+            var position = modelTile.position.clone();
+            bounds.left = bounds.left + deltaLon;
+            bounds.right = bounds.right + deltaLon;
+            position.x = position.x + deltaX;
+
+            var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
+            tile.moveTo(bounds, position);
+            if (prepend) {
+                this.grid[i].unshift(tile);
+            } else {
+                this.grid[i].push(tile);
+            }
+        }
+    },
+    
+    /**
+     * Method: removeExcessTiles
+     * When the size of the map or the buffer changes, we may need to
+     *     remove some excess rows and columns.
+     * 
+     * Parameters:
+     * rows - {Integer} Maximum number of rows we want our grid to have.
+     * colums - {Integer} Maximum number of columns we want our grid to have.
+     */
+    removeExcessTiles: function(rows, columns) {
+        
+        // remove extra rows
+        while (this.grid.length > rows) {
+            var row = this.grid.pop();
+            for (var i=0, l=row.length; i<l; i++) {
+                var tile = row[i];
+                this.removeTileMonitoringHooks(tile);
+                tile.destroy();
+            }
+        }
+        
+        // remove extra columns
+        while (this.grid[0].length > columns) {
+            for (var i=0, l=this.grid.length; i<l; i++) {
+                var row = this.grid[i];
+                var tile = row.pop();
+                this.removeTileMonitoringHooks(tile);
+                tile.destroy();
+            }
+        }
+    },
+
+    /**
+     * Method: onMapResize
+     * For singleTile layers, this will replace the tile with the
+     * a new one with updated tileSize and extent.
+     */
+    onMapResize: function() {
+      if (this.singleTile) {
+        this.clearGrid();
+        this.setTileSize();
+        this.initSingleTile(this.map.getExtent());
+      }
+    },
+    
+    /**
+     * APIMethod: getTileBounds
+     * Returns The tile bounds for a layer given a pixel location.
+     *
+     * Parameters:
+     * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
+     *
+     * Returns:
+     * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+     */
+    getTileBounds: function(viewPortPx) {
+        var maxExtent = this.map.getMaxExtent();
+        var resolution = this.getResolution();
+        var tileMapWidth = resolution * this.tileSize.w;
+        var tileMapHeight = resolution * this.tileSize.h;
+        var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
+        var tileLeft = maxExtent.left + (tileMapWidth *
+                                         Math.floor((mapPoint.lon -
+                                                     maxExtent.left) /
+                                                    tileMapWidth));
+        var tileBottom = maxExtent.bottom + (tileMapHeight *
+                                             Math.floor((mapPoint.lat -
+                                                         maxExtent.bottom) /
+                                                        tileMapHeight));
+        return new OpenLayers.Bounds(tileLeft, tileBottom,
+                                     tileLeft + tileMapWidth,
+                                     tileBottom + tileMapHeight);
+    },
+    
+    CLASS_NAME: "OpenLayers.Layer.Grid"
+});
+/* ======================================================================
+    OpenLayers/Control/Navigation.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/ZoomBox.js
+ * @requires OpenLayers/Control/DragPan.js
+ * @requires OpenLayers/Handler/MouseWheel.js
+ * 
+ * Class: OpenLayers.Control.Navigation
+ * The navigation control handles map browsing with mouse events (dragging,
+ *     double-clicking, and scrolling the wheel).  Create a new navigation 
+ *     control with the <OpenLayers.Control.Navigation> control.  
+ * 
+ *     Note that this control is added to the map by default (if no controls 
+ *     array is sent in the options object to the <OpenLayers.Map> 
+ *     constructor).
+ * 
+ * Inherits:
+ *  - <OpenLayers.Control>
+ */
+OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
+
+    /** 
+     * Property: dragPan
+     * {<OpenLayers.Control.DragPan>} 
+     */
+    dragPan: null,
+
+    /** 
+     * Property: zoomBox
+     * {<OpenLayers.Control.ZoomBox>}
+     */
+    zoomBox: null,
+
+    /** 
+     * Property: wheelHandler
+     * {<OpenLayers.Handler.MouseWheel>}
+     */
+    wheelHandler: null,
+
+    /**
+     * Constructor: OpenLayers.Control.Navigation
+     * Create a new navigation control
+     * 
+     * Parameters:
+     * options - {Object} An optional object whose properties will be set on
+     *                    the control
+     */
+    initialize: function(options) {
+        OpenLayers.Control.prototype.initialize.apply(this, arguments);
+    },
+
+    /**
+     * Method: activate
+     */
+    activate: function() {
+        this.dragPan.activate();
+        this.wheelHandler.activate();
+        this.zoomBox.activate();
+        return OpenLayers.Control.prototype.activate.apply(this,arguments);
+    },
+
+    /**
+     * Method: deactivate
+     */
+    deactivate: function() {
+        this.zoomBox.deactivate();
+        this.dragPan.deactivate();
+        this.wheelHandler.deactivate();
+        return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
+    },
+    
+    /**
+     * Method: draw
+     */
+    draw: function() {
+        this.map.events.register( "dblclick", this, this.defaultDblClick );
+        this.dragPan = new OpenLayers.Control.DragPan({map: this.map});
+        this.zoomBox = new OpenLayers.Control.ZoomBox(
+                    {map: this.map, keyMask: OpenLayers.Handler.MOD_SHIFT});
+        this.dragPan.draw();
+        this.zoomBox.draw();
+        this.wheelHandler = new OpenLayers.Handler.MouseWheel(
+                                    this, {"up"  : this.wheelUp,
+                                           "down": this.wheelDown} );
+        this.activate();
+    },
+
+    /**
+     * Method: defaultDblClick 
+     * 
+     * Parameters:
+     * evt - {Event} 
+     */
+    defaultDblClick: function (evt) {
+        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
+        this.map.setCenter(newCenter, this.map.zoom + 1);
+        OpenLayers.Event.stop(evt);
+        return false;
+    },
+
+    /**
+     * Method: wheelChange  
+     *
+     * Parameters:
+     * evt - {Event}
+     */
+    wheelChange: function(evt, deltaZ) {
+        var newZoom = this.map.getZoom() + deltaZ;
+        if (!this.map.isValidZoomLevel(newZoom)) return;
+
+        var size    = this.map.getSize();
+        var deltaX  = size.w/2 - evt.xy.x;
+        var deltaY  = evt.xy.y - size.h/2;
+        var newRes  = this.map.baseLayer.resolutions[newZoom];
+        var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
+        var newCenter = new OpenLayers.LonLat(
+                            zoomPoint.lon + deltaX * newRes,
+                            zoomPoint.lat + deltaY * newRes );
+        this.map.setCenter( newCenter, newZoom );
+    },
+
+    /** 
+     * Method: wheelUp
+     * User spun scroll wheel up
+     * 
+     * Parameters:
+     * evt - {Event}
+     */
+    wheelUp: function(evt) {
+        this.wheelChange(evt, 1);
+    },
+
+    /** 
+     * Method: wheelDown
+     * User spun scroll wheel down
+     * 
+     * Parameters:
+     * evt - {Event}
+     */
+    wheelDown: function(evt) {
+        this.wheelChange(evt, -1);
+    },
+
+    CLASS_NAME: "OpenLayers.Control.Navigation"
+});
+/* ======================================================================
+    OpenLayers/Layer/MapGuide.js
+   ====================================================================== */
+
+/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Ajax.js
+ * @requires OpenLayers/Layer/Grid.js
+ *
+ * Class: OpenLayers.Layer.MapGuide
+ * Instances of OpenLayers.Layer.MapGuide are used to display
+ * data from a MapGuide OS instance.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /** 
+     * APIProperty: reproject
+     * {Boolean} Try to reproject this layer if it is used as an overlay.
+     *     Default is false.
+     **/
+    reproject: false,
+    
+    /** 
+     * APIProperty: isBaseLayer
+     * {Boolean} Treat this layer as a base layer.  Default is true.
+     **/
+    isBaseLayer: true,
+    
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    TILE_PARAMS: {
+                      operation: 'GETTILEIMAGE',
+                      version: '1.2.0'
+                     },
+
+    SINGLE_TILE_PARAMS: {
+                      operation: 'GETMAPIMAGE',
+                      format: 'PNG',
+                      version: '1.0.0'
+                     },
+
+    session: null,
+    mapName: null,
+    groupName: null,
+
+    /**
+    * @constructor
+    *
+    * @param {str} name
+    * @param {str} url
+    * @param {hash} params
+    * @param {Object} options
+    */
+    initialize: function(name, url, params, options) {
+        
+        var newArguments = new Array();
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+        // unless explicitly set in options, if the layer is transparent, 
+        // it will be an overlay
+        if (options == null || options.isBaseLayer == null) {
+            this.isBaseLayer = ((this.params.transparent != "true") && 
+                                (this.params.transparent != true));
+        }
+
+        if (arguments.length > 0) {
+          if (this.options.singleTile) {
+            this.session = params.session;
+            this.mapName = params.mapname;
+            OpenLayers.Util.applyDefaults(
+                           this.params,
+                           this.SINGLE_TILE_PARAMS
+                           );
+            if (!this.isBaseLayer) {
+              this.params.operation = "GETDYNAMICMAPOVERLAYIMAGE";
+            }
+          } else {
+            this.groupName = params.groupname;
+            OpenLayers.Util.applyDefaults(
+                           this.params,
+                           this.TILE_PARAMS
+                           );
+            this.setTileSize(new OpenLayers.Size(300,300)); //TBD: set this by options?
+          }
+        }
+    },
+
+    updateExtents: function(a) {
+      var center = this.map.getExtent().getCenterLonLat();
+      var mapSize = this.map.getCurrentSize();
+      var sParams = "operation=GETVISIBLEMAPEXTENT&version=1.0.0";
+      sParams += "&session="+this.session;
+      sParams += "&mapname="+this.mapName;
+      sParams += "&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;   
+      sParams += "&setdisplayheight="+mapSize.h*this.ratio;
+      sParams += "&setdisplaywidth="+mapSize.w*this.ratio;
+      sParams += "&setviewcenterx="+center.lon;
+      sParams += "&setviewcentery="+center.lat;
+      sParams += "&setviewscale="+this.map.getScale();
+      if (this.options.showLayers) sParams += "&showlayers="+this.options.showLayers;
+      if (this.options.hideLayers) sParams += "&hidelayers="+this.options.hideLayers;
+      if (this.options.showGroups) sParams += "&showgroups="+this.options.showGroups;
+      if (this.options.hideGroups) sParams += "&hidegroups="+this.options.hideGroups;
+      if (this.options.refreshLayers) sParams += "&refreshlayers="+this.options.refreshLayers;
+      sParams += "&ts="+(new Date()).getTime();
+      // add in hidden/visible layers here?
+      new OpenLayers.Ajax.Request(this.url, 
+             {   parameters: sParams,
+                 onSuccess: this._getExtentSuccess, 
+                 onFailure: this._getExtentFailure,
+                 //requestHeaders: ['Authorization', 'Basic QW5vbnltb3VzOg=='], //TBD anon user base64 encoded
+                 asynchronous: false         //must be synchronous call to return control here
+              });
+
+    },
+    
+    _getExtentSuccess: function(transport) {
+      //really this is a no-op, result is thrown away
+      var temp = transport.responseXML;
+    },
+    
+    _getExtentFailure: function(r) {
+      //no-op
+    },
+    
+    
+	/**
+    * @param {Object} obj
+    *
+    * @returns A clone of this OpenLayers.Layer.MapGuide
+    * @type OpenLayers.Layer.MapGuide
+    */
+    clone: function (obj) {
+      if (obj == null) {
+            obj = new OpenLayers.Layer.MapGuide(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+      //get all additions from superclasses
+      obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+      // copy/set any non-init, non-simple values here
+
+      return obj;
+    },
+
+    /**
+    * addTile creates a tile, initializes it (via 'draw' in this case), and
+    * adds it to the layer div.
+    *
+    * @param {OpenLayers.Bounds} bounds
+    *
+    * @returns The added OpenLayers.Tile.Image
+    * @type OpenLayers.Tile.Image
+    */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, url, this.tileSize);
+    },
+
+     /**
+     * @param {OpenLayers.Bounds} bounds
+     * 
+     * @returns A string with the layer's url and parameters and also the 
+     *           passed-in bounds and appropriate tile size specified as 
+     *           parameters
+     * @type String
+     */
+    getURL: function (bounds) {
+        
+        var center = bounds.getCenterLonLat();
+        var mapSize = this.map.getCurrentSize();
+
+        if (this.options.singleTile) {
+          //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY
+          var params = {};
+
+          params.session = this.session;
+          params.mapname = this.mapName;
+          if (this.isBaseLayer) {
+            params.locale = "en";
+            params.setdisplaydpi = OpenLayers.DOTS_PER_INCH;   
+            params.setdisplayheight = mapSize.h*this.ratio;
+            params.setdisplaywidth = mapSize.w*this.ratio;
+            params.setviewcenterx = center.lon;
+            params.setviewcentery = center.lat;
+            params.setviewscale = this.map.getScale();
+            params.clip = "1";
+            if (this.options.showLayers) params.showlayers = this.options.showLayers;
+            if (this.options.hideLayers) params.hidelayers = this.options.hideLayers;
+            if (this.options.showGroups) params.showgroups = this.options.showGroups;
+            if (this.options.hideGroups) params.hidegroups = this.options.hideGroups;
+            if (this.options.refreshLayers) params.refreshlayers = this.options.refreshLayers;
+          } else {
+            this.updateExtents();
+          }
+          params.ts = (new Date()).getTime();
+
+          var url = this.getFullRequestString( params );
+
+        } else {
+
+          //tiled version
+          var currentRes = this.map.getResolution();
+          var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
+          colidx = Math.round(colidx/this.tileSize.w);
+          var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
+          rowidx = Math.round(rowidx/this.tileSize.h);
+
+          var url = this.getFullRequestString(
+                       {
+                           tilecol: colidx,
+                           tilerow: rowidx,
+                           scaleindex: this.resolutions.length-this.map.zoom-1
+                        });
+         }
+        
+        return url;
+    },
+
+    /** 
+     * getFullRequestString on MapGuide layers is special, because we 
+     * do a regular expression replace on ',' in parameters to '+'.
+     * This is why it is subclassed here.
+     *
+     * @param {Object} newParams Parameters to add to the default parameters
+     *                           for the layer.
+     * @param {String} altUrl    Alternative base URL to use.
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        
+    
+        // use layer's url unless altUrl passed in
+        var url = (altUrl == null) ? this.url : altUrl;
+        
+        // if url is not a string, it should be an array of strings, 
+        //  in which case we will randomly select one of them in order
+        //  to evenly distribute requests to different urls.
+        if (typeof url == "object") {
+            url = url[Math.floor(Math.random()*url.length)];
+        }   
+        // requestString always starts with url
+        var requestString = url;        
+
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        // ignore parameters that are already in the url search string
+        var urlParams = OpenLayers.Util.upperCaseObject(
+                            OpenLayers.Util.getArgs(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        /* MapGuide needs '+' seperating things like bounds/height/width.
+           Since typically this is URL encoded, we use a slight hack: we
+           depend on the list-like functionality of getParameterString to
+           leave ',' only in the case of list items (since otherwise it is
+           encoded) then do a regular expression replace on the , characters
+           to '+' */
+        paramsString = paramsString.replace(/,/g, "+");
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+    /**
+     * Method: initGriddedTiles
+     * 
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     */
+    initGriddedTiles:function(bounds) {
+       
+        // work out mininum number of rows and columns; this is the number of
+        // tiles required to cover the viewport plus one for panning
+        var viewSize = this.map.getSize();
+        var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 1;
+        var minCols = Math.ceil(viewSize.w/this.tileSize.w) + 1;
+        
+        var extent = this.map.getMaxExtent();
+        var resolution = this.map.getResolution();
+        var tilelon = resolution * this.tileSize.w;
+        var tilelat = resolution * this.tileSize.h;
+        
+        var offsetlon = bounds.left - extent.left;
+        var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+        var tilecolremain = offsetlon/tilelon - tilecol;
+        var tileoffsetx = -tilecolremain * this.tileSize.w;
+        var tileoffsetlon = extent.left + tilecol * tilelon;
+        
+        //Original OL code
+        //var offsetlat = bounds.top - (extent.bottom + tilelat);  
+        //var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+        //var tilerowremain = tilerow - offsetlat/tilelat;
+        //var tileoffsety = -tilerowremain * this.tileSize.h;
+        //var tileoffsetlat = extent.bottom + tilerow * tilelat;
+
+        var offsetlat = extent.top - bounds.top + tilelat; 
+        var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
+        var tilerowremain = tilerow - offsetlat/tilelat;
+        var tileoffsety = tilerowremain * this.tileSize.h;
+        var tileoffsetlat = extent.top - tilelat*tilerow;
+        
+
+        tileoffsetx = Math.round(tileoffsetx); // heaven help us
+        tileoffsety = Math.round(tileoffsety);
+
+        this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+        var startX = tileoffsetx; 
+        var startLon = tileoffsetlon;
+
+        var rowidx = 0;
+    
+        do {
+            var row = this.grid[rowidx++];
+            if (!row) {
+                row = [];
+                this.grid.push(row);
+            }
+
+            tileoffsetlon = startLon;
+            tileoffsetx = startX;
+            var colidx = 0;
+ 
+            do {
+                var tileBounds = 
+                    new OpenLayers.Bounds(tileoffsetlon, 
+                                          tileoffsetlat, 
+                                          tileoffsetlon + tilelon,
+                                          tileoffsetlat + tilelat);
+
+                var x = tileoffsetx;
+                x -= parseInt(this.map.layerContainerDiv.style.left);
+
+                var y = tileoffsety;
+                //y -= parseInt(this.map.layerContainerDiv.style.top);
+
+                var px = new OpenLayers.Pixel(x, y);
+                var tile = row[colidx++];
+                if (!tile) {
+                    tile = this.addTile(tileBounds, px);
+                    this.addTileMonitoringHooks(tile);
+                    row.push(tile);
+                } else {
+                    tile.moveTo(tileBounds, px, false);
+                }
+     
+                tileoffsetlon += tilelon;       
+                tileoffsetx += this.tileSize.w;
+            } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+                     || colidx < minCols)  
+             
+            tileoffsetlat -= tilelat;
+            tileoffsety += this.tileSize.h;
+        } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+                || rowidx < minRows)
+        
+        //shave off exceess rows and colums
+        this.removeExcessTiles(rowidx, colidx);
+
+        //now actually draw the tiles
+        this.spiralTileLoad();
+    },
+    
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Layer.MapGuide"
+});
+/* ======================================================================
+    OpenLayers/Layer/MapServer.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ *
+ * Class: OpenLayers.Layer.MapServer
+ * Instances of OpenLayers.Layer.MapServer are used to display
+ * data from a MapServer CGI instance.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    DEFAULT_PARAMS: {
+        mode: "map",
+        map_imagetype: "png"
+    },
+
+    /**
+     * Constructor: OpenLayers.Layer.MapServer
+     * Create a new MapServer layer object
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the MapServer CGI
+     *       (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
+     * params - {Object} An object with key/value pairs representing the
+     *          GetMap query string parameters and parameter values.
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = [];
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+        if (arguments.length > 0) {
+            OpenLayers.Util.applyDefaults(
+                           this.params,
+                           this.DEFAULT_PARAMS
+                           );
+        }
+
+        // unless explicitly set in options, if the layer is transparent, 
+        // it will be an overlay
+        if (options == null || options.isBaseLayer == null) {
+            this.isBaseLayer = ((this.params.transparent != "true") && 
+                                (this.params.transparent != true));
+        }
+    },
+
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        if (obj == null) {
+            obj = new OpenLayers.Layer.MapServer(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },
+
+    /**
+     * Method: addTile
+     * Creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+    
+    /**
+     * Method: getURL
+     * Return a query string for this layer
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox 
+     *                                for the request
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also 
+     *          the passed-in bounds and appropriate tile size specified 
+     *          as parameters.
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        // Make a list, so that getFullRequestString uses literal "," 
+        var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
+
+        var imageSize = this.getImageSize(); 
+        
+        // make lists, so that literal ','s are used 
+        var url = this.getFullRequestString(
+                     {mapext:   extent,
+                      imgext:   extent,
+                      map_size: [imageSize.w, imageSize.h],
+                      imgx:     imageSize.w / 2,
+                      imgy:     imageSize.h / 2,
+                      imgxy:    [imageSize.w, imageSize.h]
+                      });
+        
+        return url;
+    },
+    
+    /** 
+     * Method: getFullRequestString
+     * combine the layer's url with its params and these newParams. 
+     *   
+     * Parameter:
+     * newParams - {Object} New parameters that should be added to the 
+     *                      request string.
+     * altUrl - {String} (optional) Replace the URL in the full request  
+     *                              string with the provided URL.
+     * 
+     * Returns: 
+     * {String} A string with the layer's url and parameters embedded in it.
+     */
+    getFullRequestString:function(newParams, altUrl) {
+        // use layer's url unless altUrl passed in
+        var url = (altUrl == null) ? this.url : altUrl;
+        
+        // if url is not a string, it should be an array of strings, 
+        //  in which case we will randomly select one of them in order
+        //  to evenly distribute requests to different urls.
+        if (typeof url == "object") {
+            url = url[Math.floor(Math.random()*url.length)];
+        }   
+        // requestString always starts with url
+        var requestString = url;        
+
+        // create a new params hashtable with all the layer params and the 
+        // new params together. then convert to string
+        var allParams = OpenLayers.Util.extend({}, this.params);
+        allParams = OpenLayers.Util.extend(allParams, newParams);
+        // ignore parameters that are already in the url search string
+        var urlParams = OpenLayers.Util.upperCaseObject(
+                            OpenLayers.Util.getParameters(url));
+        for(var key in allParams) {
+            if(key.toUpperCase() in urlParams) {
+                delete allParams[key];
+            }
+        }
+        var paramsString = OpenLayers.Util.getParameterString(allParams);
+        
+        // MapServer needs '+' seperating things like bounds/height/width.
+        //   Since typically this is URL encoded, we use a slight hack: we
+        //  depend on the list-like functionality of getParameterString to
+        //  leave ',' only in the case of list items (since otherwise it is
+        //  encoded) then do a regular expression replace on the , characters
+        //  to '+'
+        //
+        paramsString = paramsString.replace(/,/g, "+");
+        
+        if (paramsString != "") {
+            var lastServerChar = url.charAt(url.length - 1);
+            if ((lastServerChar == "&") || (lastServerChar == "?")) {
+                requestString += paramsString;
+            } else {
+                if (url.indexOf('?') == -1) {
+                    //serverPath has no ? -- add one
+                    requestString += '?' + paramsString;
+                } else {
+                    //serverPath contains ?, so must already have paramsString at the end
+                    requestString += '&' + paramsString;
+                }
+            }
+        }
+        return requestString;
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.MapServer"
+});
+/* ======================================================================
+    OpenLayers/Layer/WMS.js
+   ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ * 
+ * Class: OpenLayers.Layer.WMS
+ * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
+ *     Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
+ *     constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+    /**
+     * Constant: DEFAULT_PARAMS
+     * {Object} Hashtable of default parameter key/value pairs 
+     */
+    DEFAULT_PARAMS: { service: "WMS",
+                      version: "1.1.1",
+                      request: "GetMap",
+                      styles: "",
+                      exceptions: "application/vnd.ogc.se_inimage",
+                      format: "image/jpeg"
+                     },
+    
+    /**
+     * Property: reproject
+     * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+     * for information on the replacement for this functionality. 
+     * {Boolean} Try to reproject this layer if its coordinate reference system
+     *           is different than that of the base layer.  Default is true.  
+     *           Set this in the layer options.  Should be set to false in 
+     *           most cases.
+     */
+    reproject: false,
+ 
+    /**
+     * APIProperty: isBaseLayer
+     * {Boolean} Default is true for WMS layer
+     */
+    isBaseLayer: true,
+    
+    /**
+     * APIProperty: encodeBBOX
+     * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', 
+     * but some services want it that way. Default false.
+     */
+    encodeBBOX: false,
+ 
+    /**
+     * Constructor: OpenLayers.Layer.WMS
+     * Create a new WMS layer object
+     *
+     * Example:
+     * (code)
+     * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
+     *                                    "http://wms.jpl.nasa.gov/wms.cgi", 
+     *                                    {layers: "modis,global_mosaic"});
+     * (end)
+     *
+     * Parameters:
+     * name - {String} A name for the layer
+     * url - {String} Base url for the WMS
+     *                (e.g. http://wms.jpl.nasa.gov/wms.cgi)
+     * params - {Object} An object with key/value pairs representing the
+     *                   GetMap query string parameters and parameter values.
+     * options - {Ojbect} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, url, params, options) {
+        var newArguments = [];
+        //uppercase params
+        params = OpenLayers.Util.upperCaseObject(params);
+        newArguments.push(name, url, params, options);
+        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+        OpenLayers.Util.applyDefaults(
+                       this.params, 
+                       OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
+                       );
+
+
+        //layer is transparent        
+        if (this.params.TRANSPARENT && 
+            this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+            
+            // unless explicitly set in options, make layer an overlay
+            if ( (options == null) || (!options.isBaseLayer) ) {
+                this.isBaseLayer = false;
+            } 
+            
+            // jpegs can never be transparent, so intelligently switch the 
+            //  format, depending on teh browser's capabilities
+            if (this.params.FORMAT == "image/jpeg") {
+                this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
+                                                                 : "image/png";
+            }
+        }
+
+    },    
+
+    /**
+     * Method: destroy
+     * Destroy this layer
+     */
+    destroy: function() {
+        // for now, nothing special to do here. 
+        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
+    },
+
+    
+    /**
+     * Method: clone
+     * Create a clone of this layer
+     *
+     * Returns:
+     * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+     */
+    clone: function (obj) {
+        
+        if (obj == null) {
+            obj = new OpenLayers.Layer.WMS(this.name,
+                                           this.url,
+                                           this.params,
+                                           this.options);
+        }
+
+        //get all additions from superclasses
+        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+        // copy/set any non-init, non-simple values here
+
+        return obj;
+    },    
+    
+    /**
+     * Method: getURL
+     * Return a GetMap query string for this layer
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+     *                                request.
+     *
+     * Returns:
+     * {String} A string with the layer's url and parameters and also the
+     *          passed-in bounds and appropriate tile size specified as 
+     *          parameters.
+     */
+    getURL: function (bounds) {
+        bounds = this.adjustBounds(bounds);
+        
+        var imageSize = this.getImageSize(); 
+        return this.getFullRequestString(
+                     {BBOX: this.encodeBBOX ?  bounds.toBBOX() : bounds.toArray(),
+                      WIDTH:imageSize.w,
+                      HEIGHT:imageSize.h});
+    },
+
+    /**
+     * Method: addTile
+     * addTile creates a tile, initializes it, and adds it to the layer div. 
+     *
+     * Parameters:
+     * bounds - {<OpenLayers.Bounds>}
+     * 
+     * Returns:
+     * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+     */
+    addTile:function(bounds,position) {
+        return new OpenLayers.Tile.Image(this, position, bounds, 
+                                         null, this.tileSize);
+    },
+
+    /**
+     * APIMethod: mergeNewParams
+     * Catch changeParams and uppercase the new params to be merged in
+     *     before calling changeParams on the super class.
+     * 
+     *     Once params have been changed, we will need to re-init our tiles.
+     * 
+     * Parameters:
+     * newParams - {Object} Hashtable of new params to use
+     */
+    mergeNewParams:function(newParams) {
+        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
+        var newArguments = [upperParams];
+        OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
+                                                             newArguments);
+    },
+
+    /** 
+     * Method: getFullRequestString
+     * Combine the layer's url with its params and these newParams. 
+     *   
+     *     Add the SRS parameter from projection -- this is probably
+     *     more eloquently done via a setProjection() method, but this 
+     *     works for now and always.
+     *
+     * Parameters:
+     * newParams - {Object}
+     * 
+     * Returns:
+     * {String} 
+     */
+    getFullRequestString:function(newParams) {
+        var projection = this.map.getProjection();
+        this.params.SRS = (projection == "none") ? null : projection.getCode();
+
+        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+                                                    this, arguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.WMS"
+});


Property changes on: sandbox/aboudreault/lib/OpenLayers/OpenLayers.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -43,403 +43,410 @@
 *
 **/
 
-OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){var scriptLocation="";var scriptName=OpenLayers._scriptName;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptName.length==src.length)){scriptLocation=src.slice(0,-scriptName.length);break;}}}
-return scriptLocation;}};if(!singleFile){var jsfiles=new Array("OpenLayers/Util.js","OpenLayers/BaseTypes.js","OpenLayers/BaseTypes/Class.js","OpenLayers/BaseTypes/Bounds.js","OpenLayers/BaseTypes/Element.js","OpenLayers/BaseTypes/LonLat.js","OpenLayers/BaseTypes/Pixel.js","OpenLayers/BaseTypes/Size.js","OpenLayers/Console.js","Rico/Corner.js","Rico/Color.js","OpenLayers/Ajax.js","OpenLayers/Events.js","OpenLayers/Map.js","OpenLayers/Layer.js","OpenLayers/Icon.js","OpenLayers/Marker.js","OpenLayers/Marker/Box.js","OpenLayers/Popup.js","OpenLayers/Tile.js","OpenLayers/Tile/Image.js","OpenLayers/Tile/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.js","OpenLayers/Layer/VirtualEarth.js","OpenLayers/Layer/Yahoo.js","OpenLayers/Layer/HTTPRequest.js","OpenLayers/Layer/Grid.js","OpenLayers/Layer/MapServer.js","OpenLayers/Layer/MapGuide.js","OpenLayers/Layer/MapServer/Untiled.js","OpenLayers/Layer/KaMap.js","OpenLayers/Layer/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.js","OpenLayers/Feature.js","OpenLayers/Feature/Vector.js","OpenLayers/Feature/WFS.js","OpenLayers/Handler.js","OpenLayers/Handler/Point.js","OpenLayers/Handler/Path.js","OpenLayers/Handler/Polygon.js","OpenLayers/Handler/Feature.js","OpenLayers/Handler/Drag.js","OpenLayers/Handler/RegularPolygon.js","OpenLayers/Handler/Box.js","OpenLayers/Handler/MouseWheel.js","OpenLayers/Handler/Keyboard.js","OpenLayers/Control.js","OpenLayers/Control/Attribution.js","OpenLayers/Control/ZoomBox.js","OpenLayers/Control/ZoomToMaxExtent.js","OpenLayers/Control/DragPan.js","OpenLayers/Control/Navigation.js","OpenLayers/Control/MouseDefaults.js","OpenLayers/Control/MousePosition.js","OpenLayers/Control/OverviewMap.js","OpenLayers/Control/KeyboardDefaults.js","OpenLayers/Control/PanZoom.js","OpenLayers/Control/PanZoomBar.js","OpenLayers/Control/ArgParser.js","OpenLayers/Control/Permalink.js","OpenLayers/Control/Scale.js","OpenLayers/Control/LayerSwitcher.js","OpenLayers/Control/DrawFeature.js","OpenLayers/Control/DragFeature.js","OpenLayers/Control/ModifyFeature.js","OpenLayers/Control/Panel.js","OpenLayers/Control/SelectFeature.js","OpenLayers/Geometry.js","OpenLayers/Geometry/Rectangle.js","OpenLayers/Geometry/Collection.js","OpenLayers/Geometry/Point.js","OpenLayers/Geometry/MultiPoint.js","OpenLayers/Geometry/Curve.js","OpenLayers/Geometry/LineString.js","OpenLayers/Geometry/LinearRing.js","OpenLayers/Geometry/Polygon.js","OpenLayers/Geometry/MultiLineString.js","OpenLayers/Geometry/MultiPolygon.js","OpenLayers/Geometry/Surface.js","OpenLayers/Renderer.js","OpenLayers/Renderer/Elements.js","OpenLayers/Renderer/SVG.js","OpenLayers/Renderer/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/GML.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/JSON.js","OpenLayers/Format/GeoJSON.js","OpenLayers/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Projection.js","OpenLayers/Strings/en.js");var allScriptTags="";var host=OpenLayers._getScriptLocation()+"lib/";for(var i=0;i<jsfiles.length;i++){if(/MSIE/.test(navigator.userAgent)||/Safari/.test(navigator.userAgent)){var currentScriptTag="<script src='"+host+jsfiles[i]+"'></script>";allScriptTags+=currentScriptTag;}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}}
-if(allScriptTags)document.write(allScriptTags);}})();OpenLayers.VERSION_NUMBER="$Revision: 5560 $";OpenLayers.Util={};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0;i<arguments.length;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
-if(arguments.length==1){return element;}
-elements.push(element);}
-return elements;};if($==null){var $=OpenLayers.Util.getElement;}
-OpenLayers.Util.extend=function(destination,source){if(destination&&source){for(var property in source){destination[property]=source[property];}
-if(source.hasOwnProperty&&source.hasOwnProperty('toString')){destination.toString=source.toString;}}
-return destination;};OpenLayers.Util.removeItem=function(array,item){for(var i=0;i<array.length;i++){if(array[i]==item){array.splice(i,1);}}
-return array;};OpenLayers.Util.clearArray=function(array){var msg=OpenLayers.String.translate("clearArrayDeprecated");OpenLayers.Console.warn(msg);array.length=0;};OpenLayers.Util.indexOf=function(array,obj){for(var i=0;i<array.length;i++){if(array[i]==obj)return i;}
-return-1;};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
-if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
-if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
-if(position){element.style.position=position;}
-if(border){element.style.border=border;}
-if(overflow){element.style.overflow=overflow;}
-if(opacity){element.style.opacity=opacity;element.style.filter='alpha(opacity='+(opacity*100)+')';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';}
-if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
-if(!position){position="absolute";}
-OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
-if(!position){position="relative";}
-OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";OpenLayers.Event.observe(image,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,image));OpenLayers.Event.observe(image,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,image));}
-image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
-return image;};OpenLayers.Util.setOpacity=function(element,opacity){OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
-OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||(this.map&&this.viewRequestID==this.map.viewRequestID)){this.style.backgroundColor=null;this.style.display="";}};OpenLayers.Util.onImageLoadErrorColor="pink";OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.onImageLoadError=function(){this._attempts=(this._attempts)?(this._attempts+1):1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.src=this.src;}else{this.style.backgroundColor=OpenLayers.Util.onImageLoadErrorColor;}
-this.style.display="";};OpenLayers.Util.alphaHack=function(){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=document.body.filters;}catch(e){}
-return(filter&&(version>=5.5)&&(version<7));}
-OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
-OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(opacity){div.style.opacity=opacity;div.style.filter='alpha(opacity='+(opacity*100)+')';}
-if(OpenLayers.Util.alphaHack()){div.style.display="inline-block";if(sizing==null){sizing="scale";}
-div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(div.style.opacity){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
-img.style.filter="progid:DXImageTransform.Microsoft"+".Alpha(opacity=0)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,false);div.appendChild(img);if(delayDisplay){img.style.display="none";OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,div));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,div));}
-OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];}
-return uObject;};OpenLayers.Util.applyDefaults=function(to,from){for(var key in from){if(to[key]==null){to[key]=from[key];}}};OpenLayers.Util.getParameterString=function(params){paramsArray=[];for(var key in params){var value=params[key];if((value!=null)&&(typeof value!='function')){var encodedValue;if(typeof value=='object'&&value.constructor==Array){var encodedItemArray=[];for(var itemIndex=0;itemIndex<value.length;itemIndex++){encodedItemArray.push(encodeURIComponent(value[itemIndex]));}
-encodedValue=encodedItemArray.join(",");}
-else{encodedValue=encodeURIComponent(value);}
-paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
-return paramsArray.join("&");};OpenLayers.ImgPath='';OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0;i<arguments.length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
-return returnValue;}
-OpenLayers.Util.getNodes=function(p,tagName){var nodes=OpenLayers.Util.Try(function(){return OpenLayers.Util._getNodes(p.documentElement.childNodes,tagName);},function(){return OpenLayers.Util._getNodes(p.childNodes,tagName);});return nodes;};OpenLayers.Util._getNodes=function(nodes,tagName){var retArray=[];for(var i=0;i<nodes.length;i++){if(nodes[i].nodeName==tagName){retArray.push(nodes[i]);}}
-return retArray;};OpenLayers.Util.getTagText=function(parent,item,index){var result=OpenLayers.Util.getNodes(parent,item);if(result&&(result.length>0))
-{if(!index){index=0;}
-if(result[index].childNodes.length>1){return result.childNodes[1].nodeValue;}
-else if(result[index].childNodes.length==1){return result[index].firstChild.nodeValue;}}else{return"";}};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val)
-val=node.textContent;if(!val)
-val=node.firstChild.nodeValue;},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
-return(target!=div);};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.distVincenty=function(p1,p2){var a=6378137,b=6356752.3142,f=1/298.257223563;var L=OpenLayers.Util.rad(p2.lon-p1.lon);var U1=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p1.lat)));var U2=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p2.lat)));var sinU1=Math.sin(U1),cosU1=Math.cos(U1);var sinU2=Math.sin(U2),cosU2=Math.cos(U2);var lambda=L,lambdaP=2*Math.PI;var iterLimit=20;while(Math.abs(lambda-lambdaP)>1e-12&&--iterLimit>0){var sinLambda=Math.sin(lambda),cosLambda=Math.cos(lambda);var sinSigma=Math.sqrt((cosU2*sinLambda)*(cosU2*sinLambda)+
-(cosU1*sinU2-sinU1*cosU2*cosLambda)*(cosU1*sinU2-sinU1*cosU2*cosLambda));if(sinSigma==0)return 0;var cosSigma=sinU1*sinU2+cosU1*cosU2*cosLambda;var sigma=Math.atan2(sinSigma,cosSigma);var alpha=Math.asin(cosU1*cosU2*sinLambda/sinSigma);var cosSqAlpha=Math.cos(alpha)*Math.cos(alpha);var cos2SigmaM=cosSigma-2*sinU1*sinU2/cosSqAlpha;var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));lambdaP=lambda;lambda=L+(1-C)*f*Math.sin(alpha)*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));}
-if(iterLimit==0)return NaN
-var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
-B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));var s=b*A*(sigma-deltaSigma);var d=s.toFixed(3)/1000;return d;};OpenLayers.Util.getParameters=function(url){url=url||window.location.href
-if(url==null){url=window.location.href;}
-var paramsString="";if(OpenLayers.String.contains(url,'?')){var start=url.indexOf('?')+1;var end=OpenLayers.String.contains(url,"#")?url.indexOf('#'):url.length;paramsString=url.substring(start,end);}
-var parameters={};var pairs=paramsString.split(/[&;]/);for(var i=0;i<pairs.length;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=decodeURIComponent(keyValue[0]);var value=keyValue[1]||'';value=value.split(",");for(var j=0;j<value.length;j++){value[j]=decodeURIComponent(value[j]);}
-if(value.length==1){value=value[0];}
-parameters[key]=value;}}
-return parameters;};OpenLayers.Util.getArgs=function(url){var err=OpenLayers.String.translate("getArgsDeprecated");OpenLayers.Console.warn(err);return OpenLayers.Util.getParameters(url);};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
-OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){if(units==null){units="degrees";}
-var normScale=OpenLayers.Util.normalizeScale(scale);var resolution=1/(normScale*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH);return resolution;};OpenLayers.Util.getScaleFromResolution=function(resolution,units){if(units==null){units="degrees";}
-var scale=resolution*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH;return scale;};OpenLayers.Util.safeStopPropagation=function(evt){OpenLayers.Event.stop(evt,true);};OpenLayers.Util.pagePosition=function(forElement){var valueT=0,valueL=0;var element=forElement;var child=forElement;while(element){if(element==document.body){if(OpenLayers.Element.getStyle(child,'position')=='absolute'){break;}}
-valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;child=element;try{element=element.offsetParent;}catch(e){OpenLayers.Console.error(OpenLayers.String.translate("pagePositionFailed",element.id));break;}}
-element=forElement;while(element){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;element=element.parentNode;}
-return[valueL,valueT];};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true});urlObj1=OpenLayers.Util.createUrlObject(url1,options);urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(options.test){alert(key+"\n1:"+urlObj1[key]+"\n2:"+urlObj2[key]);}
-var val1=urlObj1[key];var val2=urlObj2[key];switch(key){case"args":break;case"host":case"port":case"protocol":if((val1=="")||(val2=="")){break;}
-default:if((key!="args")&&(urlObj1[key]!=urlObj2[key])){return false;}
-break;}}
-for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;}
-delete urlObj2.args[key];}
-for(var key in urlObj2.args){return false;}
-return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};var urlObject={};if(options.ignoreCase){url=url.toLowerCase();}
-var a=document.createElement('a');a.href=url;urlObject.host=a.host;var port=a.port;if(port.length<=0){var newHostLength=urlObject.host.length-(port.length);urlObject.host=urlObject.host.substring(0,newHostLength);}
-urlObject.protocol=a.protocol;urlObject.port=((port=="80")&&(options.ignorePort80))?"":port;urlObject.hash=(options.ignoreHash)?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
-urlObject.args=OpenLayers.Util.getParameters(queryString);if(((urlObject.protocol=="file:")&&(url.indexOf("file:")!=-1))||((urlObject.protocol!="file:")&&(urlObject.host!=""))){urlObject.pathname=a.pathname;var qIndex=urlObject.pathname.indexOf("?");if(qIndex!=-1){urlObject.pathname=urlObject.pathname.substring(0,qIndex);}}else{var relStr=OpenLayers.Util.removeTail(url);var backs=0;do{var index=relStr.indexOf("../");if(index==0){backs++
-relStr=relStr.substr(3);}else if(index>=0){var prevChunk=relStr.substr(0,index-1);var slash=prevChunk.indexOf("/");prevChunk=(slash!=-1)?prevChunk.substr(0,slash+1):"";var postChunk=relStr.substr(index+3);relStr=prevChunk+postChunk;}}while(index!=-1)
-var windowAnchor=document.createElement("a");var windowUrl=window.location.href;if(options.ignoreCase){windowUrl=windowUrl.toLowerCase();}
-windowAnchor.href=windowUrl;urlObject.protocol=windowAnchor.protocol;var splitter=(windowAnchor.pathname.indexOf("/")!=-1)?"/":"\\";var dirs=windowAnchor.pathname.split(splitter);dirs.pop();while((backs>0)&&(dirs.length>0)){dirs.pop();backs--;}
-relStr=dirs.join("/")+"/"+relStr;urlObject.pathname=relStr;}
-if((urlObject.protocol=="file:")||(urlObject.protocol=="")){urlObject.host="localhost";}
-return urlObject;};OpenLayers.Util.removeTail=function(url){var head=null;var qMark=url.indexOf("?");var hashMark=url.indexOf("#");if(qMark==-1){head=(hashMark!=-1)?url.substr(0,hashMark):url;}else{head=(hashMark!=-1)?url.substr(0,Math.min(qMark,hashMark)):url.substr(0,qMark);}
-return head;};OpenLayers.Util.getBrowserName=function(){var browserName="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){browserName="opera";}else if(ua.indexOf("msie")!=-1){browserName="msie";}else if(ua.indexOf("safari")!=-1){browserName="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){browserName="firefox";}else{browserName="mozilla";}}
-return browserName;};OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s*(.*?)\s*$/,"$1");},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1;i<oStringList.length;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
-return camelizedString;},langCode:(OpenLayers.Util.getBrowserName()=="msie")?navigator.userLanguage.substring(0,2):navigator.language.substring(0,2),defaultLangCode:'en',translate:function(key){var langCode=OpenLayers.String.langCode;if(!OpenLayers.Strings[langCode]){var msg='failed to find '+OpenLayers.String.langCode+' dictionary, falling back to default language';OpenLayers.Console.log(msg);OpenLayers.Strings[langCode]=OpenLayers.Strings[OpenLayers.String.defaultLangCode];langCode=OpenLayers.String.defaultLangCode;}
-var dictionary=OpenLayers.Strings[langCode];var message="NoMsgsFound";var msgValue=dictionary[key];if(!msgValue){message=key;}else{message=msgValue;if(arguments[this.translate.length]){var varArgs=[].slice.call(arguments,this.translate.length);varArgs.unshift(message);message=this.formatMessage.apply(this,varArgs);}}
-return message;},formatMessage:function(messageTemplate)
-{var message=messageTemplate;var varArgs=[].slice.call(arguments,this.formatMessage.length);for(var i in varArgs){var parm=new RegExp("\\{"+i+"\\}","g");message=message.replace(parm,varArgs[i]);}
-return message;},};OpenLayers.Strings={};if(!String.prototype.startsWith){String.prototype.startsWith=function(sStart){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.startsWith"));return OpenLayers.String.startsWith(this,sStart);};}
-if(!String.prototype.contains){String.prototype.contains=function(str){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.contains"));return OpenLayers.String.contains(this,str);};}
-if(!String.prototype.trim){String.prototype.trim=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.trim"));return OpenLayers.String.trim(this);};}
-if(!String.prototype.camelize){String.prototype.camelize=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.camelize"));return OpenLayers.String.camelize(this);};}
-OpenLayers.Number={limitSigDigs:function(num,sig){var fig;if(sig>0){fig=parseFloat(num.toPrecision(sig));}else{fig=0;}
-return fig;}};if(!Number.prototype.limitSigDigs){Number.prototype.limitSigDigs=function(sig){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Number.limitSigDigs"));return OpenLayers.Number.limitSigDigs(this,sig);};}
-OpenLayers.Function={bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};}};if(!Function.prototype.bind){Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bind"));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments);};}
-if(!Function.prototype.bindAsEventListener){Function.prototype.bindAsEventListener=function(object){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bindAsEventListener"));return OpenLayers.Function.bindAsEventListener(this,object);};}
-OpenLayers.Class=function(){var Class=function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}}
-var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];}
-OpenLayers.Util.extend(extended,parent);}
-Class.prototype=extended;return Class;}
-OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype)
-this.initialize.apply(this,arguments);}}
-OpenLayers.Class.inherit=function(){var superClass=arguments[0];var proto=new superClass(OpenLayers.Class.isPrototype);for(var i=1;i<arguments.length;i++){if(typeof arguments[i]=="function"){var mixin=arguments[i];arguments[i]=new mixin(OpenLayers.Class.isPrototype);}
-OpenLayers.Util.extend(proto,arguments[i]);}
-return proto;}
-OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));}
-return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,initialize:function(left,bottom,right,top){if(left!=null){this.left=parseFloat(left);}
-if(bottom!=null){this.bottom=parseFloat(bottom);}
-if(right!=null){this.right=parseFloat(right);}
-if(top!=null){this.top=parseFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},equals:function(bounds){var equals=false;if(bounds!=null){equals=((this.left==bounds.left)&&(this.right==bounds.right)&&(this.top==bounds.top)&&(this.bottom==bounds.bottom));}
-return equals;},toString:function(){return("left-bottom=("+this.left+","+this.bottom+")"
-+" right-top=("+this.right+","+this.top+")");},toArray:function(){return[this.left,this.bottom,this.right,this.top];},toBBOX:function(decimal){if(decimal==null){decimal=6;}
-var mult=Math.pow(10,decimal);var bbox=Math.round(this.left*mult)/mult+","+
-Math.round(this.bottom*mult)/mult+","+
-Math.round(this.right*mult)/mult+","+
-Math.round(this.top*mult)/mult;return bbox;},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){return new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("boundsAddError");OpenLayers.Console.error(msg);return null;}
-return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){switch(object.CLASS_NAME){case"OpenLayers.LonLat":bounds=new OpenLayers.Bounds(object.lon,object.lat,object.lon,object.lat);break;case"OpenLayers.Geometry.Point":bounds=new OpenLayers.Bounds(object.x,object.y,object.x,object.y);break;case"OpenLayers.Bounds":bounds=object;break;}
-if(bounds){if((this.left==null)||(bounds.left<this.left)){this.left=bounds.left;}
-if((this.bottom==null)||(bounds.bottom<this.bottom)){this.bottom=bounds.bottom;}
-if((this.right==null)||(bounds.right>this.right)){this.right=bounds.right;}
-if((this.top==null)||(bounds.top>this.top)){this.top=bounds.top;}}}},containsLonLat:function(ll,inclusive){return this.contains(ll.lon,ll.lat,inclusive);},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
-var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(x<this.right)&&(y>this.bottom)&&(y<this.top));}
-return contains;},intersectsBounds:function(bounds,inclusive){if(inclusive==null){inclusive=true;}
-var inBottom=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.bottom>this.bottom)&&(bounds.bottom<this.top))||((this.bottom>bounds.bottom)&&(this.bottom<bounds.top)));var inTop=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.top>this.bottom)&&(bounds.top<this.top))||((this.top>bounds.bottom)&&(this.top<bounds.top)));var inRight=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.right>this.left)&&(bounds.right<this.right))||((this.right>bounds.left)&&(this.right<bounds.right)));var inLeft=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.left>this.left)&&(bounds.left<this.right))||((this.left>bounds.left)&&(this.left<bounds.right)));return(this.containsBounds(bounds,true,inclusive)||bounds.containsBounds(this,true,inclusive)||((inTop||inBottom)&&(inLeft||inRight)));},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
-if(inclusive==null){inclusive=true;}
-var inLeft;var inTop;var inRight;var inBottom;if(inclusive){inLeft=(bounds.left>=this.left)&&(bounds.left<=this.right);inTop=(bounds.top>=this.bottom)&&(bounds.top<=this.top);inRight=(bounds.right>=this.left)&&(bounds.right<=this.right);inBottom=(bounds.bottom>=this.bottom)&&(bounds.bottom<=this.top);}else{inLeft=(bounds.left>this.left)&&(bounds.left<this.right);inTop=(bounds.top>this.bottom)&&(bounds.top<this.top);inRight=(bounds.right>this.left)&&(bounds.right<this.right);inBottom=(bounds.bottom>this.bottom)&&(bounds.bottom<this.top);}
-return(partial)?(inTop||inBottom)&&(inLeft||inRight):(inTop&&inLeft&&inBottom&&inRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat<center.lat)?"b":"t";quadrant+=(lonlat.lon<center.lon)?"l":"r";return quadrant;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){while(newBounds.left<maxExtent.left&&(newBounds.right-rightTolerance)<=maxExtent.left){newBounds=newBounds.add(maxExtent.getWidth(),0);}
-while((newBounds.left+leftTolerance)>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-maxExtent.getWidth(),0);}}
-return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds);};OpenLayers.Bounds.fromArray=function(bbox){return new OpenLayers.Bounds(parseFloat(bbox[0]),parseFloat(bbox[1]),parseFloat(bbox[2]),parseFloat(bbox[3]));};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'hide':'show';OpenLayers.Element[display](element);}},hide:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='none';}},show:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='';}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},getDimensions:function(element){element=OpenLayers.Util.getElement(element);if(OpenLayers.Element.getStyle(element,'display')!='none'){return{width:element.offsetWidth,height:element.offsetHeight};}
-var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;els.visibility='hidden';els.position='absolute';els.display='';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display='none';els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
-var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}
-return value=='auto'?null:value;}};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){this.lon=parseFloat(lon);this.lat=parseFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){var msg=OpenLayers.String.translate("lonlatAddError");OpenLayers.Console.error(msg);return null;}
-return new OpenLayers.LonLat(this.lon+lon,this.lat+lat);},equals:function(ll){var equals=false;if(ll!=null){equals=((this.lon==ll.lon&&this.lat==ll.lat)||(isNaN(this.lon)&&isNaN(this.lat)&&isNaN(ll.lon)&&isNaN(ll.lat)));}
-return equals;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
-while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
-return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(parseFloat(pair[0]),parseFloat(pair[1]));};OpenLayers.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));}
-return equals;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("pixelAddError");OpenLayers.Console.error(msg);return null;}
-return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
-return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.ProxyHost="";OpenLayers.nullHandler=function(request){alert(OpenLayers.String.translate("unhandledRequest",request.statusText));};OpenLayers.loadURL=function(uri,params,caller,onComplete,onFailure){if(OpenLayers.ProxyHost&&OpenLayers.String.startsWith(uri,"http")){uri=OpenLayers.ProxyHost+escape(uri);}
-var success=(onComplete)?OpenLayers.Function.bind(onComplete,caller):OpenLayers.nullHandler;var failure=(onFailure)?OpenLayers.Function.bind(onFailure,caller):OpenLayers.nullHandler;new OpenLayers.Ajax.Request(uri,{method:'get',parameters:params,onComplete:success,onFailure:failure});};OpenLayers.parseXMLString=function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
-var ajaxResponse=OpenLayers.Util.Try(function(){var xmldom=new ActiveXObject('Microsoft.XMLDOM');xmldom.loadXML(text);return xmldom;},function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
-req.send(null);return req.responseXML;});return ajaxResponse;};OpenLayers.Ajax={emptyFunction:function(){},getTransport:function(){return OpenLayers.Util.Try(function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')},function(){return new XMLHttpRequest()})||false;},activeRequestCount:0};OpenLayers.Ajax.Responders={responders:[],register:function(responderToAdd){for(var i=0;i<this.responders.length;i++)
-if(responderToAdd==this.responders[i])
-return;this.responders.push(responderToAdd);},dispatch:function(callback,request,transport,json){var responder;for(var i=0;i<this.responders.length;i++){responder=this.responders[i];if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}}}};OpenLayers.Ajax.Responders.register({onCreate:function(){OpenLayers.Ajax.activeRequestCount++;},onComplete:function(){OpenLayers.Ajax.activeRequestCount--;}});OpenLayers.Ajax.Base=function(){};OpenLayers.Ajax.Base.prototype={setOptions:function(options){this.options={'method':'post','asynchronous':true,'parameters':''};OpenLayers.Util.extend(this.options,options||{});},responseIsSuccess:function(){return this.transport.status==undefined||this.transport.status==0||(this.transport.status>=200&&this.transport.status<300);},responseIsFailure:function(){return!this.responseIsSuccess();}};OpenLayers.Ajax.Request=OpenLayers.Class(OpenLayers.Ajax.Base,{initialize:function(url,options){this.transport=OpenLayers.Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){var parameters=this.options.parameters||'';if(parameters.length>0)parameters+='&_=';try{this.url=url;if(this.options.method=='get'&&parameters.length>0){this.url+=(this.url.match(/\?/)?'&':'?')+parameters;}
-OpenLayers.Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.options.method,this.url,this.options.asynchronous);if(this.options.asynchronous){this.transport.onreadystatechange=OpenLayers.Function.bind(this.onStateChange,this);setTimeout(OpenLayers.Function.bind((function(){this.respondToReadyState(1)}),this),10);}
-this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange();}}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version','OpenLayers'];if(this.options.method=='post'&&!this.options.postBody){requestHeaders.push('Content-type','application/x-www-form-urlencoded');if(this.transport.overrideMimeType){requestHeaders.push('Connection','close');}}
-if(this.options.requestHeaders){requestHeaders.push.apply(requestHeaders,this.options.requestHeaders);}
-for(var i=0;i<requestHeaders.length;i+=2){this.transport.setRequestHeader(requestHeaders[i],requestHeaders[i+1]);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState!=1){this.respondToReadyState(this.transport.readyState);}},header:function(name){try{return this.transport.getResponseHeader(name);}catch(e){}},evalJSON:function(){try{return eval(this.header('X-JSON'));}catch(e){}},evalResponse:function(){try{return eval(this.transport.responseText);}catch(e){this.dispatchException(e);}},respondToReadyState:function(readyState){var event=OpenLayers.Ajax.Request.Events[readyState];var transport=this.transport,json=this.evalJSON();if(event=='Complete'){try{var responseSuccess=this.responseIsSuccess()?'Success':'Failure';(this.options['on'+this.transport.status]||this.options['on'+responseSuccess]||OpenLayers.Ajax.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);}
-var contentType=this.header('Content-type')||'';if(contentType.match(/^text\/javascript/i)){this.evalResponse();}}
-try{(this.options['on'+event]||OpenLayers.Ajax.emptyFunction)(transport,json);OpenLayers.Ajax.Responders.dispatch('on'+event,this,transport,json);}catch(e){this.dispatchException(e);}
-if(event=='Complete'){this.transport.onreadystatechange=OpenLayers.Ajax.emptyFunction;}},dispatchException:function(exception){if(this.options.onException){this.options.onException(this,exception);}else{throw exception;}
-OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}});OpenLayers.Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];OpenLayers.Ajax.getElementsByTagNameNS=function(parentnode,nsuri,nsprefix,tagname){var elem=null;if(parentnode.getElementsByTagNameNS){elem=parentnode.getElementsByTagNameNS(nsuri,tagname);}else{elem=parentnode.getElementsByTagName(nsprefix+':'+tagname);}
-return elem;};OpenLayers.Ajax.serializeXMLToString=function(xmldom){var serializer=new XMLSerializer();data=serializer.serializeToString(xmldom);return data;}
-OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,displayClass:"",active:null,handler:null,initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if(this.handler){this.handler.destroy();}
-this.map=null;},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv();this.div.id=this.id;this.div.className=this.displayClass;}
-if(px!=null){this.position=px.clone();}
-this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
-if(this.handler){this.handler.activate();}
-this.active=true;return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
-this.active=false;return true;}
-return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=(size)?size:new OpenLayers.Size(20,20);this.offset=offset?offset:new OpenLayers.Pixel(-(this.size.w/2),-(this.size.h/2));this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
-this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
-if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
-var offsetPx=this.px.offset(this.offset);OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,offsetPx);}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Strings.en={'test1':'this is a test','test2':'and another test','test3':'arg one:{0} arg two: {1}','unhandledRequest':"Unhandled request return {0}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Base Layer",'sameProjection':"The overview map only works when it is in the same projection as the main map",'readNotImplemented':"Read not implemented.",'writeNotImplemented':"Write not implemented.",'noFID':"Can't update a feature for which there is no FID.",'errorLoadingGML':"Error in loading GML file {0}",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n{0}",'componentShouldBe':"addFeatures : component should be an {0}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. "+"This usually means you destroyed a layer, but not some handler which is associated with it.",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS {0}",'commitFailed':"WFS Transaction: FAILED {0}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The {0} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the {0} library "+"script was either not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/{1}' "+"target='_blank'>click here</a>",'scale':"Scale = 1 : {0}",'layerAlreadyAdded':"You tried to add the layer: {0} to the map, but it has already been added",'reprojectDeprecated':"You are using the 'reproject' option "+"on the {0} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use {0} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: {0}",'clearArrayDeprecated':"OpenLayers.Util.clearArray() is Deprecated."+" Please use 'array.length = 0' instead.",'getArgsDeprecated':"The getArgs() function is deprecated and will be removed "+"with the 3.0 version of OpenLayers. Please instead use "+"OpenLayers.Util.getParameters().",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",'end':''};OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0;i<this.map.controls.length;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){break;}}
-if(i==this.map.controls.length){var args=OpenLayers.Util.getParameters();if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseInt(args.zoom);}
-this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}
-if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0;i<this.layers.length;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);while(this.buttons.length){var btn=this.buttons.shift();btn.map=null;OpenLayers.Event.stopObservingElement(btn);}
-this.buttons=null;this.position=null;},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var btn=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_PanZoom_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);OpenLayers.Event.observe(btn,"mousedown",OpenLayers.Function.bindAsEventListener(this.buttonDown,btn));OpenLayers.Event.observe(btn,"dblclick",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));OpenLayers.Event.observe(btn,"click",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));btn.action=id;btn.map=this.map;btn.slideFactor=this.slideFactor;this.buttons.push(btn);return btn;},doubleClick:function(evt){OpenLayers.Event.stop(evt);return false;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;switch(this.action){case"panup":this.map.pan(0,-50);break;case"pandown":this.map.pan(0,50);break;case"panleft":this.map.pan(-50,0);break;case"panright":this.map.pan(50,0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}
-OpenLayers.Event.stop(evt);},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Event={observers:false,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
-if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
-element=element.parentNode;return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';}
-if(!this.observers){this.observers={};}
-if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;}
-element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);}
-var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];}
-this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}}
-var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&i<elementObservers.length){var cacheEntry=elementObservers[i];if((cacheEntry.name==name)&&(cacheEntry.observer==observer)&&(cacheEntry.useCapture==useCapture)){elementObservers.splice(i,1);if(elementObservers.length==0){delete OpenLayers.Event.observers[cacheID];}
-foundEntry=true;break;}
-i++;}}
-if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}
-return foundEntry;},unloadCache:function(){if(OpenLayers.Event.observers){for(var cacheID in OpenLayers.Event.observers){var elementObservers=OpenLayers.Event.observers[cacheID];OpenLayers.Event._removeElementObservers.apply(this,[elementObservers]);}
-OpenLayers.Event.observers=false;}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);if(window.Event){OpenLayers.Util.applyDefaults(window.Event,OpenLayers.Event);}else{var Event=OpenLayers.Event;}
-OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","resize","focus","blur"],listeners:null,object:null,element:null,eventTypes:null,eventHandler:null,fallThrough:null,initialize:function(object,element,eventTypes,fallThrough){this.object=object;this.element=element;this.eventTypes=eventTypes;this.fallThrough=fallThrough;this.listeners={};this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);if(this.eventTypes!=null){for(var i=0;i<this.eventTypes.length;i++){this.addEventType(this.eventTypes[i]);}}
-if(this.element!=null){this.attachToElement(element);}},destroy:function(){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}
-this.element=null;this.listeners=null;this.object=null;this.eventTypes=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){if(!this.listeners[eventName]){this.listeners[eventName]=[];}},attachToElement:function(element){for(var i=0;i<this.BROWSER_EVENTS.length;i++){var eventType=this.BROWSER_EVENTS[i];this.addEventType(eventType);OpenLayers.Event.observe(element,eventType,this.eventHandler);}
-OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},register:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){listeners.push({obj:obj,func:func});}}},registerPriority:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){listeners.unshift({obj:obj,func:func});}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){for(var i=0;i<listeners.length;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){if(evt==null){evt={};}
-evt.object=this.object;evt.element=this.element;var listeners=(this.listeners[type])?this.listeners[type].slice():null;if((listeners!=null)&&(listeners.length>0)){for(var i=0;i<listeners.length;i++){var callback=listeners[i];var continueChain;if(callback.obj!=null){continueChain=callback.func.call(callback.obj,evt);}else{continueChain=callback.func(evt);}
-if((continueChain!=null)&&(continueChain==false)){break;}}
-if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}}},handleBrowserEvent:function(evt){evt.xy=this.getMousePosition(evt);this.triggerEvent(evt.type,evt)},getMousePosition:function(evt){if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=(document.documentElement.scrollLeft||document.body.scrollLeft);this.element.offsets[1]+=(document.documentElement.scrollTop||document.body.scrollTop);}
-return new OpenLayers.Pixel((evt.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft))-this.element.offsets[0]
--(document.documentElement.clientLeft||0),(evt.clientY+(document.documentElement.scrollTop||document.body.scrollTop))-this.element.offsets[1]
--(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Projection=OpenLayers.Class({initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transform=function(point,source,dest){if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}
-return point;};OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size){this.layer=layer;this.position=position.clone();this.bounds=bounds.clone();this.url=url;this.size=size.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;this.events.destroy();this.events=null;},draw:function(){this.clear();var maxExtent=this.layer.maxExtent;var withinMaxExtent=true;if(this.layer.restrictedExtent){withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));}
-return(withinMaxExtent||this.layer.displayOutsideMaxExtent);},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
-this.bounds=bounds.clone();this.position=position.clone();if(redraw){this.draw();}},clear:function(){},getBoundsFromBaseLayer:function(position){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",this.layer.name));var topLeft=this.layer.map.getLonLatFromLayerPx(position);var bottomRightPx=position.clone();bottomRightPx.x+=this.size.w;bottomRightPx.y+=this.size.h;var bottomRight=this.layer.map.getLonLatFromLayerPx(bottomRightPx);if(topLeft.lon>bottomRight.lon){if(topLeft.lon<0){topLeft.lon=-180-(topLeft.lon+180);}else{bottomRight.lon=180+bottomRight.lon+180;}}
-bounds=new OpenLayers.Bounds(topLeft.lon,bottomRight.lat,bottomRight.lon,topLeft.lat);return bounds;},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{id:"OverviewMap",element:null,ovmap:null,size:new OpenLayers.Size(180,90),layers:null,minRatio:8,maxRatio:32,mapOptions:null,initialize:function(options){this.layers=[];OpenLayers.Control.prototype.initialize.apply(this,[options]);},destroy:function(){if(!this.mapDiv){return;}
-this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;this.rectEvents.destroy();this.rectEvents=null;this.ovmap.destroy();this.ovmap=null;this.element.removeChild(this.mapDiv);this.mapDiv=null;this.mapDivEvents.destroy();this.mapDivEvents=null;this.div.removeChild(this.element);this.element=null;this.elementEvents.destroy();this.elementEvents=null;if(this.maximizeDiv){OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.div.removeChild(this.maximizeDiv);this.maximizeDiv=null;}
-if(this.minimizeDiv){OpenLayers.Event.stopObservingElement(this.minimizeDiv);this.div.removeChild(this.minimizeDiv);this.minimizeDiv=null;}
-this.map.events.unregister('moveend',this,this.update);this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!(this.layers.length>0)){if(this.map.baseLayer){var layer=this.map.baseLayer.clone();this.layers=[layer];}else{this.map.events.register("changebaselayer",this,this.baseLayerDraw);return this.div;}}
-this.element=document.createElement('div');this.element.className=this.displayClass+'Element';this.element.style.display='none';this.mapDiv=document.createElement('div');this.mapDiv.style.width=this.size.w+'px';this.mapDiv.style.height=this.size.h+'px';this.mapDiv.style.position='relative';this.mapDiv.style.overflow='hidden';this.mapDiv.id=OpenLayers.Util.createUniqueID('overviewMap');this.extentRectangle=document.createElement('div');this.extentRectangle.style.position='absolute';this.extentRectangle.style.zIndex=1000;this.extentRectangle.style.overflow='hidden';this.extentRectangle.style.backgroundImage='url('+
-OpenLayers.Util.getImagesLocation()+'blank.gif)';this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);this.map.events.register('moveend',this,this.update);this.elementEvents=new OpenLayers.Events(this,this.element);this.elementEvents.register('mousedown',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('dblclick',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,true);this.rectEvents.register('mouseout',this,this.rectMouseOut);this.rectEvents.register('mousedown',this,this.rectMouseDown);this.rectEvents.register('mousemove',this,this.rectMouseMove);this.rectEvents.register('mouseup',this,this.rectMouseUp);this.rectEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents.register('dblclick',this,this.rectDblClick);this.mapDivEvents=new OpenLayers.Events(this,this.mapDiv);this.mapDivEvents.register('click',this,this.mapDivClick);if(!this.outsideViewport){this.div.className=this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+'MaximizeButton',null,new OpenLayers.Size(18,18),img,'absolute');this.maximizeDiv.style.display='none';this.maximizeDiv.className=this.displayClass+'MaximizeButton';OpenLayers.Event.observe(this.maximizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv('OpenLayers_Control_minimizeDiv',null,new OpenLayers.Size(18,18),img,'absolute');this.minimizeDiv.style.display='none';this.minimizeDiv.className=this.displayClass+'MinimizeButton';OpenLayers.Event.observe(this.minimizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);var eventsToStop=['dblclick','mousedown'];for(var i=0;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
-this.minimizeControl();}else{this.element.style.display='';}
-if(this.map.getExtent()){this.update();}
-return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},rectMouseOut:function(evt){if(this.rectDragStart!=null){if(this.performedRectDrag){this.rectMouseMove(evt);var rectPxBounds=this.getRectPxBounds();if((rectPxBounds.top<=0)||(rectPxBounds.left<=0)||(rectPxBounds.bottom>=this.size.h-this.hComp)||(rectPxBounds.right>=this.size.w-this.wComp)){this.updateMapToRect();}else{return;}}
-document.onselectstart=null;this.rectDragStart=null;}},rectMouseDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;this.rectDragStart=evt.xy.clone();this.performedRectDrag=false;OpenLayers.Event.stop(evt);},rectMouseMove:function(evt){if(this.rectDragStart!=null){var deltaX=this.rectDragStart.x-evt.xy.x;var deltaY=this.rectDragStart.y-evt.xy.y;var rectPxBounds=this.getRectPxBounds();var rectTop=rectPxBounds.top;var rectLeft=rectPxBounds.left;var rectHeight=Math.abs(rectPxBounds.getHeight());var rectWidth=rectPxBounds.getWidth();var newTop=Math.max(0,(rectTop-deltaY));newTop=Math.min(newTop,this.ovmap.size.h-this.hComp-rectHeight);var newLeft=Math.max(0,(rectLeft-deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-this.wComp-rectWidth);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+rectHeight,newLeft+rectWidth,newTop));this.rectDragStart=evt.xy.clone();this.performedRectDrag=true;OpenLayers.Event.stop(evt);}},rectMouseUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;if(this.performedRectDrag){this.updateMapToRect();OpenLayers.Event.stop(evt);}
-document.onselectstart=null;this.rectDragStart=null;},rectDblClick:function(evt){this.performedRectDrag=false;OpenLayers.Event.stop(evt);this.updateOverview();},mapDivClick:function(evt){var pxBounds=this.getRectPxBounds();var pxCenter=pxBounds.getCenterPixel();var deltaX=evt.xy.x-pxCenter.x;var deltaY=evt.xy.y-pxCenter.y;var top=pxBounds.top;var left=pxBounds.left;var height=Math.abs(pxBounds.getHeight());var width=pxBounds.getWidth();var newTop=Math.max(0,(top+deltaY));newTop=Math.min(newTop,this.ovmap.size.h-height);var newLeft=Math.max(0,(left+deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-width);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+height,newLeft+width,newTop));this.updateMapToRect();OpenLayers.Event.stop(evt);},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
-if(!this.isSuitableOverview()){this.updateOverview();}
-this.updateRectToMap();},isSuitableOverview:function(){var mapExtent=this.map.getExtent();var maxExtent=this.map.maxExtent;var testExtent=new OpenLayers.Bounds(Math.max(mapExtent.left,maxExtent.left),Math.max(mapExtent.bottom,maxExtent.bottom),Math.min(mapExtent.right,maxExtent.right),Math.min(mapExtent.top,maxExtent.top));var resRatio=this.ovmap.getResolution()/this.map.getResolution();return((resRatio>this.minRatio)&&(resRatio<=this.maxRatio)&&(this.ovmap.getExtent().containsBounds(testExtent)));},updateOverview:function(){var mapRes=this.map.getResolution();var targetRes=this.ovmap.getResolution();var resRatio=targetRes/mapRes;if(resRatio>this.maxRatio){targetRes=this.minRatio*mapRes;}else if(resRatio<=this.minRatio){targetRes=this.maxRatio*mapRes;}
-this.ovmap.setCenter(this.map.center,this.ovmap.getZoomForResolution(targetRes));this.updateRectToMap();},createMap:function(){var options=OpenLayers.Util.extend({controls:[],maxResolution:'auto'},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,options);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-left-width'))+
-parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-right-width'));this.wComp=(this.wComp)?this.wComp:2;this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-top-width'))+
-parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-bottom-width'));this.hComp=(this.hComp)?this.hComp:2;},updateRectToMap:function(){if(this.ovmap.getProjection()&&(this.map.getProjection()!=this.ovmap.getProjection())){alert(OpenLayers.String.translate("sameProjection"));}
-var pxBounds=this.getRectBoundsFromMapBounds(this.map.getExtent());if(pxBounds){this.setRectPxBounds(pxBounds);}},updateMapToRect:function(){var pxBounds=this.getRectPxBounds();var lonLatBounds=this.getMapBoundsFromRectBounds(pxBounds);this.map.setCenter(lonLatBounds.getCenterLonLat(),this.map.zoom);},getRectPxBounds:function(){var top=parseInt(this.extentRectangle.style.top);var left=parseInt(this.extentRectangle.style.left);var height=parseInt(this.extentRectangle.style.height);var width=parseInt(this.extentRectangle.style.width);return new OpenLayers.Bounds(left,top+height,left+width,top);},setRectPxBounds:function(pxBounds){var top=Math.max(pxBounds.top,0);var left=Math.max(pxBounds.left,0);var bottom=Math.min(pxBounds.top+Math.abs(pxBounds.getHeight()),this.ovmap.size.h-this.hComp);var right=Math.min(pxBounds.left+pxBounds.getWidth(),this.ovmap.size.w-this.wComp);this.extentRectangle.style.top=parseInt(top)+'px';this.extentRectangle.style.left=parseInt(left)+'px';this.extentRectangle.style.height=parseInt(Math.max(bottom-top,0))+'px';this.extentRectangle.style.width=parseInt(Math.max(right-left,0))+'px';},getRectBoundsFromMapBounds:function(lonLatBounds){var leftBottomLonLat=new OpenLayers.LonLat(lonLatBounds.left,lonLatBounds.bottom);var rightTopLonLat=new OpenLayers.LonLat(lonLatBounds.right,lonLatBounds.top);var leftBottomPx=this.getOverviewPxFromLonLat(leftBottomLonLat);var rightTopPx=this.getOverviewPxFromLonLat(rightTopLonLat);var bounds=null;if(leftBottomPx&&rightTopPx){bounds=new OpenLayers.Bounds(leftBottomPx.x,leftBottomPx.y,rightTopPx.x,rightTopPx.y);}
-return bounds;},getMapBoundsFromRectBounds:function(pxBounds){var leftBottomPx=new OpenLayers.Pixel(pxBounds.left,pxBounds.bottom);var rightTopPx=new OpenLayers.Pixel(pxBounds.right,pxBounds.top);var leftBottomLonLat=this.getLonLatFromOverviewPx(leftBottomPx);var rightTopLonLat=this.getLonLatFromOverviewPx(rightTopPx);return new OpenLayers.Bounds(leftBottomLonLat.lon,leftBottomLonLat.lat,rightTopLonLat.lon,rightTopLonLat.lat);},getLonLatFromOverviewPx:function(overviewMapPx){var size=this.ovmap.size;var res=this.ovmap.getResolution();var center=this.ovmap.getExtent().getCenterLonLat();var delta_x=overviewMapPx.x-(size.w/2);var delta_y=overviewMapPx.y-(size.h/2);return new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);},getOverviewPxFromLonLat:function(lonlat){var res=this.ovmap.getResolution();var extent=this.ovmap.getExtent();var px=null;if(extent){px=new OpenLayers.Pixel(Math.round(1/res*(lonlat.lon-extent.left)),Math.round(1/res*(extent.top-lonlat.lat)));}
-return px;},CLASS_NAME:'OpenLayers.Control.OverviewMap'});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;if(control.map){this.setMap(control.map);}
-OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
-var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
-this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
-this.active=false;return true;},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,events:null,div:null,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,zoom:0,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:'auto',numZoomLevels:16,theme:null,fallThrough:false,initialize:function(div,options){this.setOptions(options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{OpenLayers.Event.observe(window,'resize',OpenLayers.Function.bind(this.updateSize,this));}
-if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0;i<nodes.length;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
-if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
-this.layers=[];if(this.controls==null){if(OpenLayers.Control!=null){this.controls=[new OpenLayers.Control.Navigation(),new OpenLayers.Control.PanZoom(),new OpenLayers.Control.ArgParser(),new OpenLayers.Control.Attribution()];}else{this.controls=[];}}
-for(var i=0;i<this.controls.length;i++){this.addControlToMap(this.controls[i]);}
-this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);},unloadDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
-OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
-this.layers=null;}
-if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
-this.controls=null;}
-if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);}
-this.viewPortDiv=null;this.events.destroy();this.events=null;},setOptions:function(options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);},getTileSize:function(){return this.tileSize;},getLayer:function(id){var foundLayer=null;for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;}}
-return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
-+zIdx*5);},addLayer:function(layer){for(var i=0;i<this.layers.length;i++){if(this.layers[i]==layer){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",layer.name));return false;}}
-layer.div.style.overflow="";this.setLayerZIndex(layer,this.layers.length);if(layer.isFixed){this.viewPortDiv.appendChild(layer.div);}else{this.layerContainerDiv.appendChild(layer.div);}
-this.layers.push(layer);layer.setMap(this);if(layer.isBaseLayer){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
-this.events.triggerEvent("addlayer");},addLayers:function(layers){for(var i=0;i<layers.length;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
-if(layer.isFixed){this.viewPortDiv.removeChild(layer.div);}else{this.layerContainerDiv.removeChild(layer.div);}
-OpenLayers.Util.removeItem(this.layers,layer);layer.removeMap(this);layer.map=null;if(setNewBaseLayer&&(this.baseLayer==layer)){this.baseLayer=null;for(i=0;i<this.layers.length;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer){this.setBaseLayer(iLayer);break;}}}
-this.events.triggerEvent("removelayer");},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},setLayerIndex:function(layer,idx){var base=this.getLayerIndex(layer);if(idx<0){idx=0;}else if(idx>this.layers.length){idx=this.layers.length;}
-if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0;i<this.layers.length;i++){this.setLayerZIndex(this.layers[i],i);}
-this.events.triggerEvent("changelayer");}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){var oldExtent=null;if(this.baseLayer){oldExtent=this.baseLayer.getExtent();}
-if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){if(this.baseLayer!=null){this.baseLayer.setVisibility(false);}
-this.baseLayer=newBaseLayer;this.maxExtent=newBaseLayer.maxExtent;this.minExtent=newBaseLayer.minExtent;this.maxScale=newBaseLayer.maxScale;this.minScale=newBaseLayer.minScale;this.maxResolution=newBaseLayer.maxResolution;this.minResolution=newBaseLayer.minResolution;this.units=newBaseLayer.units;this.projection=newBaseLayer.projection;this.viewRequestID++;this.baseLayer.visibility=true;var center=this.getCenter();if(center!=null){if(oldExtent==null){this.setCenter(center,this.getZoom(),false,true);}else{this.setCenter(oldExtent.getCenterLonLat(),this.getZoomForExtent(oldExtent),false,true);}}
-this.events.triggerEvent("changebaselayer");}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);control.setMap(this);var div=control.draw(px);if(div){if(!control.outsideViewport){div.style.zIndex=this.Z_INDEX_BASE['Control']+
-this.controls.length;this.viewPortDiv.appendChild(div);}}},getControl:function(id){var returnControl=null;for(var i=0;i<this.controls.length;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
-return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(!control.outsideViewport){this.viewPortDiv.removeChild(control.div)}
-OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=0;i<this.popups.length;i++){this.removePopup(this.popups[i]);}}
-popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+
-this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);}
-catch(e){}}
-popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();}
-return size;},updateSize:function(){this.events.element.offsets=null;var newSize=this.getCurrentSize();var oldSize=this.getSize();if(oldSize==null)
-this.size=oldSize=newSize;if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0;i<this.layers.length;i++){this.layers[i].onMapResize();}
-if(this.baseLayer!=null){var center=new OpenLayers.Pixel(newSize.w/2,newSize.h/2);var centerLL=this.getLonLatFromViewPortPx(center);var zoom=this.getZoom();this.zoom=null;this.setCenter(this.getCenter(),zoom);}}},getCurrentSize:function(){var size=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){var dim=OpenLayers.Element.getDimensions(this.div);size.w=dim.width;size.h=dim.height;}
-if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=parseInt(this.div.style.width);size.h=parseInt(this.div.style.height);}
-return size;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCenter();}
-if(resolution==null){resolution=this.getResolution();}
-if((center!=null)&&(resolution!=null)){var size=this.getSize();var w_deg=size.w*resolution;var h_deg=size.h*resolution;extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);}
-return extent;},getCenter:function(){return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy){var centerPx=this.getViewPortPxFromLonLat(this.getCenter());var newCenterPx=centerPx.add(dx,dy);if(!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);this.setCenter(newCenterLonLat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){if(!this.center&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();}
-if(this.restrictedExtent&&this.restrictedExtent!='auto'){if(lonlat==null){lonlat=this.getCenter();}
-if(zoom==null){zoom=this.getZoom();}
-var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.resolutions[zoom];}
-var extent=this.calculateBounds(lonlat,resolution);if(!this.restrictedExtent.containsBounds(extent)){var maxCenter=this.restrictedExtent.getCenterLonLat();if(extent.getWidth()>this.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.left<this.restrictedExtent.left){lonlat=lonlat.add(this.restrictedExtent.left-
-extent.left,0);}else if(extent.right>this.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right-
-extent.right,0);}
-if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottom<this.restrictedExtent.bottom){lonlat=lonlat.add(0,this.restrictedExtent.bottom-
-extent.bottom);}
-else if(extent.top>this.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top-
-extent.top);}}}
-var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=!lonlat.equals(this.center);if(this.restrictedExtent=='auto'){centerChanged=this.isValidLonLat(lonlat)&&centerChanged;}
-if(zoomChanged||centerChanged||!dragging){if(!dragging){this.events.triggerEvent("movestart");}
-if(centerChanged){if((!zoomChanged)&&(this.center)){this.centerLayerContainer(lonlat);}
-this.center=lonlat.clone();}
-if((zoomChanged)||(this.layerContainerOrigin==null)){this.layerContainerOrigin=this.center.clone();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";}
-if(zoomChanged){this.zoom=zoom;this.viewRequestID++;}
-var bounds=this.getExtent();this.baseLayer.moveTo(bounds,zoomChanged,dragging);bounds=this.baseLayer.getExtent();for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(!layer.isBaseLayer){var moveLayer;var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;moveLayer=true;this.events.triggerEvent("changelayer");}else{moveLayer=(layer.visibility&&layer.inRange);}
-if(moveLayer){layer.moveTo(bounds,zoomChanged,dragging);}}}
-if(zoomChanged){for(var i=0;i<this.popups.length;i++){this.popups[i].updatePosition();}}
-this.events.triggerEvent("move");if(zoomChanged){this.events.triggerEvent("zoomend");}}
-if(!dragging){this.events.triggerEvent("moveend");}},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){this.layerContainerDiv.style.left=(originPx.x-newPx.x)+"px";this.layerContainerDiv.style.top=(originPx.y-newPx.y)+"px";}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();valid=maxExtent.containsLonLat(lonlat);}
-return valid;},getProjection:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
-return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
-return maxResolution;},getMaxExtent:function(){var maxExtent=null;if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
-return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
-return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
-return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}
-return resolution;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);}
-return scale;},getZoomForExtent:function(bounds){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds);}
-return zoom;},getZoomForResolution:function(resolution){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution);}
-return zoom;},zoomTo:function(zoom){if(this.isValidZoomLevel(zoom)){this.setCenter(null,zoom);}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds){var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
-center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
-this.setCenter(center,this.getZoomForExtent(bounds));},zoomToMaxExtent:function(){this.zoomToExtent(this.getMaxExtent());},zoomToScale:function(scale){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var size=this.getSize();var w_deg=size.w*res;var h_deg=size.h*res;var center=this.getCenter();var extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);this.zoomToExtent(extent);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
-return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){return this.getViewPortPxFromLonLat(lonlat);},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
-return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
-return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
-this.events=new OpenLayers.Events(this,this.icon.imageDiv,null);},destroy:function(){this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
-this.lonlat=this.map.getLonLatFromLayerPx(px);},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},inflate:function(inflate){if(this.icon){var newSize=new OpenLayers.Size(this.icon.size.w*inflate,this.icon.size.h*inflate);this.icon.setSize(newSize);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){var url=OpenLayers.Util.getImagesLocation()+"marker.png";var size=new OpenLayers.Size(21,25);var calculateOffset=function(size){return new OpenLayers.Pixel(-(size.w/2),-size.h);};return new OpenLayers.Icon(url,size,null,calculateOffset);};OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.frame=document.createElement('div');this.frame.style.overflow='hidden';this.frame.style.position='absolute';},destroy:function(){if(this.imgDiv!=null){OpenLayers.Event.stopObservingElement(this.imgDiv.id);if(this.imgDiv.parentNode==this.frame){this.frame.removeChild(this.imgDiv);this.imgDiv.map=null;}}
-this.imgDiv=null;if((this.frame!=null)&&(this.frame.parentNode==this.layer.div)){this.layer.div.removeChild(this.frame);}
-this.frame=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
-if(!OpenLayers.Tile.prototype.draw.apply(this,arguments)){return false;}
-if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
-if(this.imgDiv==null){this.initImgDiv();}
-this.imgDiv.viewRequestID=this.layer.map.viewRequestID;this.url=this.layer.getURL(this.bounds);OpenLayers.Util.modifyDOMElement(this.frame,null,this.position,this.size);var imageSize=this.layer.getImageSize();if(this.layer.alpha){OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,null,null,imageSize,this.url);}else{this.imgDiv.src=this.url;OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,imageSize);}
-return true;},clear:function(){if(this.imgDiv){this.imgDiv.style.display="none";}},initImgDiv:function(){var offset=this.layer.imageOffset;var size=this.layer.getImageSize();if(this.layer.alpha){this.imgDiv=OpenLayers.Util.createAlphaImageDiv(null,offset,size,null,"relative",null,null,null,true);}else{this.imgDiv=OpenLayers.Util.createImage(null,offset,size,null,"relative",null,null,true);}
-this.imgDiv.className='olTileImage';this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
-this.imgDiv.map=this.layer.map;var onload=function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}}
-OpenLayers.Event.observe(this.imgDiv,'load',OpenLayers.Function.bind(onload,this));},checkImgURL:function(){if(this.layer){var loaded=this.layer.alpha?this.imgDiv.firstChild.src:this.imgDiv.src;if(!OpenLayers.Util.isEquivalentUrl(loaded,this.url)){this.imgDiv.style.display="none";}}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,dragging:false,last:null,start:null,oldOnselectstart:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&OpenLayers.Event.isLeftClick(evt)){this.started=true;this.start=evt.xy;this.last=evt.xy;this.map.div.style.cursor="move";this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
-propagate=false;}else{this.started=false;this.start=null;this.last=null;}
-return propagate;},mousemove:function(evt){if(this.started){if(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y){this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
-this.last=evt.xy;}}
-return true;},mouseup:function(evt){if(this.started){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.up(evt);this.callback("up",[evt.xy]);this.callback("done",[evt.xy]);document.onselectstart=this.oldOnselectstart;}
-return true;},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.div)){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.out(evt);this.callback("out",[]);if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}
-this.callback("done",[evt.xy])}
-return true;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;}
-return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;}
-return deactivated;},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null;},onWheelEvent:function(e){if(!this.checkModifiers(e))return;var inMap=false;var elem=OpenLayers.Event.element(e);while(elem!=null){if(this.map&&elem==this.map.div){inMap=true;break;}
-elem=elem.parentNode;}
-if(inMap){var delta=0;if(!e){e=window.event;}
-if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
-if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
-if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
-if(delta<0){this.callback("down",[e,delta]);}else{this.callback("up",[e,delta]);}}
-OpenLayers.Event.stop(e);}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,EVENT_TYPES:["loadstart","loadend","loadcancel","visibilitychanged"],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,imageOffset:null,options:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:false,wrapDateLine:false,initialize:function(name,options){this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv();this.div.style.width="100%";this.div.style.height="100%";this.div.id=this.id;this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES);}
-if(this.wrapDateLine){this.displayOutsideMaxExtent=true;}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
-if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
-this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){this.events.destroy();}
-this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.options);}
-OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer");}}},addOptions:function(newOptions){if(this.options==null){this.options={};}
-OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){this.moveTo(extent,true,false);redrawn=true;}}
-return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
-this.display(display);},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.projection=this.projection||this.map.projection;if(this.projection&&typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
-this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";}
-this.setTileSize();}},removeMap:function(map){},getImageSize:function(){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageOffset=new OpenLayers.Pixel(-this.gutter,-this.gutter);this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer");}
-this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display)?"block":"none";}},calculateInRange:function(){var inRange=false;if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}
-return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changelayer");}}},initResolutions:function(){var props=new Array('projection','units','scales','resolutions','maxScale','minScale','maxResolution','minResolution','minExtent','maxExtent','numZoomLevels','maxZoomLevel');var confProps={};for(var i=0;i<props.length;i++){var property=props[i];confProps[property]=this.options[property]||this.map[property];}
-if((!confProps.numZoomLevels)&&(confProps.maxZoomLevel)){confProps.numZoomLevels=confProps.maxZoomLevel+1;}
-if((confProps.scales!=null)||(confProps.resolutions!=null)){if(confProps.scales!=null){confProps.resolutions=[];for(var i=0;i<confProps.scales.length;i++){var scale=confProps.scales[i];confProps.resolutions[i]=OpenLayers.Util.getResolutionFromScale(scale,confProps.units);}}
-confProps.numZoomLevels=confProps.resolutions.length;}else{confProps.resolutions=[];if(confProps.minScale){confProps.maxResolution=OpenLayers.Util.getResolutionFromScale(confProps.minScale,confProps.units);}else if(confProps.maxResolution=="auto"){var viewSize=this.map.getSize();var wRes=confProps.maxExtent.getWidth()/viewSize.w;var hRes=confProps.maxExtent.getHeight()/viewSize.h;confProps.maxResolution=Math.max(wRes,hRes);}
-if(confProps.maxScale!=null){confProps.minResolution=OpenLayers.Util.getResolutionFromScale(confProps.maxScale);}else if((confProps.minResolution=="auto")&&(confProps.minExtent!=null)){var viewSize=this.map.getSize();var wRes=confProps.minExtent.getWidth()/viewSize.w;var hRes=confProps.minExtent.getHeight()/viewSize.h;confProps.minResolution=Math.max(wRes,hRes);}
-if(confProps.minResolution!=null){var ratio=confProps.maxResolution/confProps.minResolution;confProps.numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}
-for(var i=0;i<confProps.numZoomLevels;i++){var res=confProps.maxResolution/Math.pow(2,i)
-confProps.resolutions.push(res);}}
-confProps.resolutions.sort(function(a,b){return(b-a);});this.resolutions=confProps.resolutions;this.maxResolution=confProps.resolutions[0];var lastIndex=confProps.resolutions.length-1;this.minResolution=confProps.resolutions[lastIndex];this.scales=[];for(var i=0;i<confProps.resolutions.length;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],confProps.units);}
-this.minScale=this.scales[0];this.maxScale=this.scales[this.scales.length-1];this.numZoomLevels=confProps.numZoomLevels;},getResolution:function(){var zoom=this.map.getZoom();return this.resolutions[zoom];},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution);},getDataExtent:function(){},getZoomForResolution:function(resolution){var zoom,diff;var minDiff=Number.POSITIVE_INFINITY;for(var i=0;i<this.resolutions.length;i++){diff=Math.abs(this.resolutions[i]-resolution);if(diff<minDiff){zoom=i;minDiff=diff;}else if(diff>minDiff){break;}}
-return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(viewPortPx!=null){var size=this.map.getSize();var center=this.map.getCenter();if(center){var res=this.map.getResolution();var delta_x=viewPortPx.x-(size.w/2);var delta_y=viewPortPx.y-(size.h/2);lonlat=new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(lonlat!=null){var resolution=this.map.getResolution();var extent=this.map.getExtent();px=new OpenLayers.Pixel(Math.round(1/resolution*(lonlat.lon-extent.left)),Math.round(1/resolution*(extent.top-lonlat.lat)));}
-return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0;i<this.div.childNodes.length;++i){var element=this.div.childNodes[i].firstChild;OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}}},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){var mapGutter=this.gutter*this.map.getResolution();bounds=new OpenLayers.Bounds(bounds.left-mapGutter,bounds.bottom-mapGutter,bounds.right+mapGutter,bounds.top+mapGutter);}
-if(this.wrapDateLine){var wrappingOptions={'rightTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
-return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(bounds,borderColor,borderWidth){this.bounds=bounds;this.div=OpenLayers.Util.createDiv();this.div.style.overflow='hidden';this.events=new OpenLayers.Events(this,this.div,null);this.setBorder(borderColor,borderWidth);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
-if(!width){width=2;}
-this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
-return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},panMap:function(xy){this.panned=true;var deltaX=this.handler.last.x-xy.x;var deltaY=this.handler.last.y-xy.y;var size=this.map.getSize();var newXY=new OpenLayers.Pixel(size.w/2+deltaX,size.h/2+deltaY);var newCenter=this.map.getLonLatFromViewPortPx(newXY);this.map.setCenter(newCenter,null,this.handler.dragging);},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);var callbacks={"down":this.startBox,"move":this.moveBox,"out":this.removeBox,"up":this.endBox};this.dragHandler=new OpenLayers.Handler.Drag(this,callbacks,{keyMask:this.keyMask});},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.dragHandler.start,null,null,"absolute","2px solid red");this.zoomBox.style.backgroundColor="white";this.zoomBox.style.filter="alpha(opacity=50)";this.zoomBox.style.opacity="0.50";this.zoomBox.style.fontSize="1px";this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);this.map.div.style.cursor="crosshair";},moveBox:function(xy){var deltaX=Math.abs(this.dragHandler.start.x-xy.x);var deltaY=Math.abs(this.dragHandler.start.y-xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(xy.x<this.dragHandler.start.x){this.zoomBox.style.left=xy.x+"px";}
-if(xy.y<this.dragHandler.start.y){this.zoomBox.style.top=xy.y+"px";}},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
-this.removeBox();this.map.div.style.cursor="";this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragHandler.deactivate();return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){var newArguments=arguments;newArguments=[name,options];OpenLayers.Layer.prototype.initialize.apply(this,newArguments);this.url=url;this.params=OpenLayers.Util.extend({},params);},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);this.redraw();},selectUrl:function(paramString,urls){var product=1;for(var i=0;i<paramString.length;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
-return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
-var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);this.map.zoomToExtent(bounds);}else{this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()+1);}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,grid:null,singleTile:false,ratio:1.5,buffer:2,numLoadingTiles:0,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.events.addEventType("tileloaded");this.grid=[];},destroy:function(){this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0;iRow<this.grid.length;iRow++){var row=this.grid[iRow];for(var iCol=0;iCol<row.length;iCol++){var tile=row[iCol];this.removeTileMonitoringHooks(tile);tile.destroy();}}
-this.grid=[];}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
-obj.grid=[];return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){this.initSingleTile(bounds);}}else{if(forceReTile||!tilesBounds.containsBounds(bounds,true)){this.initGriddedTiles(bounds);}else{this.moveGriddedTiles(bounds);}}}},setTileSize:function(size){if(this.singleTile){var size=this.map.getSize().clone();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
-OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getGridBounds:function(){var msg="The getGridBounds() function is deprecated. It will be "+"removed in 3.0. Please use getTilesBounds() instead.";OpenLayers.Console.warn(msg);return this.getTilesBounds();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
-return bounds;},initSingleTile:function(bounds){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var px=this.map.getLayerPxFromLonLat(ul);if(!this.grid.length){this.grid[0]=[];}
-var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
-this.removeExcessTiles(1,1);},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
-Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
-Math.max(1,2*this.buffer);var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=bounds.top-(extent.bottom+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=extent.bottom+tilerow*tilelat;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
-tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;y-=parseInt(this.map.layerContainerDiv.style.top);var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
-tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
-tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
-this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},spiralTileLoad:function(){var tileQueue=[];var directions=["right","down","left","up"];var iRow=0;var iCell=-1;var direction=OpenLayers.Util.indexOf(directions,"right");var directionsTried=0;while(directionsTried<directions.length){var testRow=iRow;var testCell=iCell;switch(directions[direction]){case"right":testCell++;break;case"down":testRow++;break;case"left":testCell--;break;case"up":testRow--;break;}
-var tile=null;if((testRow<this.grid.length)&&(testRow>=0)&&(testCell<this.grid[0].length)&&(testCell>=0)){tile=this.grid[testRow][testCell];}
-if((tile!=null)&&(!tile.queued)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
-for(var i=0;i<tileQueue.length;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
-this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.events.unregister("loadstart",this,tile.onLoadStart);tile.events.unregister("loadend",this,tile.onLoadEnd);},moveGriddedTiles:function(bounds){var buffer=this.buffer||1;while(true){var tlLayer=this.grid[0][0].position;var tlViewPort=this.map.getViewPortPxFromLayerPx(tlLayer);if(tlViewPort.x>-this.tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-this.tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-this.tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-this.tileSize.h*buffer){this.shiftRow(false);}else{break;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var modelRow=this.grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?this.grid.pop():this.grid.shift();for(var i=0;i<modelRow.length;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
-if(prepend){this.grid.unshift(row);}else{this.grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0;i<this.grid.length;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){this.grid[i].unshift(tile);}else{this.grid[i].push(tile);}}},removeExcessTiles:function(rows,columns){while(this.grid.length>rows){var row=this.grid.pop();for(var i=0,l=row.length;i<l;i++){var tile=row[i];this.removeTileMonitoringHooks(tile);tile.destroy();}}
-while(this.grid[0].length>columns){for(var i=0,l=this.grid.length;i<l;i++){var row=this.grid[i];var tile=row.pop();this.removeTileMonitoringHooks(tile);tile.destroy();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();this.initSingleTile(this.map.getExtent());}},getTileBounds:function(viewPortPx){var maxExtent=this.map.getMaxExtent();var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=maxExtent.left+(tileMapWidth*Math.floor((mapPoint.lon-
-maxExtent.left)/tileMapWidth));var tileBottom=maxExtent.bottom+(tileMapHeight*Math.floor((mapPoint.lat-
-maxExtent.bottom)/tileMapHeight));return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,wheelHandler:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},activate:function(){this.dragPan.activate();this.wheelHandler.activate();this.zoomBox.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){this.zoomBox.deactivate();this.dragPan.deactivate();this.wheelHandler.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){this.map.events.register("dblclick",this,this.defaultDblClick);this.dragPan=new OpenLayers.Control.DragPan({map:this.map});this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:OpenLayers.Handler.MOD_SHIFT});this.dragPan.draw();this.zoomBox.draw();this.wheelHandler=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown});this.activate();},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);OpenLayers.Event.stop(evt);return false;},wheelChange:function(evt,deltaZ){var newZoom=this.map.getZoom()+deltaZ;if(!this.map.isValidZoomLevel(newZoom))return;var size=this.map.getSize();var deltaX=size.w/2-evt.xy.x;var deltaY=evt.xy.y-size.h/2;var newRes=this.map.baseLayer.resolutions[newZoom];var zoomPoint=this.map.getLonLatFromPixel(evt.xy);var newCenter=new OpenLayers.LonLat(zoomPoint.lon+deltaX*newRes,zoomPoint.lat+deltaY*newRes);this.map.setCenter(newCenter,newZoom);},wheelUp:function(evt){this.wheelChange(evt,1);},wheelDown:function(evt){this.wheelChange(evt,-1);},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{reproject:false,isBaseLayer:true,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',version:'1.0.0'},session:null,mapName:null,groupName:null,initialize:function(name,url,params,options){var newArguments=new Array();newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}
-if(arguments.length>0){if(this.options.singleTile){this.session=params.session;this.mapName=params.mapname;OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);if(!this.isBaseLayer){this.params.operation="GETDYNAMICMAPOVERLAYIMAGE";}}else{this.groupName=params.groupname;OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);this.setTileSize(new OpenLayers.Size(300,300));}}},updateExtents:function(a){var center=this.map.getExtent().getCenterLonLat();var mapSize=this.map.getCurrentSize();var sParams="operation=GETVISIBLEMAPEXTENT&version=1.0.0";sParams+="&session="+this.session;sParams+="&mapname="+this.mapName;sParams+="&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;sParams+="&setdisplayheight="+mapSize.h*this.ratio;sParams+="&setdisplaywidth="+mapSize.w*this.ratio;sParams+="&setviewcenterx="+center.lon;sParams+="&setviewcentery="+center.lat;sParams+="&setviewscale="+this.map.getScale();if(this.options.showLayers)sParams+="&showlayers="+this.options.showLayers;if(this.options.hideLayers)sParams+="&hidelayers="+this.options.hideLayers;if(this.options.showGroups)sParams+="&showgroups="+this.options.showGroups;if(this.options.hideGroups)sParams+="&hidegroups="+this.options.hideGroups;if(this.options.refreshLayers)sParams+="&refreshlayers="+this.options.refreshLayers;sParams+="&ts="+(new Date()).getTime();new OpenLayers.Ajax.Request(this.url,{parameters:sParams,onSuccess:this._getExtentSuccess,onFailure:this._getExtentFailure,asynchronous:false});},_getExtentSuccess:function(transport){var temp=transport.responseXML;},_getExtentFailure:function(r){},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},getURL:function(bounds){var center=bounds.getCenterLonLat();var mapSize=this.map.getCurrentSize();if(this.options.singleTile){var params={};params.session=this.session;params.mapname=this.mapName;if(this.isBaseLayer){params.locale="en";params.setdisplaydpi=OpenLayers.DOTS_PER_INCH;params.setdisplayheight=mapSize.h*this.ratio;params.setdisplaywidth=mapSize.w*this.ratio;params.setviewcenterx=center.lon;params.setviewcentery=center.lat;params.setviewscale=this.map.getScale();if(this.options.showLayers)params.showlayers=this.options.showLayers;if(this.options.hideLayers)params.hidelayers=this.options.hideLayers;if(this.options.showGroups)params.showgroups=this.options.showGroups;if(this.options.hideGroups)params.hidegroups=this.options.hideGroups;if(this.options.refreshLayers)params.refreshlayers=this.options.refreshLayers;}else{this.updateExtents();}
-params.ts=(new Date()).getTime();var url=this.getFullRequestString(params);}else{var currentRes=this.map.getResolution();var colidx=Math.floor((bounds.left-this.maxExtent.left)/currentRes);colidx=Math.round(colidx/this.tileSize.w);var rowidx=Math.floor((this.maxExtent.top-bounds.top)/currentRes);rowidx=Math.round(rowidx/this.tileSize.h);var url=this.getFullRequestString({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}
-return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
-var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getArgs(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+1;var minCols=Math.ceil(viewSize.w/this.tileSize.w)+1;var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
-tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
-tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
-tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
-this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
-if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
-var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
-if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();return this.getFullRequestString({BBOX:this.encodeBBOX?bounds.toBBOX():bounds.toArray(),WIDTH:imageSize.w,HEIGHT:imageSize.h});},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams){var projection=this.map.getProjection();this.params.SRS=(projection=="none")?null:projection.getCode();return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});
\ No newline at end of file
+OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){var scriptLocation="";var scriptName=OpenLayers._scriptName;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptName.length==src.length)){scriptLocation=src.slice(0,-scriptName.length);break;}}}
+return scriptLocation;}};if(!singleFile){var jsfiles=new Array("OpenLayers/Util.js","OpenLayers/BaseTypes.js","OpenLayers/BaseTypes/Class.js","OpenLayers/BaseTypes/Bounds.js","OpenLayers/BaseTypes/Element.js","OpenLayers/BaseTypes/LonLat.js","OpenLayers/BaseTypes/Pixel.js","OpenLayers/BaseTypes/Size.js","OpenLayers/Console.js","Rico/Corner.js","Rico/Color.js","OpenLayers/Ajax.js","OpenLayers/Events.js","OpenLayers/Map.js","OpenLayers/Layer.js","OpenLayers/Icon.js","OpenLayers/Marker.js","OpenLayers/Marker/Box.js","OpenLayers/Popup.js","OpenLayers/Tile.js","OpenLayers/Tile/Image.js","OpenLayers/Tile/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.js","OpenLayers/Layer/VirtualEarth.js","OpenLayers/Layer/Yahoo.js","OpenLayers/Layer/HTTPRequest.js","OpenLayers/Layer/Grid.js","OpenLayers/Layer/MapServer.js","OpenLayers/Layer/MapGuide.js","OpenLayers/Layer/MapServer/Untiled.js","OpenLayers/Layer/KaMap.js","OpenLayers/Layer/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.js","OpenLayers/Feature.js","OpenLayers/Feature/Vector.js","OpenLayers/Feature/WFS.js","OpenLayers/Handler.js","OpenLayers/Handler/Point.js","OpenLayers/Handler/Path.js","OpenLayers/Handler/Polygon.js","OpenLayers/Handler/Feature.js","OpenLayers/Handler/Drag.js","OpenLayers/Handler/RegularPolygon.js","OpenLayers/Handler/Box.js","OpenLayers/Handler/MouseWheel.js","OpenLayers/Handler/Keyboard.js","OpenLayers/Control.js","OpenLayers/Control/Attribution.js","OpenLayers/Control/ZoomBox.js","OpenLayers/Control/ZoomToMaxExtent.js","OpenLayers/Control/DragPan.js","OpenLayers/Control/Navigation.js","OpenLayers/Control/MouseDefaults.js","OpenLayers/Control/MousePosition.js","OpenLayers/Control/OverviewMap.js","OpenLayers/Control/KeyboardDefaults.js","OpenLayers/Control/PanZoom.js","OpenLayers/Control/PanZoomBar.js","OpenLayers/Control/ArgParser.js","OpenLayers/Control/Permalink.js","OpenLayers/Control/Scale.js","OpenLayers/Control/LayerSwitcher.js","OpenLayers/Control/DrawFeature.js","OpenLayers/Control/DragFeature.js","OpenLayers/Control/ModifyFeature.js","OpenLayers/Control/Panel.js","OpenLayers/Control/SelectFeature.js","OpenLayers/Geometry.js","OpenLayers/Geometry/Rectangle.js","OpenLayers/Geometry/Collection.js","OpenLayers/Geometry/Point.js","OpenLayers/Geometry/MultiPoint.js","OpenLayers/Geometry/Curve.js","OpenLayers/Geometry/LineString.js","OpenLayers/Geometry/LinearRing.js","OpenLayers/Geometry/Polygon.js","OpenLayers/Geometry/MultiLineString.js","OpenLayers/Geometry/MultiPolygon.js","OpenLayers/Geometry/Surface.js","OpenLayers/Renderer.js","OpenLayers/Renderer/Elements.js","OpenLayers/Renderer/SVG.js","OpenLayers/Renderer/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/GML.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/JSON.js","OpenLayers/Format/GeoJSON.js","OpenLayers/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Projection.js","OpenLayers/Strings/en.js");var allScriptTags="";var host=OpenLayers._getScriptLocation()+"lib/";for(var i=0;i<jsfiles.length;i++){if(/MSIE/.test(navigator.userAgent)||/Safari/.test(navigator.userAgent)){var currentScriptTag="<script src='"+host+jsfiles[i]+"'></script>";allScriptTags+=currentScriptTag;}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}}
+if(allScriptTags)document.write(allScriptTags);}})();OpenLayers.VERSION_NUMBER="$Revision$";OpenLayers.Util={};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0;i<arguments.length;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
+if(arguments.length==1){return element;}
+elements.push(element);}
+return elements;};if($==null){var $=OpenLayers.Util.getElement;}
+OpenLayers.Util.extend=function(destination,source){if(destination&&source){for(var property in source){destination[property]=source[property];}
+if(source.hasOwnProperty&&source.hasOwnProperty('toString')){destination.toString=source.toString;}}
+return destination;};OpenLayers.Util.removeItem=function(array,item){for(var i=0;i<array.length;i++){if(array[i]==item){array.splice(i,1);}}
+return array;};OpenLayers.Util.clearArray=function(array){var msg=OpenLayers.String.translate("clearArrayDeprecated");OpenLayers.Console.warn(msg);array.length=0;};OpenLayers.Util.indexOf=function(array,obj){for(var i=0;i<array.length;i++){if(array[i]==obj)return i;}
+return-1;};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
+if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
+if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
+if(position){element.style.position=position;}
+if(border){element.style.border=border;}
+if(overflow){element.style.overflow=overflow;}
+if(opacity){element.style.opacity=opacity;element.style.filter='alpha(opacity='+(opacity*100)+')';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';}
+if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
+if(!position){position="absolute";}
+OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
+if(!position){position="relative";}
+OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";OpenLayers.Event.observe(image,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,image));OpenLayers.Event.observe(image,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,image));}
+image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
+return image;};OpenLayers.Util.setOpacity=function(element,opacity){OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
+OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||(this.map&&this.viewRequestID==this.map.viewRequestID)){this.style.backgroundColor=null;this.style.display="";}};OpenLayers.Util.onImageLoadErrorColor="pink";OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.onImageLoadError=function(){this._attempts=(this._attempts)?(this._attempts+1):1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.src=this.src;}else{this.style.backgroundColor=OpenLayers.Util.onImageLoadErrorColor;}
+this.style.display="";};OpenLayers.Util.alphaHack=function(){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=document.body.filters;}catch(e){}
+return(filter&&(version>=5.5)&&(version<7));}
+OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
+OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(opacity){div.style.opacity=opacity;div.style.filter='alpha(opacity='+(opacity*100)+')';}
+if(OpenLayers.Util.alphaHack()){div.style.display="inline-block";if(sizing==null){sizing="scale";}
+div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(div.style.opacity){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
+img.style.filter="progid:DXImageTransform.Microsoft"+".Alpha(opacity=0)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,false);div.appendChild(img);if(delayDisplay){img.style.display="none";OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,div));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,div));}
+OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];}
+return uObject;};OpenLayers.Util.applyDefaults=function(to,from){for(var key in from){if(to[key]==null){to[key]=from[key];}}};OpenLayers.Util.getParameterString=function(params){paramsArray=[];for(var key in params){var value=params[key];if((value!=null)&&(typeof value!='function')){var encodedValue;if(typeof value=='object'&&value.constructor==Array){var encodedItemArray=[];for(var itemIndex=0;itemIndex<value.length;itemIndex++){encodedItemArray.push(encodeURIComponent(value[itemIndex]));}
+encodedValue=encodedItemArray.join(",");}
+else{encodedValue=encodeURIComponent(value);}
+paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
+return paramsArray.join("&");};OpenLayers.ImgPath='';OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0;i<arguments.length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
+return returnValue;}
+OpenLayers.Util.getNodes=function(p,tagName){var nodes=OpenLayers.Util.Try(function(){return OpenLayers.Util._getNodes(p.documentElement.childNodes,tagName);},function(){return OpenLayers.Util._getNodes(p.childNodes,tagName);});return nodes;};OpenLayers.Util._getNodes=function(nodes,tagName){var retArray=[];for(var i=0;i<nodes.length;i++){if(nodes[i].nodeName==tagName){retArray.push(nodes[i]);}}
+return retArray;};OpenLayers.Util.getTagText=function(parent,item,index){var result=OpenLayers.Util.getNodes(parent,item);if(result&&(result.length>0))
+{if(!index){index=0;}
+if(result[index].childNodes.length>1){return result.childNodes[1].nodeValue;}
+else if(result[index].childNodes.length==1){return result[index].firstChild.nodeValue;}}else{return"";}};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val)
+val=node.textContent;if(!val)
+val=node.firstChild.nodeValue;},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
+return(target!=div);};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.distVincenty=function(p1,p2){var a=6378137,b=6356752.3142,f=1/298.257223563;var L=OpenLayers.Util.rad(p2.lon-p1.lon);var U1=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p1.lat)));var U2=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p2.lat)));var sinU1=Math.sin(U1),cosU1=Math.cos(U1);var sinU2=Math.sin(U2),cosU2=Math.cos(U2);var lambda=L,lambdaP=2*Math.PI;var iterLimit=20;while(Math.abs(lambda-lambdaP)>1e-12&&--iterLimit>0){var sinLambda=Math.sin(lambda),cosLambda=Math.cos(lambda);var sinSigma=Math.sqrt((cosU2*sinLambda)*(cosU2*sinLambda)+
+(cosU1*sinU2-sinU1*cosU2*cosLambda)*(cosU1*sinU2-sinU1*cosU2*cosLambda));if(sinSigma==0)return 0;var cosSigma=sinU1*sinU2+cosU1*cosU2*cosLambda;var sigma=Math.atan2(sinSigma,cosSigma);var alpha=Math.asin(cosU1*cosU2*sinLambda/sinSigma);var cosSqAlpha=Math.cos(alpha)*Math.cos(alpha);var cos2SigmaM=cosSigma-2*sinU1*sinU2/cosSqAlpha;var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));lambdaP=lambda;lambda=L+(1-C)*f*Math.sin(alpha)*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));}
+if(iterLimit==0)return NaN
+var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));var s=b*A*(sigma-deltaSigma);var d=s.toFixed(3)/1000;return d;};OpenLayers.Util.getParameters=function(url){url=url||window.location.href
+if(url==null){url=window.location.href;}
+var paramsString="";if(OpenLayers.String.contains(url,'?')){var start=url.indexOf('?')+1;var end=OpenLayers.String.contains(url,"#")?url.indexOf('#'):url.length;paramsString=url.substring(start,end);}
+var parameters={};var pairs=paramsString.split(/[&;]/);for(var i=0;i<pairs.length;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=decodeURIComponent(keyValue[0]);var value=keyValue[1]||'';value=value.split(",");for(var j=0;j<value.length;j++){value[j]=decodeURIComponent(value[j]);}
+if(value.length==1){value=value[0];}
+parameters[key]=value;}}
+return parameters;};OpenLayers.Util.getArgs=function(url){var err=OpenLayers.String.translate("getArgsDeprecated");OpenLayers.Console.warn(err);return OpenLayers.Util.getParameters(url);};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
+OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){if(units==null){units="degrees";}
+var normScale=OpenLayers.Util.normalizeScale(scale);var resolution=1/(normScale*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH);return resolution;};OpenLayers.Util.getScaleFromResolution=function(resolution,units){if(units==null){units="degrees";}
+var scale=resolution*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH;return scale;};OpenLayers.Util.safeStopPropagation=function(evt){OpenLayers.Event.stop(evt,true);};OpenLayers.Util.pagePosition=function(forElement){var valueT=0,valueL=0;var element=forElement;var child=forElement;while(element){if(element==document.body){if(OpenLayers.Element.getStyle(child,'position')=='absolute'){break;}}
+valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;child=element;try{element=element.offsetParent;}catch(e){OpenLayers.Console.error(OpenLayers.String.translate("pagePositionFailed",element.id));break;}}
+element=forElement;while(element){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;element=element.parentNode;}
+return[valueL,valueT];};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true});urlObj1=OpenLayers.Util.createUrlObject(url1,options);urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(options.test){alert(key+"\n1:"+urlObj1[key]+"\n2:"+urlObj2[key]);}
+var val1=urlObj1[key];var val2=urlObj2[key];switch(key){case"args":break;case"host":case"port":case"protocol":if((val1=="")||(val2=="")){break;}
+default:if((key!="args")&&(urlObj1[key]!=urlObj2[key])){return false;}
+break;}}
+for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;}
+delete urlObj2.args[key];}
+for(var key in urlObj2.args){return false;}
+return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};var urlObject={};if(options.ignoreCase){url=url.toLowerCase();}
+var a=document.createElement('a');a.href=url;urlObject.host=a.host;var port=a.port;if(port.length<=0){var newHostLength=urlObject.host.length-(port.length);urlObject.host=urlObject.host.substring(0,newHostLength);}
+urlObject.protocol=a.protocol;urlObject.port=((port=="80")&&(options.ignorePort80))?"":port;urlObject.hash=(options.ignoreHash)?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
+urlObject.args=OpenLayers.Util.getParameters(queryString);if(((urlObject.protocol=="file:")&&(url.indexOf("file:")!=-1))||((urlObject.protocol!="file:")&&(urlObject.host!=""))){urlObject.pathname=a.pathname;var qIndex=urlObject.pathname.indexOf("?");if(qIndex!=-1){urlObject.pathname=urlObject.pathname.substring(0,qIndex);}}else{var relStr=OpenLayers.Util.removeTail(url);var backs=0;do{var index=relStr.indexOf("../");if(index==0){backs++
+relStr=relStr.substr(3);}else if(index>=0){var prevChunk=relStr.substr(0,index-1);var slash=prevChunk.indexOf("/");prevChunk=(slash!=-1)?prevChunk.substr(0,slash+1):"";var postChunk=relStr.substr(index+3);relStr=prevChunk+postChunk;}}while(index!=-1)
+var windowAnchor=document.createElement("a");var windowUrl=window.location.href;if(options.ignoreCase){windowUrl=windowUrl.toLowerCase();}
+windowAnchor.href=windowUrl;urlObject.protocol=windowAnchor.protocol;var splitter=(windowAnchor.pathname.indexOf("/")!=-1)?"/":"\\";var dirs=windowAnchor.pathname.split(splitter);dirs.pop();while((backs>0)&&(dirs.length>0)){dirs.pop();backs--;}
+relStr=dirs.join("/")+"/"+relStr;urlObject.pathname=relStr;}
+if((urlObject.protocol=="file:")||(urlObject.protocol=="")){urlObject.host="localhost";}
+return urlObject;};OpenLayers.Util.removeTail=function(url){var head=null;var qMark=url.indexOf("?");var hashMark=url.indexOf("#");if(qMark==-1){head=(hashMark!=-1)?url.substr(0,hashMark):url;}else{head=(hashMark!=-1)?url.substr(0,Math.min(qMark,hashMark)):url.substr(0,qMark);}
+return head;};OpenLayers.Util.getBrowserName=function(){var browserName="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){browserName="opera";}else if(ua.indexOf("msie")!=-1){browserName="msie";}else if(ua.indexOf("safari")!=-1){browserName="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){browserName="firefox";}else{browserName="mozilla";}}
+return browserName;};OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s*(.*?)\s*$/,"$1");},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1;i<oStringList.length;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
+return camelizedString;},langCode:(OpenLayers.Util.getBrowserName()=="msie")?navigator.userLanguage.substring(0,2):navigator.language.substring(0,2),defaultLangCode:'en',translate:function(key){var langCode=OpenLayers.String.langCode;if(!OpenLayers.Strings[langCode]){var msg='failed to find '+OpenLayers.String.langCode+' dictionary, falling back to default language';OpenLayers.Console.log(msg);OpenLayers.Strings[langCode]=OpenLayers.Strings[OpenLayers.String.defaultLangCode];langCode=OpenLayers.String.defaultLangCode;}
+var dictionary=OpenLayers.Strings[langCode];var message="NoMsgsFound";var msgValue=dictionary[key];if(!msgValue){message=key;}else{message=msgValue;if(arguments[this.translate.length]){var varArgs=[].slice.call(arguments,this.translate.length);varArgs.unshift(message);message=this.formatMessage.apply(this,varArgs);}}
+return message;},formatMessage:function(messageTemplate)
+{var message=messageTemplate;var varArgs=[].slice.call(arguments,this.formatMessage.length);for(var i in varArgs){var parm=new RegExp("\\{"+i+"\\}","g");message=message.replace(parm,varArgs[i]);}
+return message;}};OpenLayers.Strings={};if(!String.prototype.startsWith){String.prototype.startsWith=function(sStart){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.startsWith"));return OpenLayers.String.startsWith(this,sStart);};}
+if(!String.prototype.contains){String.prototype.contains=function(str){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.contains"));return OpenLayers.String.contains(this,str);};}
+if(!String.prototype.trim){String.prototype.trim=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.trim"));return OpenLayers.String.trim(this);};}
+if(!String.prototype.camelize){String.prototype.camelize=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.camelize"));return OpenLayers.String.camelize(this);};}
+OpenLayers.Number={limitSigDigs:function(num,sig){var fig;if(sig>0){fig=parseFloat(num.toPrecision(sig));}else{fig=0;}
+return fig;}};if(!Number.prototype.limitSigDigs){Number.prototype.limitSigDigs=function(sig){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Number.limitSigDigs"));return OpenLayers.Number.limitSigDigs(this,sig);};}
+OpenLayers.Function={bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};}};if(!Function.prototype.bind){Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bind"));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments);};}
+if(!Function.prototype.bindAsEventListener){Function.prototype.bindAsEventListener=function(object){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bindAsEventListener"));return OpenLayers.Function.bindAsEventListener(this,object);};}
+OpenLayers.Class=function(){var Class=function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}}
+var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];}
+OpenLayers.Util.extend(extended,parent);}
+Class.prototype=extended;return Class;}
+OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype)
+this.initialize.apply(this,arguments);}}
+OpenLayers.Class.inherit=function(){var superClass=arguments[0];var proto=new superClass(OpenLayers.Class.isPrototype);for(var i=1;i<arguments.length;i++){if(typeof arguments[i]=="function"){var mixin=arguments[i];arguments[i]=new mixin(OpenLayers.Class.isPrototype);}
+OpenLayers.Util.extend(proto,arguments[i]);}
+return proto;}
+OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));}
+return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,initialize:function(left,bottom,right,top){if(left!=null){this.left=parseFloat(left);}
+if(bottom!=null){this.bottom=parseFloat(bottom);}
+if(right!=null){this.right=parseFloat(right);}
+if(top!=null){this.top=parseFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},equals:function(bounds){var equals=false;if(bounds!=null){equals=((this.left==bounds.left)&&(this.right==bounds.right)&&(this.top==bounds.top)&&(this.bottom==bounds.bottom));}
+return equals;},toString:function(){return("left-bottom=("+this.left+","+this.bottom+")"
++" right-top=("+this.right+","+this.top+")");},toArray:function(){return[this.left,this.bottom,this.right,this.top];},toBBOX:function(decimal){if(decimal==null){decimal=6;}
+var mult=Math.pow(10,decimal);var bbox=Math.round(this.left*mult)/mult+","+
+Math.round(this.bottom*mult)/mult+","+
+Math.round(this.right*mult)/mult+","+
+Math.round(this.top*mult)/mult;return bbox;},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){return new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("boundsAddError");OpenLayers.Console.error(msg);return null;}
+return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){switch(object.CLASS_NAME){case"OpenLayers.LonLat":bounds=new OpenLayers.Bounds(object.lon,object.lat,object.lon,object.lat);break;case"OpenLayers.Geometry.Point":bounds=new OpenLayers.Bounds(object.x,object.y,object.x,object.y);break;case"OpenLayers.Bounds":bounds=object;break;}
+if(bounds){if((this.left==null)||(bounds.left<this.left)){this.left=bounds.left;}
+if((this.bottom==null)||(bounds.bottom<this.bottom)){this.bottom=bounds.bottom;}
+if((this.right==null)||(bounds.right>this.right)){this.right=bounds.right;}
+if((this.top==null)||(bounds.top>this.top)){this.top=bounds.top;}}}},containsLonLat:function(ll,inclusive){return this.contains(ll.lon,ll.lat,inclusive);},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
+var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(x<this.right)&&(y>this.bottom)&&(y<this.top));}
+return contains;},intersectsBounds:function(bounds,inclusive){if(inclusive==null){inclusive=true;}
+var inBottom=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.bottom>this.bottom)&&(bounds.bottom<this.top))||((this.bottom>bounds.bottom)&&(this.bottom<bounds.top)));var inTop=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.top>this.bottom)&&(bounds.top<this.top))||((this.top>bounds.bottom)&&(this.top<bounds.top)));var inRight=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.right>this.left)&&(bounds.right<this.right))||((this.right>bounds.left)&&(this.right<bounds.right)));var inLeft=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.left>this.left)&&(bounds.left<this.right))||((this.left>bounds.left)&&(this.left<bounds.right)));return(this.containsBounds(bounds,true,inclusive)||bounds.containsBounds(this,true,inclusive)||((inTop||inBottom)&&(inLeft||inRight)));},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
+if(inclusive==null){inclusive=true;}
+var inLeft;var inTop;var inRight;var inBottom;if(inclusive){inLeft=(bounds.left>=this.left)&&(bounds.left<=this.right);inTop=(bounds.top>=this.bottom)&&(bounds.top<=this.top);inRight=(bounds.right>=this.left)&&(bounds.right<=this.right);inBottom=(bounds.bottom>=this.bottom)&&(bounds.bottom<=this.top);}else{inLeft=(bounds.left>this.left)&&(bounds.left<this.right);inTop=(bounds.top>this.bottom)&&(bounds.top<this.top);inRight=(bounds.right>this.left)&&(bounds.right<this.right);inBottom=(bounds.bottom>this.bottom)&&(bounds.bottom<this.top);}
+return(partial)?(inTop||inBottom)&&(inLeft||inRight):(inTop&&inLeft&&inBottom&&inRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat<center.lat)?"b":"t";quadrant+=(lonlat.lon<center.lon)?"l":"r";return quadrant;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){while(newBounds.left<maxExtent.left&&(newBounds.right-rightTolerance)<=maxExtent.left){newBounds=newBounds.add(maxExtent.getWidth(),0);}
+while((newBounds.left+leftTolerance)>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-maxExtent.getWidth(),0);}}
+return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds);};OpenLayers.Bounds.fromArray=function(bbox){return new OpenLayers.Bounds(parseFloat(bbox[0]),parseFloat(bbox[1]),parseFloat(bbox[2]),parseFloat(bbox[3]));};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'hide':'show';OpenLayers.Element[display](element);}},hide:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='none';}},show:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='';}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},getDimensions:function(element){element=OpenLayers.Util.getElement(element);if(OpenLayers.Element.getStyle(element,'display')!='none'){return{width:element.offsetWidth,height:element.offsetHeight};}
+var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;els.visibility='hidden';els.position='absolute';els.display='';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display='none';els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
+var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}
+return value=='auto'?null:value;}};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){this.lon=parseFloat(lon);this.lat=parseFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){var msg=OpenLayers.String.translate("lonlatAddError");OpenLayers.Console.error(msg);return null;}
+return new OpenLayers.LonLat(this.lon+lon,this.lat+lat);},equals:function(ll){var equals=false;if(ll!=null){equals=((this.lon==ll.lon&&this.lat==ll.lat)||(isNaN(this.lon)&&isNaN(this.lat)&&isNaN(ll.lon)&&isNaN(ll.lat)));}
+return equals;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
+while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
+return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(parseFloat(pair[0]),parseFloat(pair[1]));};OpenLayers.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));}
+return equals;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("pixelAddError");OpenLayers.Console.error(msg);return null;}
+return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
+return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.ProxyHost="";OpenLayers.nullHandler=function(request){alert(OpenLayers.String.translate("unhandledRequest",request.statusText));};OpenLayers.loadURL=function(uri,params,caller,onComplete,onFailure){if(OpenLayers.ProxyHost&&OpenLayers.String.startsWith(uri,"http")){uri=OpenLayers.ProxyHost+escape(uri);}
+var success=(onComplete)?OpenLayers.Function.bind(onComplete,caller):OpenLayers.nullHandler;var failure=(onFailure)?OpenLayers.Function.bind(onFailure,caller):OpenLayers.nullHandler;new OpenLayers.Ajax.Request(uri,{method:'get',parameters:params,onComplete:success,onFailure:failure});};OpenLayers.parseXMLString=function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
+var ajaxResponse=OpenLayers.Util.Try(function(){var xmldom=new ActiveXObject('Microsoft.XMLDOM');xmldom.loadXML(text);return xmldom;},function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
+req.send(null);return req.responseXML;});return ajaxResponse;};OpenLayers.Ajax={emptyFunction:function(){},getTransport:function(){return OpenLayers.Util.Try(function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')},function(){return new XMLHttpRequest()})||false;},activeRequestCount:0};OpenLayers.Ajax.Responders={responders:[],register:function(responderToAdd){for(var i=0;i<this.responders.length;i++)
+if(responderToAdd==this.responders[i])
+return;this.responders.push(responderToAdd);},dispatch:function(callback,request,transport,json){var responder;for(var i=0;i<this.responders.length;i++){responder=this.responders[i];if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}}}};OpenLayers.Ajax.Responders.register({onCreate:function(){OpenLayers.Ajax.activeRequestCount++;},onComplete:function(){OpenLayers.Ajax.activeRequestCount--;}});OpenLayers.Ajax.Base=function(){};OpenLayers.Ajax.Base.prototype={setOptions:function(options){this.options={'method':'post','asynchronous':true,'parameters':''};OpenLayers.Util.extend(this.options,options||{});},responseIsSuccess:function(){return this.transport.status==undefined||this.transport.status==0||(this.transport.status>=200&&this.transport.status<300);},responseIsFailure:function(){return!this.responseIsSuccess();}};OpenLayers.Ajax.Request=OpenLayers.Class(OpenLayers.Ajax.Base,{initialize:function(url,options){this.transport=OpenLayers.Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){var parameters=this.options.parameters||'';if(parameters.length>0)parameters+='&_=';try{this.url=url;if(this.options.method=='get'&&parameters.length>0){this.url+=(this.url.match(/\?/)?'&':'?')+parameters;}
+OpenLayers.Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.options.method,this.url,this.options.asynchronous);if(this.options.asynchronous){this.transport.onreadystatechange=OpenLayers.Function.bind(this.onStateChange,this);setTimeout(OpenLayers.Function.bind((function(){this.respondToReadyState(1)}),this),10);}
+this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange();}}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version','OpenLayers'];if(this.options.method=='post'&&!this.options.postBody){requestHeaders.push('Content-type','application/x-www-form-urlencoded');if(this.transport.overrideMimeType){requestHeaders.push('Connection','close');}}
+if(this.options.requestHeaders){requestHeaders.push.apply(requestHeaders,this.options.requestHeaders);}
+for(var i=0;i<requestHeaders.length;i+=2){this.transport.setRequestHeader(requestHeaders[i],requestHeaders[i+1]);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState!=1){this.respondToReadyState(this.transport.readyState);}},header:function(name){try{return this.transport.getResponseHeader(name);}catch(e){}},evalJSON:function(){try{return eval(this.header('X-JSON'));}catch(e){}},evalResponse:function(){try{return eval(this.transport.responseText);}catch(e){this.dispatchException(e);}},respondToReadyState:function(readyState){var event=OpenLayers.Ajax.Request.Events[readyState];var transport=this.transport,json=this.evalJSON();if(event=='Complete'){try{var responseSuccess=this.responseIsSuccess()?'Success':'Failure';(this.options['on'+this.transport.status]||this.options['on'+responseSuccess]||OpenLayers.Ajax.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);}
+var contentType=this.header('Content-type')||'';if(contentType.match(/^text\/javascript/i)){this.evalResponse();}}
+try{(this.options['on'+event]||OpenLayers.Ajax.emptyFunction)(transport,json);OpenLayers.Ajax.Responders.dispatch('on'+event,this,transport,json);}catch(e){this.dispatchException(e);}
+if(event=='Complete'){this.transport.onreadystatechange=OpenLayers.Ajax.emptyFunction;}},dispatchException:function(exception){if(this.options.onException){this.options.onException(this,exception);}else{throw exception;}
+OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}});OpenLayers.Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];OpenLayers.Ajax.getElementsByTagNameNS=function(parentnode,nsuri,nsprefix,tagname){var elem=null;if(parentnode.getElementsByTagNameNS){elem=parentnode.getElementsByTagNameNS(nsuri,tagname);}else{elem=parentnode.getElementsByTagName(nsprefix+':'+tagname);}
+return elem;};OpenLayers.Ajax.serializeXMLToString=function(xmldom){var serializer=new XMLSerializer();data=serializer.serializeToString(xmldom);return data;}
+OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,displayClass:"",active:null,handler:null,initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if(this.handler){this.handler.destroy();}
+this.map=null;},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv();this.div.id=this.id;this.div.className=this.displayClass;}
+if(px!=null){this.position=px.clone();}
+this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
+if(this.handler){this.handler.activate();}
+this.active=true;return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
+this.active=false;return true;}
+return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=(size)?size:new OpenLayers.Size(20,20);this.offset=offset?offset:new OpenLayers.Pixel(-(this.size.w/2),-(this.size.h/2));this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
+this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
+if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
+var offsetPx=this.px.offset(this.offset);OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,offsetPx);}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Strings.en={'test1':'this is a test','test2':'and another test','test3':'arg one:{0} arg two: {1}','unhandledRequest':"Unhandled request return {0}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Base Layer",'sameProjection':"The overview map only works when it is in the same projection as the main map",'readNotImplemented':"Read not implemented.",'writeNotImplemented':"Write not implemented.",'noFID':"Can't update a feature for which there is no FID.",'errorLoadingGML':"Error in loading GML file {0}",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n{0}",'componentShouldBe':"addFeatures : component should be an {0}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. "+"This usually means you destroyed a layer, but not some handler which is associated with it.",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS {0}",'commitFailed':"WFS Transaction: FAILED {0}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The {0} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the {0} library "+"script was either not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/{1}' "+"target='_blank'>click here</a>",'scale':"Scale = 1 : {0}",'layerAlreadyAdded':"You tried to add the layer: {0} to the map, but it has already been added",'reprojectDeprecated':"You are using the 'reproject' option "+"on the {0} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use {0} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: {0}",'clearArrayDeprecated':"OpenLayers.Util.clearArray() is Deprecated."+" Please use 'array.length = 0' instead.",'getArgsDeprecated':"The getArgs() function is deprecated and will be removed "+"with the 3.0 version of OpenLayers. Please instead use "+"OpenLayers.Util.getParameters().",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",'end':''};OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0;i<this.map.controls.length;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){break;}}
+if(i==this.map.controls.length){var args=OpenLayers.Util.getParameters();if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseInt(args.zoom);}
+this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}
+if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0;i<this.layers.length;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);while(this.buttons.length){var btn=this.buttons.shift();btn.map=null;OpenLayers.Event.stopObservingElement(btn);}
+this.buttons=null;this.position=null;},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var btn=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_PanZoom_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);OpenLayers.Event.observe(btn,"mousedown",OpenLayers.Function.bindAsEventListener(this.buttonDown,btn));OpenLayers.Event.observe(btn,"dblclick",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));OpenLayers.Event.observe(btn,"click",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));btn.action=id;btn.map=this.map;btn.slideFactor=this.slideFactor;this.buttons.push(btn);return btn;},doubleClick:function(evt){OpenLayers.Event.stop(evt);return false;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;switch(this.action){case"panup":this.map.pan(0,-50);break;case"pandown":this.map.pan(0,50);break;case"panleft":this.map.pan(-50,0);break;case"panright":this.map.pan(50,0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}
+OpenLayers.Event.stop(evt);},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Event={observers:false,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
+if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase())))
+element=element.parentNode;return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';}
+if(!this.observers){this.observers={};}
+if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;}
+element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);}
+var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];}
+this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}}
+var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&i<elementObservers.length){var cacheEntry=elementObservers[i];if((cacheEntry.name==name)&&(cacheEntry.observer==observer)&&(cacheEntry.useCapture==useCapture)){elementObservers.splice(i,1);if(elementObservers.length==0){delete OpenLayers.Event.observers[cacheID];}
+foundEntry=true;break;}
+i++;}}
+if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}
+return foundEntry;},unloadCache:function(){if(OpenLayers.Event.observers){for(var cacheID in OpenLayers.Event.observers){var elementObservers=OpenLayers.Event.observers[cacheID];OpenLayers.Event._removeElementObservers.apply(this,[elementObservers]);}
+OpenLayers.Event.observers=false;}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);if(window.Event){OpenLayers.Util.applyDefaults(window.Event,OpenLayers.Event);}else{var Event=OpenLayers.Event;}
+OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","resize","focus","blur"],listeners:null,object:null,element:null,eventTypes:null,eventHandler:null,fallThrough:null,initialize:function(object,element,eventTypes,fallThrough){this.object=object;this.element=element;this.eventTypes=eventTypes;this.fallThrough=fallThrough;this.listeners={};this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);if(this.eventTypes!=null){for(var i=0;i<this.eventTypes.length;i++){this.addEventType(this.eventTypes[i]);}}
+if(this.element!=null){this.attachToElement(element);}},destroy:function(){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}
+this.element=null;this.listeners=null;this.object=null;this.eventTypes=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){if(!this.listeners[eventName]){this.listeners[eventName]=[];}},attachToElement:function(element){for(var i=0;i<this.BROWSER_EVENTS.length;i++){var eventType=this.BROWSER_EVENTS[i];this.addEventType(eventType);OpenLayers.Event.observe(element,eventType,this.eventHandler);}
+OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},register:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){listeners.push({obj:obj,func:func});}}},registerPriority:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){listeners.unshift({obj:obj,func:func});}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){for(var i=0;i<listeners.length;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){if(evt==null){evt={};}
+evt.object=this.object;evt.element=this.element;var listeners=(this.listeners[type])?this.listeners[type].slice():null;if((listeners!=null)&&(listeners.length>0)){for(var i=0;i<listeners.length;i++){var callback=listeners[i];var continueChain;if(callback.obj!=null){continueChain=callback.func.call(callback.obj,evt);}else{continueChain=callback.func(evt);}
+if((continueChain!=null)&&(continueChain==false)){break;}}
+if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}}},handleBrowserEvent:function(evt){evt.xy=this.getMousePosition(evt);this.triggerEvent(evt.type,evt)},getMousePosition:function(evt){if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=(document.documentElement.scrollLeft||document.body.scrollLeft);this.element.offsets[1]+=(document.documentElement.scrollTop||document.body.scrollTop);}
+return new OpenLayers.Pixel((evt.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft))-this.element.offsets[0]
+-(document.documentElement.clientLeft||0),(evt.clientY+(document.documentElement.scrollTop||document.body.scrollTop))-this.element.offsets[1]
+-(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Projection=OpenLayers.Class({initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transform=function(point,source,dest){if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}
+return point;};OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size){this.layer=layer;this.position=position.clone();this.bounds=bounds.clone();this.url=url;this.size=size.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;this.events.destroy();this.events=null;},draw:function(){this.clear();var maxExtent=this.layer.maxExtent;var withinMaxExtent=true;if(this.layer.restrictedExtent){withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));}
+return(withinMaxExtent||this.layer.displayOutsideMaxExtent);},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
+this.bounds=bounds.clone();this.position=position.clone();if(redraw){this.draw();}},clear:function(){},getBoundsFromBaseLayer:function(position){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",this.layer.name));var topLeft=this.layer.map.getLonLatFromLayerPx(position);var bottomRightPx=position.clone();bottomRightPx.x+=this.size.w;bottomRightPx.y+=this.size.h;var bottomRight=this.layer.map.getLonLatFromLayerPx(bottomRightPx);if(topLeft.lon>bottomRight.lon){if(topLeft.lon<0){topLeft.lon=-180-(topLeft.lon+180);}else{bottomRight.lon=180+bottomRight.lon+180;}}
+bounds=new OpenLayers.Bounds(topLeft.lon,bottomRight.lat,bottomRight.lon,topLeft.lat);return bounds;},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{id:"OverviewMap",element:null,ovmap:null,size:new OpenLayers.Size(180,90),layers:null,minRatio:8,maxRatio:32,mapOptions:null,initialize:function(options){this.layers=[];OpenLayers.Control.prototype.initialize.apply(this,[options]);},destroy:function(){if(!this.mapDiv){return;}
+this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;this.rectEvents.destroy();this.rectEvents=null;this.ovmap.destroy();this.ovmap=null;this.element.removeChild(this.mapDiv);this.mapDiv=null;this.mapDivEvents.destroy();this.mapDivEvents=null;this.div.removeChild(this.element);this.element=null;this.elementEvents.destroy();this.elementEvents=null;if(this.maximizeDiv){OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.div.removeChild(this.maximizeDiv);this.maximizeDiv=null;}
+if(this.minimizeDiv){OpenLayers.Event.stopObservingElement(this.minimizeDiv);this.div.removeChild(this.minimizeDiv);this.minimizeDiv=null;}
+this.map.events.unregister('moveend',this,this.update);this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!(this.layers.length>0)){if(this.map.baseLayer){var layer=this.map.baseLayer.clone();this.layers=[layer];}else{this.map.events.register("changebaselayer",this,this.baseLayerDraw);return this.div;}}
+this.element=document.createElement('div');this.element.className=this.displayClass+'Element';this.element.style.display='none';this.mapDiv=document.createElement('div');this.mapDiv.style.width=this.size.w+'px';this.mapDiv.style.height=this.size.h+'px';this.mapDiv.style.position='relative';this.mapDiv.style.overflow='hidden';this.mapDiv.id=OpenLayers.Util.createUniqueID('overviewMap');this.extentRectangle=document.createElement('div');this.extentRectangle.style.position='absolute';this.extentRectangle.style.zIndex=1000;this.extentRectangle.style.overflow='hidden';this.extentRectangle.style.backgroundImage='url('+
+OpenLayers.Util.getImagesLocation()+'blank.gif)';this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);this.map.events.register('moveend',this,this.update);this.elementEvents=new OpenLayers.Events(this,this.element);this.elementEvents.register('mousedown',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('dblclick',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,true);this.rectEvents.register('mouseout',this,this.rectMouseOut);this.rectEvents.register('mousedown',this,this.rectMouseDown);this.rectEvents.register('mousemove',this,this.rectMouseMove);this.rectEvents.register('mouseup',this,this.rectMouseUp);this.rectEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents.register('dblclick',this,this.rectDblClick);this.mapDivEvents=new OpenLayers.Events(this,this.mapDiv);this.mapDivEvents.register('click',this,this.mapDivClick);if(!this.outsideViewport){this.div.className=this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+'MaximizeButton',null,new OpenLayers.Size(18,18),img,'absolute');this.maximizeDiv.style.display='none';this.maximizeDiv.className=this.displayClass+'MaximizeButton';OpenLayers.Event.observe(this.maximizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv('OpenLayers_Control_minimizeDiv',null,new OpenLayers.Size(18,18),img,'absolute');this.minimizeDiv.style.display='none';this.minimizeDiv.className=this.displayClass+'MinimizeButton';OpenLayers.Event.observe(this.minimizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);var eventsToStop=['dblclick','mousedown'];for(var i=0;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
+this.minimizeControl();}else{this.element.style.display='';}
+if(this.map.getExtent()){this.update();}
+return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},rectMouseOut:function(evt){if(this.rectDragStart!=null){if(this.performedRectDrag){this.rectMouseMove(evt);var rectPxBounds=this.getRectPxBounds();if((rectPxBounds.top<=0)||(rectPxBounds.left<=0)||(rectPxBounds.bottom>=this.size.h-this.hComp)||(rectPxBounds.right>=this.size.w-this.wComp)){this.updateMapToRect();}else{return;}}
+document.onselectstart=null;this.rectDragStart=null;}},rectMouseDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;this.rectDragStart=evt.xy.clone();this.performedRectDrag=false;OpenLayers.Event.stop(evt);},rectMouseMove:function(evt){if(this.rectDragStart!=null){var deltaX=this.rectDragStart.x-evt.xy.x;var deltaY=this.rectDragStart.y-evt.xy.y;var rectPxBounds=this.getRectPxBounds();var rectTop=rectPxBounds.top;var rectLeft=rectPxBounds.left;var rectHeight=Math.abs(rectPxBounds.getHeight());var rectWidth=rectPxBounds.getWidth();var newTop=Math.max(0,(rectTop-deltaY));newTop=Math.min(newTop,this.ovmap.size.h-this.hComp-rectHeight);var newLeft=Math.max(0,(rectLeft-deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-this.wComp-rectWidth);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+rectHeight,newLeft+rectWidth,newTop));this.rectDragStart=evt.xy.clone();this.performedRectDrag=true;OpenLayers.Event.stop(evt);}},rectMouseUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;if(this.performedRectDrag){this.updateMapToRect();OpenLayers.Event.stop(evt);}
+document.onselectstart=null;this.rectDragStart=null;},rectDblClick:function(evt){this.performedRectDrag=false;OpenLayers.Event.stop(evt);this.updateOverview();},mapDivClick:function(evt){var pxBounds=this.getRectPxBounds();var pxCenter=pxBounds.getCenterPixel();var deltaX=evt.xy.x-pxCenter.x;var deltaY=evt.xy.y-pxCenter.y;var top=pxBounds.top;var left=pxBounds.left;var height=Math.abs(pxBounds.getHeight());var width=pxBounds.getWidth();var newTop=Math.max(0,(top+deltaY));newTop=Math.min(newTop,this.ovmap.size.h-height);var newLeft=Math.max(0,(left+deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-width);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+height,newLeft+width,newTop));this.updateMapToRect();OpenLayers.Event.stop(evt);},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
+if(!this.isSuitableOverview()){this.updateOverview();}
+this.updateRectToMap();},isSuitableOverview:function(){var mapExtent=this.map.getExtent();var maxExtent=this.map.maxExtent;var testExtent=new OpenLayers.Bounds(Math.max(mapExtent.left,maxExtent.left),Math.max(mapExtent.bottom,maxExtent.bottom),Math.min(mapExtent.right,maxExtent.right),Math.min(mapExtent.top,maxExtent.top));var resRatio=this.ovmap.getResolution()/this.map.getResolution();return((resRatio>this.minRatio)&&(resRatio<=this.maxRatio)&&(this.ovmap.getExtent().containsBounds(testExtent)));},updateOverview:function(){var mapRes=this.map.getResolution();var targetRes=this.ovmap.getResolution();var resRatio=targetRes/mapRes;if(resRatio>this.maxRatio){targetRes=this.minRatio*mapRes;}else if(resRatio<=this.minRatio){targetRes=this.maxRatio*mapRes;}
+this.ovmap.setCenter(this.map.center,this.ovmap.getZoomForResolution(targetRes));this.updateRectToMap();},createMap:function(){var options=OpenLayers.Util.extend({controls:[],maxResolution:'auto'},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,options);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-left-width'))+
+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-right-width'));this.wComp=(this.wComp)?this.wComp:2;this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-top-width'))+
+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-bottom-width'));this.hComp=(this.hComp)?this.hComp:2;},updateRectToMap:function(){var pxBounds=this.getRectBoundsFromMapBounds(this.map.getExtent());if(pxBounds){this.setRectPxBounds(pxBounds);}},updateMapToRect:function(){var pxBounds=this.getRectPxBounds();var lonLatBounds=this.getMapBoundsFromRectBounds(pxBounds);this.map.setCenter(lonLatBounds.getCenterLonLat(),this.map.zoom);},getRectPxBounds:function(){var top=parseInt(this.extentRectangle.style.top);var left=parseInt(this.extentRectangle.style.left);var height=parseInt(this.extentRectangle.style.height);var width=parseInt(this.extentRectangle.style.width);return new OpenLayers.Bounds(left,top+height,left+width,top);},setRectPxBounds:function(pxBounds){var top=Math.max(pxBounds.top,0);var left=Math.max(pxBounds.left,0);var bottom=Math.min(pxBounds.top+Math.abs(pxBounds.getHeight()),this.ovmap.size.h-this.hComp);var right=Math.min(pxBounds.left+pxBounds.getWidth(),this.ovmap.size.w-this.wComp);this.extentRectangle.style.top=parseInt(top)+'px';this.extentRectangle.style.left=parseInt(left)+'px';this.extentRectangle.style.height=parseInt(Math.max(bottom-top,0))+'px';this.extentRectangle.style.width=parseInt(Math.max(right-left,0))+'px';},getRectBoundsFromMapBounds:function(lonLatBounds){var leftBottomLonLat=new OpenLayers.LonLat(lonLatBounds.left,lonLatBounds.bottom);var rightTopLonLat=new OpenLayers.LonLat(lonLatBounds.right,lonLatBounds.top);var leftBottomPx=this.getOverviewPxFromLonLat(leftBottomLonLat);var rightTopPx=this.getOverviewPxFromLonLat(rightTopLonLat);var bounds=null;if(leftBottomPx&&rightTopPx){bounds=new OpenLayers.Bounds(leftBottomPx.x,leftBottomPx.y,rightTopPx.x,rightTopPx.y);}
+return bounds;},getMapBoundsFromRectBounds:function(pxBounds){var leftBottomPx=new OpenLayers.Pixel(pxBounds.left,pxBounds.bottom);var rightTopPx=new OpenLayers.Pixel(pxBounds.right,pxBounds.top);var leftBottomLonLat=this.getLonLatFromOverviewPx(leftBottomPx);var rightTopLonLat=this.getLonLatFromOverviewPx(rightTopPx);return new OpenLayers.Bounds(leftBottomLonLat.lon,leftBottomLonLat.lat,rightTopLonLat.lon,rightTopLonLat.lat);},getLonLatFromOverviewPx:function(overviewMapPx){var size=this.ovmap.size;var res=this.ovmap.getResolution();var center=this.ovmap.getExtent().getCenterLonLat();var delta_x=overviewMapPx.x-(size.w/2);var delta_y=overviewMapPx.y-(size.h/2);return new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);},getOverviewPxFromLonLat:function(lonlat){var res=this.ovmap.getResolution();var extent=this.ovmap.getExtent();var px=null;if(extent){px=new OpenLayers.Pixel(Math.round(1/res*(lonlat.lon-extent.left)),Math.round(1/res*(extent.top-lonlat.lat)));}
+return px;},CLASS_NAME:'OpenLayers.Control.OverviewMap'});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;if(control.map){this.setMap(control.map);}
+OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
+var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
+this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
+this.active=false;return true;},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,events:null,div:null,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,zoom:0,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:'auto',numZoomLevels:16,theme:null,fallThrough:false,initialize:function(div,options){this.setOptions(options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{OpenLayers.Event.observe(window,'resize',OpenLayers.Function.bind(this.updateSize,this));}
+if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0;i<nodes.length;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
+if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
+this.layers=[];if(this.controls==null){if(OpenLayers.Control!=null){this.controls=[new OpenLayers.Control.Navigation(),new OpenLayers.Control.PanZoom(),new OpenLayers.Control.ArgParser(),new OpenLayers.Control.Attribution()];}else{this.controls=[];}}
+for(var i=0;i<this.controls.length;i++){this.addControlToMap(this.controls[i]);}
+this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);},unloadDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
+OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
+this.layers=null;}
+if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
+this.controls=null;}
+if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);}
+this.viewPortDiv=null;this.events.destroy();this.events=null;},setOptions:function(options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);},getTileSize:function(){return this.tileSize;},getLayer:function(id){var foundLayer=null;for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;}}
+return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
++zIdx*5);},addLayer:function(layer){for(var i=0;i<this.layers.length;i++){if(this.layers[i]==layer){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",layer.name));return false;}}
+layer.div.style.overflow="";this.setLayerZIndex(layer,this.layers.length);if(layer.isFixed){this.viewPortDiv.appendChild(layer.div);}else{this.layerContainerDiv.appendChild(layer.div);}
+this.layers.push(layer);layer.setMap(this);if(layer.isBaseLayer){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
+this.events.triggerEvent("addlayer");},addLayers:function(layers){for(var i=0;i<layers.length;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
+if(layer.isFixed){this.viewPortDiv.removeChild(layer.div);}else{this.layerContainerDiv.removeChild(layer.div);}
+OpenLayers.Util.removeItem(this.layers,layer);layer.removeMap(this);layer.map=null;if(setNewBaseLayer&&(this.baseLayer==layer)){this.baseLayer=null;for(i=0;i<this.layers.length;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer){this.setBaseLayer(iLayer);break;}}}
+this.events.triggerEvent("removelayer");},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},setLayerIndex:function(layer,idx){var base=this.getLayerIndex(layer);if(idx<0){idx=0;}else if(idx>this.layers.length){idx=this.layers.length;}
+if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0;i<this.layers.length;i++){this.setLayerZIndex(this.layers[i],i);}
+this.events.triggerEvent("changelayer");}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){var oldExtent=null;if(this.baseLayer){oldExtent=this.baseLayer.getExtent();}
+if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){if(this.baseLayer!=null){this.baseLayer.setVisibility(false);}
+this.baseLayer=newBaseLayer;this.maxExtent=newBaseLayer.maxExtent;this.minExtent=newBaseLayer.minExtent;this.maxScale=newBaseLayer.maxScale;this.minScale=newBaseLayer.minScale;this.maxResolution=newBaseLayer.maxResolution;this.minResolution=newBaseLayer.minResolution;this.units=newBaseLayer.units;this.projection=newBaseLayer.projection;this.viewRequestID++;this.baseLayer.visibility=true;var center=this.getCenter();if(center!=null){if(oldExtent==null){this.setCenter(center,this.getZoom(),false,true);}else{this.setCenter(oldExtent.getCenterLonLat(),this.getZoomForExtent(oldExtent),false,true);}}
+this.events.triggerEvent("changebaselayer");}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);control.setMap(this);var div=control.draw(px);if(div){if(!control.outsideViewport){div.style.zIndex=this.Z_INDEX_BASE['Control']+
+this.controls.length;this.viewPortDiv.appendChild(div);}}},getControl:function(id){var returnControl=null;for(var i=0;i<this.controls.length;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
+return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(!control.outsideViewport){this.viewPortDiv.removeChild(control.div)}
+OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=0;i<this.popups.length;i++){this.removePopup(this.popups[i]);}}
+popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+
+this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);}
+catch(e){}}
+popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();}
+return size;},updateSize:function(){this.events.element.offsets=null;var newSize=this.getCurrentSize();var oldSize=this.getSize();if(oldSize==null)
+this.size=oldSize=newSize;if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0;i<this.layers.length;i++){this.layers[i].onMapResize();}
+if(this.baseLayer!=null){var center=new OpenLayers.Pixel(newSize.w/2,newSize.h/2);var centerLL=this.getLonLatFromViewPortPx(center);var zoom=this.getZoom();this.zoom=null;this.setCenter(this.getCenter(),zoom);}}},getCurrentSize:function(){var size=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){var dim=OpenLayers.Element.getDimensions(this.div);size.w=dim.width;size.h=dim.height;}
+if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=parseInt(this.div.style.width);size.h=parseInt(this.div.style.height);}
+return size;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCenter();}
+if(resolution==null){resolution=this.getResolution();}
+if((center!=null)&&(resolution!=null)){var size=this.getSize();var w_deg=size.w*resolution;var h_deg=size.h*resolution;extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);}
+return extent;},getCenter:function(){return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy){var centerPx=this.getViewPortPxFromLonLat(this.getCenter());var newCenterPx=centerPx.add(dx,dy);if(!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);this.setCenter(newCenterLonLat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){if(!this.center&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();}
+if(this.restrictedExtent&&this.restrictedExtent!='auto'){if(lonlat==null){lonlat=this.getCenter();}
+if(zoom==null){zoom=this.getZoom();}
+var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.resolutions[zoom];}
+var extent=this.calculateBounds(lonlat,resolution);if(!this.restrictedExtent.containsBounds(extent)){var maxCenter=this.restrictedExtent.getCenterLonLat();if(extent.getWidth()>this.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.left<this.restrictedExtent.left){lonlat=lonlat.add(this.restrictedExtent.left-
+extent.left,0);}else if(extent.right>this.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right-
+extent.right,0);}
+if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottom<this.restrictedExtent.bottom){lonlat=lonlat.add(0,this.restrictedExtent.bottom-
+extent.bottom);}
+else if(extent.top>this.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top-
+extent.top);}}}
+var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=!lonlat.equals(this.center);if(this.restrictedExtent=='auto'){centerChanged=this.isValidLonLat(lonlat)&&centerChanged;}
+if(zoomChanged||centerChanged||!dragging){if(!dragging){this.events.triggerEvent("movestart");}
+if(centerChanged){if((!zoomChanged)&&(this.center)){this.centerLayerContainer(lonlat);}
+this.center=lonlat.clone();}
+if((zoomChanged)||(this.layerContainerOrigin==null)){this.layerContainerOrigin=this.center.clone();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";}
+if(zoomChanged){this.zoom=zoom;this.viewRequestID++;}
+var bounds=this.getExtent();this.baseLayer.moveTo(bounds,zoomChanged,dragging);bounds=this.baseLayer.getExtent();for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(!layer.isBaseLayer){var moveLayer;var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;moveLayer=true;this.events.triggerEvent("changelayer");}else{moveLayer=(layer.visibility&&layer.inRange);}
+if(moveLayer){layer.moveTo(bounds,zoomChanged,dragging);}}}
+if(zoomChanged){for(var i=0;i<this.popups.length;i++){this.popups[i].updatePosition();}}
+this.events.triggerEvent("move");if(zoomChanged){this.events.triggerEvent("zoomend");}}
+if(!dragging){this.events.triggerEvent("moveend");}},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){this.layerContainerDiv.style.left=(originPx.x-newPx.x)+"px";this.layerContainerDiv.style.top=(originPx.y-newPx.y)+"px";}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();valid=maxExtent.containsLonLat(lonlat);}
+return valid;},getProjection:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
+return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
+return maxResolution;},getMaxExtent:function(){var maxExtent=null;if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
+return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
+return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
+return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}
+return resolution;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);}
+return scale;},getZoomForExtent:function(bounds){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds);}
+return zoom;},getZoomForResolution:function(resolution){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution);}
+return zoom;},zoomTo:function(zoom){if(this.isValidZoomLevel(zoom)){this.setCenter(null,zoom);}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds){var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
+center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
+this.setCenter(center,this.getZoomForExtent(bounds));},zoomToMaxExtent:function(){this.zoomToExtent(this.getMaxExtent());},zoomToScale:function(scale){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var size=this.getSize();var w_deg=size.w*res;var h_deg=size.h*res;var center=this.getCenter();var extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);this.zoomToExtent(extent);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
+return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){return this.getViewPortPxFromLonLat(lonlat);},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
+return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
+return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
+this.events=new OpenLayers.Events(this,this.icon.imageDiv,null);},destroy:function(){this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
+this.lonlat=this.map.getLonLatFromLayerPx(px);},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
+return onScreen;},inflate:function(inflate){if(this.icon){var newSize=new OpenLayers.Size(this.icon.size.w*inflate,this.icon.size.h*inflate);this.icon.setSize(newSize);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){var url=OpenLayers.Util.getImagesLocation()+"marker.png";var size=new OpenLayers.Size(21,25);var calculateOffset=function(size){return new OpenLayers.Pixel(-(size.w/2),-size.h);};return new OpenLayers.Icon(url,size,null,calculateOffset);};OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.frame=document.createElement('div');this.frame.style.overflow='hidden';this.frame.style.position='absolute';},destroy:function(){if(this.imgDiv!=null){OpenLayers.Event.stopObservingElement(this.imgDiv.id);if(this.imgDiv.parentNode==this.frame){this.frame.removeChild(this.imgDiv);this.imgDiv.map=null;}}
+this.imgDiv=null;if((this.frame!=null)&&(this.frame.parentNode==this.layer.div)){this.layer.div.removeChild(this.frame);}
+this.frame=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
+if(!OpenLayers.Tile.prototype.draw.apply(this,arguments)){return false;}
+if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
+if(this.imgDiv==null){this.initImgDiv();}
+this.imgDiv.viewRequestID=this.layer.map.viewRequestID;this.url=this.layer.getURL(this.bounds);OpenLayers.Util.modifyDOMElement(this.frame,null,this.position,this.size);var imageSize=this.layer.getImageSize();if(this.layer.alpha){OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,null,null,imageSize,this.url);}else{this.imgDiv.src=this.url;OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,imageSize);}
+return true;},clear:function(){if(this.imgDiv){this.imgDiv.style.display="none";}},initImgDiv:function(){var offset=this.layer.imageOffset;var size=this.layer.getImageSize();if(this.layer.alpha){this.imgDiv=OpenLayers.Util.createAlphaImageDiv(null,offset,size,null,"relative",null,null,null,true);}else{this.imgDiv=OpenLayers.Util.createImage(null,offset,size,null,"relative",null,null,true);}
+this.imgDiv.className='olTileImage';this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
+this.imgDiv.map=this.layer.map;var onload=function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}}
+OpenLayers.Event.observe(this.imgDiv,'load',OpenLayers.Function.bind(onload,this));},checkImgURL:function(){if(this.layer){var loaded=this.layer.alpha?this.imgDiv.firstChild.src:this.imgDiv.src;if(!OpenLayers.Util.isEquivalentUrl(loaded,this.url)){this.imgDiv.style.display="none";}}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,stopSingle:false,stopDouble:false,timerId:null,down:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.pixelTolerance!=null){this.mousedown=function(evt){this.down=evt.xy;return true;};}},mousedown:null,dblclick:function(evt){if(this.passesTolerance(evt)){if(this["double"]){this.callback('dblclick',[evt]);}
+this.clearTimer();}
+return!this.stopDouble;},click:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){this.clearTimer();}else{var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,clickEvent),this.delay);}}
+return!this.stopSingle;},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down){var dpx=Math.sqrt(Math.pow(this.down.x-evt.xy.x,2)+
+Math.pow(this.down.y-evt.xy.y,2));if(dpx>this.pixelTolerance){passes=false;}}
+return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback('click',[evt]);}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;deactivated=true;}
+return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,dragging:false,last:null,start:null,oldOnselectstart:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&OpenLayers.Event.isLeftClick(evt)){this.started=true;this.start=evt.xy;this.last=evt.xy;this.map.div.style.cursor="move";this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
+propagate=false;}else{this.started=false;this.start=null;this.last=null;}
+return propagate;},mousemove:function(evt){if(this.started){if(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y){this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
+this.last=evt.xy;}}
+return true;},mouseup:function(evt){if(this.started){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.up(evt);this.callback("up",[evt.xy]);this.callback("done",[evt.xy]);document.onselectstart=this.oldOnselectstart;}
+return true;},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.div)){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.out(evt);this.callback("out",[]);if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}
+this.callback("done",[evt.xy])}
+return true;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;}
+return deactivated;},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null;},onWheelEvent:function(e){if(!this.checkModifiers(e))return;var inMap=false;var elem=OpenLayers.Event.element(e);while(elem!=null){if(this.map&&elem==this.map.div){inMap=true;break;}
+elem=elem.parentNode;}
+if(inMap){var delta=0;if(!e){e=window.event;}
+if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
+if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
+if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
+if(delta<0){this.callback("down",[e,delta]);}else{this.callback("up",[e,delta]);}}
+OpenLayers.Event.stop(e);}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,EVENT_TYPES:["loadstart","loadend","loadcancel","visibilitychanged"],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,imageOffset:null,options:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:false,wrapDateLine:false,initialize:function(name,options){this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv();this.div.style.width="100%";this.div.style.height="100%";this.div.id=this.id;this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES);}
+if(this.wrapDateLine){this.displayOutsideMaxExtent=true;}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
+if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
+this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){this.events.destroy();}
+this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.options);}
+OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer");}}},addOptions:function(newOptions){if(this.options==null){this.options={};}
+OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){this.moveTo(extent,true,false);redrawn=true;}}
+return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
+this.display(display);},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.projection=this.projection||this.map.projection;if(this.projection&&typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
+this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";}
+this.setTileSize();}},removeMap:function(map){},getImageSize:function(){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageOffset=new OpenLayers.Pixel(-this.gutter,-this.gutter);this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer");}
+this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display)?"block":"none";}},calculateInRange:function(){var inRange=false;if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}
+return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changelayer");}}},initResolutions:function(){var props=new Array('projection','units','scales','resolutions','maxScale','minScale','maxResolution','minResolution','minExtent','maxExtent','numZoomLevels','maxZoomLevel');var confProps={};for(var i=0;i<props.length;i++){var property=props[i];confProps[property]=this.options[property]||this.map[property];}
+if((!confProps.numZoomLevels)&&(confProps.maxZoomLevel)){confProps.numZoomLevels=confProps.maxZoomLevel+1;}
+if((confProps.scales!=null)||(confProps.resolutions!=null)){if(confProps.scales!=null){confProps.resolutions=[];for(var i=0;i<confProps.scales.length;i++){var scale=confProps.scales[i];confProps.resolutions[i]=OpenLayers.Util.getResolutionFromScale(scale,confProps.units);}}
+confProps.numZoomLevels=confProps.resolutions.length;}else{confProps.resolutions=[];if(confProps.minScale){confProps.maxResolution=OpenLayers.Util.getResolutionFromScale(confProps.minScale,confProps.units);}else if(confProps.maxResolution=="auto"){var viewSize=this.map.getSize();var wRes=confProps.maxExtent.getWidth()/viewSize.w;var hRes=confProps.maxExtent.getHeight()/viewSize.h;confProps.maxResolution=Math.max(wRes,hRes);}
+if(confProps.maxScale!=null){confProps.minResolution=OpenLayers.Util.getResolutionFromScale(confProps.maxScale);}else if((confProps.minResolution=="auto")&&(confProps.minExtent!=null)){var viewSize=this.map.getSize();var wRes=confProps.minExtent.getWidth()/viewSize.w;var hRes=confProps.minExtent.getHeight()/viewSize.h;confProps.minResolution=Math.max(wRes,hRes);}
+if(confProps.minResolution!=null){var ratio=confProps.maxResolution/confProps.minResolution;confProps.numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}
+for(var i=0;i<confProps.numZoomLevels;i++){var res=confProps.maxResolution/Math.pow(2,i)
+confProps.resolutions.push(res);}}
+confProps.resolutions.sort(function(a,b){return(b-a);});this.resolutions=confProps.resolutions;this.maxResolution=confProps.resolutions[0];var lastIndex=confProps.resolutions.length-1;this.minResolution=confProps.resolutions[lastIndex];this.scales=[];for(var i=0;i<confProps.resolutions.length;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],confProps.units);}
+this.minScale=this.scales[0];this.maxScale=this.scales[this.scales.length-1];this.numZoomLevels=confProps.numZoomLevels;},getResolution:function(){var zoom=this.map.getZoom();return this.resolutions[zoom];},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution);},getDataExtent:function(){},getZoomForResolution:function(resolution){var zoom,diff;var minDiff=Number.POSITIVE_INFINITY;for(var i=0;i<this.resolutions.length;i++){diff=Math.abs(this.resolutions[i]-resolution);if(diff<minDiff){zoom=i;minDiff=diff;}else if(diff>minDiff){break;}}
+return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(viewPortPx!=null){var size=this.map.getSize();var center=this.map.getCenter();if(center){var res=this.map.getResolution();var delta_x=viewPortPx.x-(size.w/2);var delta_y=viewPortPx.y-(size.h/2);lonlat=new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(lonlat!=null){var resolution=this.map.getResolution();var extent=this.map.getExtent();px=new OpenLayers.Pixel(Math.round(1/resolution*(lonlat.lon-extent.left)),Math.round(1/resolution*(extent.top-lonlat.lat)));}
+return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0;i<this.div.childNodes.length;++i){var element=this.div.childNodes[i].firstChild;OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}}},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){var mapGutter=this.gutter*this.map.getResolution();bounds=new OpenLayers.Bounds(bounds.left-mapGutter,bounds.bottom-mapGutter,bounds.right+mapGutter,bounds.top+mapGutter);}
+if(this.wrapDateLine){var wrappingOptions={'rightTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
+return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(bounds,borderColor,borderWidth){this.bounds=bounds;this.div=OpenLayers.Util.createDiv();this.div.style.overflow='hidden';this.events=new OpenLayers.Events(this,this.div,null);this.setBorder(borderColor,borderWidth);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
+if(!width){width=2;}
+this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
+return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},panMap:function(xy){this.panned=true;var deltaX=this.handler.last.x-xy.x;var deltaY=this.handler.last.y-xy.y;var size=this.map.getSize();var newXY=new OpenLayers.Pixel(size.w/2+deltaX,size.h/2+deltaY);var newCenter=this.map.getLonLatFromViewPortPx(newXY);this.map.setCenter(newCenter,null,this.handler.dragging);},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);var callbacks={"down":this.startBox,"move":this.moveBox,"out":this.removeBox,"up":this.endBox};this.dragHandler=new OpenLayers.Handler.Drag(this,callbacks,{keyMask:this.keyMask});},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.dragHandler.start,null,null,"absolute","2px solid red");this.zoomBox.style.backgroundColor="white";this.zoomBox.style.filter="alpha(opacity=50)";this.zoomBox.style.opacity="0.50";this.zoomBox.style.fontSize="1px";this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);this.map.div.style.cursor="crosshair";},moveBox:function(xy){var deltaX=Math.abs(this.dragHandler.start.x-xy.x);var deltaY=Math.abs(this.dragHandler.start.y-xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(xy.x<this.dragHandler.start.x){this.zoomBox.style.left=xy.x+"px";}
+if(xy.y<this.dragHandler.start.y){this.zoomBox.style.top=xy.y+"px";}},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
+this.removeBox();this.map.div.style.cursor="";this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragHandler.deactivate();return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){var newArguments=arguments;newArguments=[name,options];OpenLayers.Layer.prototype.initialize.apply(this,newArguments);this.url=url;this.params=OpenLayers.Util.extend({},params);},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);this.redraw();},selectUrl:function(paramString,urls){var product=1;for(var i=0;i<paramString.length;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
+return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
+var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,markers:null,drawn:false,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[];},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(zoomChanged||!this.drawn){for(i=0;i<this.markers.length;i++){this.drawMarker(this.markers[i]);}
+this.drawn=true;}},addMarker:function(marker){this.markers.push(marker);if(this.map&&this.map.getExtent()){marker.map=this.map;this.drawMarker(marker);}},removeMarker:function(marker){OpenLayers.Util.removeItem(this.markers,marker);if((marker.icon!=null)&&(marker.icon.imageDiv!=null)&&(marker.icon.imageDiv.parentNode==this.div)){this.div.removeChild(marker.icon.imageDiv);marker.drawn=false;}},clearMarkers:function(){if(this.markers!=null){while(this.markers.length>0){this.removeMarker(this.markers[0]);}}},drawMarker:function(marker){var px=this.map.getLayerPxFromLonLat(marker.lonlat);if(px==null){marker.display(false);}else{var markerImg=marker.draw(px);if(!marker.drawn){this.div.appendChild(markerImg);marker.drawn=true;}}},getDataExtent:function(){var maxExtent=null;if(this.markers&&(this.markers.length>0)){var maxExtent=new OpenLayers.Bounds();for(var i=0;i<this.markers.length;i++){var marker=this.markers[i];maxExtent.extend(marker.lonlat);}}
+return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);this.map.zoomToExtent(bounds);}else{this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()+1);}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,grid:null,singleTile:false,ratio:1.5,buffer:2,numLoadingTiles:0,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.events.addEventType("tileloaded");this.grid=[];},destroy:function(){this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0;iRow<this.grid.length;iRow++){var row=this.grid[iRow];for(var iCol=0;iCol<row.length;iCol++){var tile=row[iCol];this.removeTileMonitoringHooks(tile);tile.destroy();}}
+this.grid=[];}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
+obj.grid=[];return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){this.initSingleTile(bounds);}}else{if(forceReTile||!tilesBounds.containsBounds(bounds,true)){this.initGriddedTiles(bounds);}else{this.moveGriddedTiles(bounds);}}}},setTileSize:function(size){if(this.singleTile){var size=this.map.getSize().clone();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
+OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getGridBounds:function(){var msg="The getGridBounds() function is deprecated. It will be "+"removed in 3.0. Please use getTilesBounds() instead.";OpenLayers.Console.warn(msg);return this.getTilesBounds();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
+return bounds;},initSingleTile:function(bounds){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var px=this.map.getLayerPxFromLonLat(ul);if(!this.grid.length){this.grid[0]=[];}
+var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
+this.removeExcessTiles(1,1);},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
+Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
+Math.max(1,2*this.buffer);var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=bounds.top-(extent.bottom+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=extent.bottom+tilerow*tilelat;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
+tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;y-=parseInt(this.map.layerContainerDiv.style.top);var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
+tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
+tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
+this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},spiralTileLoad:function(){var tileQueue=[];var directions=["right","down","left","up"];var iRow=0;var iCell=-1;var direction=OpenLayers.Util.indexOf(directions,"right");var directionsTried=0;while(directionsTried<directions.length){var testRow=iRow;var testCell=iCell;switch(directions[direction]){case"right":testCell++;break;case"down":testRow++;break;case"left":testCell--;break;case"up":testRow--;break;}
+var tile=null;if((testRow<this.grid.length)&&(testRow>=0)&&(testCell<this.grid[0].length)&&(testCell>=0)){tile=this.grid[testRow][testCell];}
+if((tile!=null)&&(!tile.queued)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
+for(var i=0;i<tileQueue.length;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
+this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.events.unregister("loadstart",this,tile.onLoadStart);tile.events.unregister("loadend",this,tile.onLoadEnd);},moveGriddedTiles:function(bounds){var buffer=this.buffer||1;while(true){var tlLayer=this.grid[0][0].position;var tlViewPort=this.map.getViewPortPxFromLayerPx(tlLayer);if(tlViewPort.x>-this.tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-this.tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-this.tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-this.tileSize.h*buffer){this.shiftRow(false);}else{break;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var modelRow=this.grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?this.grid.pop():this.grid.shift();for(var i=0;i<modelRow.length;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
+if(prepend){this.grid.unshift(row);}else{this.grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0;i<this.grid.length;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){this.grid[i].unshift(tile);}else{this.grid[i].push(tile);}}},removeExcessTiles:function(rows,columns){while(this.grid.length>rows){var row=this.grid.pop();for(var i=0,l=row.length;i<l;i++){var tile=row[i];this.removeTileMonitoringHooks(tile);tile.destroy();}}
+while(this.grid[0].length>columns){for(var i=0,l=this.grid.length;i<l;i++){var row=this.grid[i];var tile=row.pop();this.removeTileMonitoringHooks(tile);tile.destroy();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();this.initSingleTile(this.map.getExtent());}},getTileBounds:function(viewPortPx){var maxExtent=this.map.getMaxExtent();var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=maxExtent.left+(tileMapWidth*Math.floor((mapPoint.lon-
+maxExtent.left)/tileMapWidth));var tileBottom=maxExtent.bottom+(tileMapHeight*Math.floor((mapPoint.lat-
+maxExtent.bottom)/tileMapHeight));return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,wheelHandler:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},activate:function(){this.dragPan.activate();this.wheelHandler.activate();this.zoomBox.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){this.zoomBox.deactivate();this.dragPan.deactivate();this.wheelHandler.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){this.map.events.register("dblclick",this,this.defaultDblClick);this.dragPan=new OpenLayers.Control.DragPan({map:this.map});this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:OpenLayers.Handler.MOD_SHIFT});this.dragPan.draw();this.zoomBox.draw();this.wheelHandler=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown});this.activate();},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);OpenLayers.Event.stop(evt);return false;},wheelChange:function(evt,deltaZ){var newZoom=this.map.getZoom()+deltaZ;if(!this.map.isValidZoomLevel(newZoom))return;var size=this.map.getSize();var deltaX=size.w/2-evt.xy.x;var deltaY=evt.xy.y-size.h/2;var newRes=this.map.baseLayer.resolutions[newZoom];var zoomPoint=this.map.getLonLatFromPixel(evt.xy);var newCenter=new OpenLayers.LonLat(zoomPoint.lon+deltaX*newRes,zoomPoint.lat+deltaY*newRes);this.map.setCenter(newCenter,newZoom);},wheelUp:function(evt){this.wheelChange(evt,1);},wheelDown:function(evt){this.wheelChange(evt,-1);},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{reproject:false,isBaseLayer:true,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',version:'1.0.0'},session:null,mapName:null,groupName:null,initialize:function(name,url,params,options){var newArguments=new Array();newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}
+if(arguments.length>0){if(this.options.singleTile){this.session=params.session;this.mapName=params.mapname;OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);if(!this.isBaseLayer){this.params.operation="GETDYNAMICMAPOVERLAYIMAGE";}}else{this.groupName=params.groupname;OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);this.setTileSize(new OpenLayers.Size(300,300));}}},updateExtents:function(a){var center=this.map.getExtent().getCenterLonLat();var mapSize=this.map.getCurrentSize();var sParams="operation=GETVISIBLEMAPEXTENT&version=1.0.0";sParams+="&session="+this.session;sParams+="&mapname="+this.mapName;sParams+="&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;sParams+="&setdisplayheight="+mapSize.h*this.ratio;sParams+="&setdisplaywidth="+mapSize.w*this.ratio;sParams+="&setviewcenterx="+center.lon;sParams+="&setviewcentery="+center.lat;sParams+="&setviewscale="+this.map.getScale();if(this.options.showLayers)sParams+="&showlayers="+this.options.showLayers;if(this.options.hideLayers)sParams+="&hidelayers="+this.options.hideLayers;if(this.options.showGroups)sParams+="&showgroups="+this.options.showGroups;if(this.options.hideGroups)sParams+="&hidegroups="+this.options.hideGroups;if(this.options.refreshLayers)sParams+="&refreshlayers="+this.options.refreshLayers;sParams+="&ts="+(new Date()).getTime();new OpenLayers.Ajax.Request(this.url,{parameters:sParams,onSuccess:this._getExtentSuccess,onFailure:this._getExtentFailure,asynchronous:false});},_getExtentSuccess:function(transport){var temp=transport.responseXML;},_getExtentFailure:function(r){},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},getURL:function(bounds){var center=bounds.getCenterLonLat();var mapSize=this.map.getCurrentSize();if(this.options.singleTile){var params={};params.session=this.session;params.mapname=this.mapName;if(this.isBaseLayer){params.locale="en";params.setdisplaydpi=OpenLayers.DOTS_PER_INCH;params.setdisplayheight=mapSize.h*this.ratio;params.setdisplaywidth=mapSize.w*this.ratio;params.setviewcenterx=center.lon;params.setviewcentery=center.lat;params.setviewscale=this.map.getScale();params.clip="1";if(this.options.showLayers)params.showlayers=this.options.showLayers;if(this.options.hideLayers)params.hidelayers=this.options.hideLayers;if(this.options.showGroups)params.showgroups=this.options.showGroups;if(this.options.hideGroups)params.hidegroups=this.options.hideGroups;if(this.options.refreshLayers)params.refreshlayers=this.options.refreshLayers;}else{this.updateExtents();}
+params.ts=(new Date()).getTime();var url=this.getFullRequestString(params);}else{var currentRes=this.map.getResolution();var colidx=Math.floor((bounds.left-this.maxExtent.left)/currentRes);colidx=Math.round(colidx/this.tileSize.w);var rowidx=Math.floor((this.maxExtent.top-bounds.top)/currentRes);rowidx=Math.round(rowidx/this.tileSize.h);var url=this.getFullRequestString({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}
+return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
+var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getArgs(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+1;var minCols=Math.ceil(viewSize.w/this.tileSize.w)+1;var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
+tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
+tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
+tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
+this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
+if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
+var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
+if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();return this.getFullRequestString({BBOX:this.encodeBBOX?bounds.toBBOX():bounds.toArray(),WIDTH:imageSize.w,HEIGHT:imageSize.h});},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams){var projection=this.map.getProjection();this.params.SRS=(projection=="none")?null:projection.getCode();return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});


Property changes on: sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Copied: sandbox/aboudreault/lib/OpenLayers/Strings (from rev 1352, trunk/lib/OpenLayers/Strings)

Deleted: sandbox/aboudreault/lib/OpenLayers/Strings/en.js
===================================================================
--- trunk/lib/OpenLayers/Strings/en.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/OpenLayers/Strings/en.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,68 +0,0 @@
-OpenLayers.Strings.en = {
-'test1': 'this is a test',
-'test2': 'and another test',
-'test3': 'arg one:{0} arg two: {1}',
-'unhandledRequest': "Unhandled request return {0}",
-'permalink': "Permalink",
-'overlays': "Overlays",
-'baseLayer': "Base Layer",
-'sameProjection': "The overview map only works when it is in the same projection as the main map",
-'readNotImplemented': "Read not implemented.",
-'writeNotImplemented': "Write not implemented.",
-'noFID': "Can't update a feature for which there is no FID.",
-'errorLoadingGML': "Error in loading GML file {0}",
-'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
-'componentShouldBe': "addFeatures : component should be an {0}",
-'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
-                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
-'minZoomLevelError': "The minZoomLevel property is only intended for use " +
-                    "with the FixedZoomLevels-descendent layers. That this " +
-                    "wfs layer checks for minZoomLevel is a relic of the" +
-                    "past. We cannot, however, remove it without possibly " +
-                    "breaking OL based applications that may depend on it." +
-                    " Therefore we are deprecating it -- the minZoomLevel " +
-                    "check below will be removed at 3.0. Please instead " +
-                    "use min/max resolution setting as described here: " +
-                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
-'commitSuccess': "WFS Transaction: SUCCESS {0}",
-'commitFailed': "WFS Transaction: FAILED {0}",
-'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the Google Maps library " +
-                "script was either not included, or does not contain the " +
-                "correct API key for your site.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/Google' " +
-                "target='_blank'>click here</a>",
-'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the {0} library " +
-                "script was either not correctly included.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/{1}' " +
-                "target='_blank'>click here</a>",
-'scale': "Scale = 1 : {0}",
-'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
-'reprojectDeprecated': "You are using the 'reproject' option " +
-                "on the {0} layer. This option is deprecated: " +
-                "its use was designed to support displaying data over commercial " + 
-                "basemaps, but that functionality should now be achieved by using " +
-                "Spherical Mercator support. More information is available from " +
-                "http://trac.openlayers.org/wiki/SphericalMercator.",
-'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
-                "Please use {0} instead.",
-'boundsAddError': "You must pass both x and y values to the add function.",
-'lonlatAddError': "You must pass both lon and lat values to the add function.",
-'pixelAddError': "You must pass both x and y values to the add function.",
-'unsupportedGeometryType': "Unsupported geometry type: {0}",
-'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
-                " Please use 'array.length = 0' instead.",
-'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
-                "with the 3.0 version of OpenLayers. Please instead use " +
-                "OpenLayers.Util.getParameters().",
-'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
-                
-'end': ''
-};
\ No newline at end of file

Copied: sandbox/aboudreault/lib/OpenLayers/Strings/en.js (from rev 1352, trunk/lib/OpenLayers/Strings/en.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Strings/en.js	                        (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Strings/en.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,68 @@
+OpenLayers.Strings.en = {
+'test1': 'this is a test',
+'test2': 'and another test',
+'test3': 'arg one:{0} arg two: {1}',
+'unhandledRequest': "Unhandled request return {0}",
+'permalink': "Permalink",
+'overlays': "Overlays",
+'baseLayer': "Base Layer",
+'sameProjection': "The overview map only works when it is in the same projection as the main map",
+'readNotImplemented': "Read not implemented.",
+'writeNotImplemented': "Write not implemented.",
+'noFID': "Can't update a feature for which there is no FID.",
+'errorLoadingGML': "Error in loading GML file {0}",
+'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
+'componentShouldBe': "addFeatures : component should be an {0}",
+'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
+                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
+'minZoomLevelError': "The minZoomLevel property is only intended for use " +
+                    "with the FixedZoomLevels-descendent layers. That this " +
+                    "wfs layer checks for minZoomLevel is a relic of the" +
+                    "past. We cannot, however, remove it without possibly " +
+                    "breaking OL based applications that may depend on it." +
+                    " Therefore we are deprecating it -- the minZoomLevel " +
+                    "check below will be removed at 3.0. Please instead " +
+                    "use min/max resolution setting as described here: " +
+                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
+'commitSuccess': "WFS Transaction: SUCCESS {0}",
+'commitFailed': "WFS Transaction: FAILED {0}",
+'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the Google Maps library " +
+                "script was either not included, or does not contain the " +
+                "correct API key for your site.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/Google' " +
+                "target='_blank'>click here</a>",
+'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the {0} library " +
+                "script was either not correctly included.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/{1}' " +
+                "target='_blank'>click here</a>",
+'scale': "Scale = 1 : {0}",
+'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
+'reprojectDeprecated': "You are using the 'reproject' option " +
+                "on the {0} layer. This option is deprecated: " +
+                "its use was designed to support displaying data over commercial " + 
+                "basemaps, but that functionality should now be achieved by using " +
+                "Spherical Mercator support. More information is available from " +
+                "http://trac.openlayers.org/wiki/SphericalMercator.",
+'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
+                "Please use {0} instead.",
+'boundsAddError': "You must pass both x and y values to the add function.",
+'lonlatAddError': "You must pass both lon and lat values to the add function.",
+'pixelAddError': "You must pass both x and y values to the add function.",
+'unsupportedGeometryType': "Unsupported geometry type: {0}",
+'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
+                " Please use 'array.length = 0' instead.",
+'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
+                "with the 3.0 version of OpenLayers. Please instead use " +
+                "OpenLayers.Util.getParameters().",
+'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
+                
+'end': ''
+};
\ No newline at end of file

Deleted: sandbox/aboudreault/lib/OpenLayers/Strings/fr.js
===================================================================
--- trunk/lib/OpenLayers/Strings/fr.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/OpenLayers/Strings/fr.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,68 +0,0 @@
-OpenLayers.Strings.fr = {
-'test1': 'ceci est un test',
-'test2': 'et une autre avec des accents: è.ééééé^çà',
-'test3': 'arg un:{0} arg deux: {1} ',
-'unhandledRequest': "Unhandled request return {0}",
-'permalink': "Permalink",
-'overlays': "Overlays",
-'baseLayer': "Base Layer",
-'sameProjection': "The overview map only works when it is in the same projection as the main map",
-'readNotImplemented': "Read not implemented.",
-'writeNotImplemented': "Write not implemented.",
-'noFID': "Can't update a feature for which there is no FID.",
-'errorLoadingGML': "Error in loading GML file {0}",
-'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
-'componentShouldBe': "addFeatures : component should be an {0}",
-'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
-                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
-'minZoomLevelError': "The minZoomLevel property is only intended for use " +
-                    "with the FixedZoomLevels-descendent layers. That this " +
-                    "wfs layer checks for minZoomLevel is a relic of the" +
-                    "past. We cannot, however, remove it without possibly " +
-                    "breaking OL based applications that may depend on it." +
-                    " Therefore we are deprecating it -- the minZoomLevel " +
-                    "check below will be removed at 3.0. Please instead " +
-                    "use min/max resolution setting as described here: " +
-                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
-'commitSuccess': "WFS Transaction: SUCCESS {0}",
-'commitFailed': "WFS Transaction: FAILED {0}",
-'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the Google Maps library " +
-                "script was either not included, or does not contain the " +
-                "correct API key for your site.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/Google' " +
-                "target='_blank'>click here</a>",
-'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
-                "To get rid of this message, select a new BaseLayer " +
-                "in the layer switcher in the upper-right corner.<br><br>" +
-                "Most likely, this is because the {0} library " +
-                "script was either not correctly included.<br><br>" +
-                "Developers: For help getting this working correctly, " +
-                "<a href='http://trac.openlayers.org/wiki/{1}' " +
-                "target='_blank'>click here</a>",
-'scale': "Scale = 1 : {0}",
-'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
-'reprojectDeprecated': "You are using the 'reproject' option " +
-                "on the {0} layer. This option is deprecated: " +
-                "its use was designed to support displaying data over commercial " + 
-                "basemaps, but that functionality should now be achieved by using " +
-                "Spherical Mercator support. More information is available from " +
-                "http://trac.openlayers.org/wiki/SphericalMercator.",
-'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
-                "Please use {0} instead.",
-'boundsAddError': "You must pass both x and y values to the add function.",
-'lonlatAddError': "You must pass both lon and lat values to the add function.",
-'pixelAddError': "You must pass both x and y values to the add function.",
-'unsupportedGeometryType': "Unsupported geometry type: {0}",
-'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
-                " Please use 'array.length = 0' instead.",
-'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
-                "with the 3.0 version of OpenLayers. Please instead use " +
-                "OpenLayers.Util.getParameters().",
-'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
-
-'end': ''
-};
\ No newline at end of file

Copied: sandbox/aboudreault/lib/OpenLayers/Strings/fr.js (from rev 1352, trunk/lib/OpenLayers/Strings/fr.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Strings/fr.js	                        (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Strings/fr.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,68 @@
+OpenLayers.Strings.fr = {
+'test1': 'ceci est un test',
+'test2': 'et une autre avec des accents: è.ééééé^çà',
+'test3': 'arg un:{0} arg deux: {1} ',
+'unhandledRequest': "Unhandled request return {0}",
+'permalink': "Permalink",
+'overlays': "Overlays",
+'baseLayer': "Base Layer",
+'sameProjection': "The overview map only works when it is in the same projection as the main map",
+'readNotImplemented': "Read not implemented.",
+'writeNotImplemented': "Write not implemented.",
+'noFID': "Can't update a feature for which there is no FID.",
+'errorLoadingGML': "Error in loading GML file {0}",
+'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
+'componentShouldBe': "addFeatures : component should be an {0}",
+'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
+                   "This usually means you destroyed a layer, but not some handler which is associated with it.",
+'minZoomLevelError': "The minZoomLevel property is only intended for use " +
+                    "with the FixedZoomLevels-descendent layers. That this " +
+                    "wfs layer checks for minZoomLevel is a relic of the" +
+                    "past. We cannot, however, remove it without possibly " +
+                    "breaking OL based applications that may depend on it." +
+                    " Therefore we are deprecating it -- the minZoomLevel " +
+                    "check below will be removed at 3.0. Please instead " +
+                    "use min/max resolution setting as described here: " +
+                    "http://trac.openlayers.org/wiki/SettingZoomLevels",
+'commitSuccess': "WFS Transaction: SUCCESS {0}",
+'commitFailed': "WFS Transaction: FAILED {0}",
+'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the Google Maps library " +
+                "script was either not included, or does not contain the " +
+                "correct API key for your site.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/Google' " +
+                "target='_blank'>click here</a>",
+'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
+                "To get rid of this message, select a new BaseLayer " +
+                "in the layer switcher in the upper-right corner.<br><br>" +
+                "Most likely, this is because the {0} library " +
+                "script was either not correctly included.<br><br>" +
+                "Developers: For help getting this working correctly, " +
+                "<a href='http://trac.openlayers.org/wiki/{1}' " +
+                "target='_blank'>click here</a>",
+'scale': "Scale = 1 : {0}",
+'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
+'reprojectDeprecated': "You are using the 'reproject' option " +
+                "on the {0} layer. This option is deprecated: " +
+                "its use was designed to support displaying data over commercial " + 
+                "basemaps, but that functionality should now be achieved by using " +
+                "Spherical Mercator support. More information is available from " +
+                "http://trac.openlayers.org/wiki/SphericalMercator.",
+'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
+                "Please use {0} instead.",
+'boundsAddError': "You must pass both x and y values to the add function.",
+'lonlatAddError': "You must pass both lon and lat values to the add function.",
+'pixelAddError': "You must pass both x and y values to the add function.",
+'unsupportedGeometryType': "Unsupported geometry type: {0}",
+'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
+                " Please use 'array.length = 0' instead.",
+'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
+                "with the 3.0 version of OpenLayers. Please instead use " +
+                "OpenLayers.Util.getParameters().",
+'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
+
+'end': ''
+};
\ No newline at end of file


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/blank.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/close.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/drag-rectangle-off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/drag-rectangle-on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/east-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/layer-switcher-maximize.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/layer-switcher-minimize.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/marker-blue.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/marker-gold.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/marker-green.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/marker.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/measuring-stick-off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/measuring-stick-on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/north-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/panning-hand-off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/panning-hand-on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/slider.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/south-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/west-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/zoom-minus-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/zoom-plus-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/zoom-world-mini.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/img/zoombar.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/add_point_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/add_point_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/drag-rectangle-off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/drag-rectangle-on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_line_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_line_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_point_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_point_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_polygon_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/draw_polygon_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/move_feature_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/move_feature_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/pan_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/pan_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/panning-hand-off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/panning-hand-on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/remove_point_off.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/img/remove_point_on.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/lib/OpenLayers/theme/default/style.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/lib/fusion.js
===================================================================
--- sandbox/aboudreault/lib/fusion.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/lib/fusion.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -60,11 +60,27 @@
                         'lib/ClickTool.js',
                         'lib/RectTool.js',
                         'lib/Map.js',
-                        'lib/Search.js'];
+                        'lib/Search.js',
+                        'text/en/strings.json'];
 }
 
 /* bootstrap function that gets everything Fusion needs, loaded */
 Fusion.bootstrap = function() {
+    //determine the language to use and add resource bundles to be loaded to the core scripts
+    var locale = navigator.language ?
+                  navigator.language.substring(0,2):    //e.g. en-CA becomes just en                  
+                  navigator.userLanguage.substring(0,2);//only use the prefix part for now, 
+    var s=window.location.search.toLowerCase();
+    var idx = s.indexOf('locale=');
+    if (idx>0) {
+      locale = s.substring(idx+7,idx+9);
+    }
+    if ( locale!='en' ) {
+      Fusion.coreScripts.push('lib/OpenLayers/Strings/'+locale+'.js');
+      Fusion.coreScripts.push('text/'+locale+'/strings.json');
+    }
+    window._FusionLocale = locale;
+
     var aScripts = document.getElementsByTagName('SCRIPT');
     var gszFusionURL = '';
     for (var i=0; i<aScripts.length; i++) {
@@ -72,6 +88,7 @@
         var n = s.indexOf('lib/fusion.js');
         if (n != -1) {
             gszFusionURL = s.substring(0,n);
+            FusionScriptObject = aScripts[i];
             /* import the compressed version of jx and its CSS */
             Jx.baseURL = gszFusionURL + 'jx/';
             Jx.COMBINED_CSS = true;
@@ -81,7 +98,6 @@
             break;
         }
     }
-    document.write('<style id="fusionStyleSheets" type="text/css"></style>');
 };
 
 Fusion.bootstrap();
@@ -168,6 +184,7 @@
     bForceRedirect : false,
     sScriptLang : "",
     locale : 'en',
+    Strings: {},    //locale specific strings
     
     /** URL to the directory from which fusion.js was loaded */
     fusionURL: null,
@@ -271,14 +288,16 @@
         if (options.applicationDefinition) {
             this.applicationDefinitionURL = options.applicationDefinitionURL;            
         } else {
-            this.applicationDefinitionURL = this.getQueryParam('ApplicationDefinition') || 'ApplicationDefinition.xml';
-            
+            var queryAppDef = this.getQueryParam('ApplicationDefinition');
+            if (queryAppDef) {
+                this.applicationDefinitionURL = queryAppDef.split('+').join(' ');
+            } else {
+                this.applicationDefinitionURL = 'ApplicationDefinition.xml';
+            }
         }
+        
+        this.initializeLocale();
 
-        if (this.getQueryParam('locale').length > 0) {
-          this.locale = this.getQueryParam('locale');
-        }
-
         this.sWebagentURL = "";
         this.sScriptLang = "";
         this.configuration = {};
@@ -335,6 +354,20 @@
         }
     },
     
+    initializeLocale: function(locale) {
+      this.locale = locale ? locale : window._FusionLocale;
+      OpenLayers.String.langCode = this.locale;
+      
+      //check if strings are defined for specified locale, if not, set them to the default locale
+      if (!OpenLayers.Strings[this.locale]) {
+        OpenLayers.Strings[this.locale] = OpenLayers.Strings[OpenLayers.String.defaultLangCode];
+      }
+      if (!Fusion.Strings[this.locale]) {
+        Fusion.Strings[this.locale] = Fusion.Strings[OpenLayers.String.defaultLangCode];
+      }
+      OpenLayers.Util.extend(OpenLayers.Strings[this.locale], Fusion.Strings[this.locale]);
+    },
+    
     /**
      * Function: setLoadState
      *
@@ -436,7 +469,8 @@
      * so we need to decide how to inform the user and fail gracefully.
      */
     scriptFailed: function(url) {
-        Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL, 'failed to load script: ' + url));
+        Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL, 
+                          OpenLayers.String.translate('scriptFailed',url)));
     },
     
     /**
@@ -477,9 +511,15 @@
         var agt=navigator.userAgent.toLowerCase();
         for (var i=this.aLoadingScripts.length-1; i>=0; i--) {
             var s = this.aLoadingScripts[i];
-            if (s.readyState == 'loaded' ||
-                s.readyState == 'complete' ||
-                (agt.indexOf("safari") != -1 && s.readyState == null)) {
+            if (agt.indexOf('safari') != -1) {
+                var widgetName = s.id.substring(s.id.lastIndexOf('/')+1, s.id.indexOf('.js'));
+                var b;
+                eval ('b = typeof Fusion.Widget.'+widgetName+' == "function";');
+                if (b) {
+                    this.scriptLoaded(s.id);
+                }
+            } else if (s.readyState == 'loaded' ||
+                s.readyState == 'complete') {
                 this.scriptLoaded(s.id);
             }
         }
@@ -543,7 +583,7 @@
             this.setLoadState(this.LOAD_CONFIG);
         } else {
             //console.log('Error parsing configuration file, it is not valid somehow?');
-            alert('Error parsing fusion configuration file, initialization aborted');
+            alert(OpenLayers.String.translate('configParseError'));
         }
     },
     
@@ -562,7 +602,7 @@
      */
     serverFailed: function(r) {
         //console.log('error loading server configuration file');
-        alert('Error loading fusion configuration file, initialization aborted'); 
+        alert(OpenLayers.String.translate('configLoadError')); 
     },
     
     /**
@@ -603,7 +643,8 @@
      * Parameter: {Exception} e
      */
     ajaxException: function(r, e) {
-        this.reportError(new Fusion.Error(Fusion.Error.WARNING, "Exception occurred in AJAX callback.\n"+e + "\nLocation: " + e.fileName + ' ('+e.lineNumber+')' + "\n" + e.stack));
+        this.reportError(new Fusion.Error(Fusion.Error.WARNING, 
+          OpenLayers.String.translate('ajaxError', e, e.filename, e.lineNumber, 'xx')));
     },
     
     /**
@@ -852,33 +893,13 @@
         return false;
     },
 
-    getFusionStylesheet: function() {
-        if (!Fusion.styleSheet) {
-            for (var i=0; i<document.styleSheets.length; i++) {
-                var ss = document.styleSheets[i];
-                if (ss.ownerNode && ss.ownerNode.id == 'fusionStyleSheets') {
-                    Fusion.styleSheet = ss;
-                    break;
-                } else if (ss.owningElement && ss.owningElement.id == 'fusionStyleSheets') {
-                    Fusion.styleSheet = ss;
-                    break;
-                }
-            }
-        }
-        return Fusion.styleSheet;
-    },
-
     addWidgetStyleSheet: function(url) {
-        var ss = this.getFusionStylesheet();
-        if (ss) {
-            if (ss.addImport) {
-                ss.addImport(Fusion.getFusionURL() + url);
-            } else if (ss.insertRule) {
-                ss.insertRule('@import url('+Fusion.getFusionURL() + url+');', ss.cssRules.length);
-            }
-        } else {
-            Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 'failed to import stylesheet: ' + url));
-        }
+        var lnk = document.createElement('link');
+        var hd = document.getElementsByTagName('HEAD')[0];
+        hd.insertBefore(lnk, FusionScriptObject);
+        lnk.type = 'text/css';
+        lnk.rel='stylesheet';
+        lnk.href = Fusion.getFusionURL()+url;
     },
 
     parseQueryString: function() {
@@ -945,7 +966,8 @@
      */
     registerEventID : function( eventID ) {
         if (!eventID) {
-            Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 'Error registering eventID, invalid (empty) eventID.'));
+            Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING, 
+                          OpenLayers.String.translate('regsiterEventError')));
         }
         var ev = new String(eventID);
         if (!this.events[eventID]) {

Copied: sandbox/aboudreault/templates (from rev 1352, trunk/templates)

Copied: sandbox/aboudreault/templates/mapguide (from rev 1352, trunk/templates/mapguide)

Copied: sandbox/aboudreault/templates/mapguide/standard (from rev 1352, trunk/templates/mapguide/standard)

Deleted: sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml
===================================================================
--- trunk/templates/mapguide/standard/ApplicationDefinition.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,1036 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ApplicationDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="ApplicationDefinition-1.0.0.xsd">
-
-<!-- ****************************************** 
-* MapSet
-* 
-* Contains the map(s) you want available to your
-* application.
- ****************************************** -->
-
-  <MapSet xsi:type="MapSetType">
-    <MapGroup id="sheboygan" xsi:type="MapType">
-      <Map xsi:type="MapGuideLayerType">
-        <Type>MapGuide</Type>
-        <SingleTile>true</SingleTile>
-        <Extension>
-          <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId>
-        </Extension>
-      </Map>
-    </MapGroup>
-  </MapSet>
-
-<!-- ****************************************** 
-* WidgetSet
-*
-* Contains the widgets you want available to your 
-* application.
- ****************************************** -->
-
-  <WidgetSet xsi:type="WidgetSetType">
-
-<!-- ****************************************** 
-* ContextMenu (Tasks)
-*
-* Menu available to the Task Pane
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>TaskContextMenu</Name>
-      <Type>ContextMenu</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuMeasure</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuBuffer</Widget>
-      </Item>
-    </Container>
-
-<!-- ****************************************** 
-* ContextMenu (Map)
-*
-* Menu available to the Map on right-click
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>MapContextMenu</Name>
-      <Type>ContextMenu</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuRefreshMap</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuPan</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomInRectangle</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomInFixed</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomOutFixed</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="FlyoutItemType">
-        <Function>Flyout</Function>
-        <Label>Zoom</Label>
-        <Tooltip>Open the zoom menu</Tooltip>
-        <ImageUrl/>
-        <ImageClass/>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuInitialMapView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuPreviousView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuNextView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuInitialMapScaleAndCenter</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuZoomSelection</Widget>
-        </Item>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuSelect</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuClearSelection</Widget>
-      </Item>
-      <Item xsi:type="FlyoutItemType">
-        <Function>Flyout</Function>
-        <Label>Select More</Label>
-        <Tooltip>Open the select menu</Tooltip>
-        <ImageUrl/>
-        <ImageClass/>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectRadius</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectPolygon</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectWithin</Widget>
-        </Item>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuBuffer</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuMeasure</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuViewOptions</Widget>
-      </Item>
-
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuHelp</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuAbout</Widget>
-      </Item>
-    </Container>
-
-<!-- ****************************************** 
-* Toolbar (Primary)
-*
-* 
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>Toolbar</Name>
-      <Type>Toolbar</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarHelp</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarViewOptions</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>GetPrintablePage</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>Select</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>Pan</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomInRectangle</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomInFixed</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomOutFixed</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryInitialMapView</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryPreviousView</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryNextView</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryZoomSelection</Widget>
-      </Item>
-    </Container>
-
-
-<!-- ****************************************** 
-* Statusbar (Status Bar)
-*
-* 
- ****************************************** -->
-
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>Statusbar</Name>
-      <Type>Splitterbar</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusCoords</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusSelection</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusScale</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusViewSize</Widget>
-      </Item>
-    </Container>
-
-<!-- ****************************************** 
-* Context Menu - Widgets
-*
-* Widgets belonging to the map context menu
- ****************************************** -->
-
-<!-- CONTEXT MENU PAN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuPan</Name>
-      <Type>Pan</Type>
-      <StatusItem>Drag the map to view areas out of range.</StatusItem>
-      <ImageUrl>images/icons/pan.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Pan mode</Tooltip>
-      <Label>Pan</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM RECTANGLE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomInRectangle</Name>
-      <Type>Zoom</Type>
-      <StatusItem>Zoom in on an area.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Tolerance>5</Tolerance>
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom In</Tooltip>
-      <Label>Zoom Rectangle</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM FIXED (IN) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomInFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom in by a preset increment.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom In</Tooltip>
-      <Label>Zoom In</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU REFRESH MAP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuRefreshMap</Name>
-      <Type>RefreshMap</Type>
-      <StatusItem>Refreshes the map image.</StatusItem>
-      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
-      <Label>Refresh Map</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM FIXED (OUT) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomOutFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom out by a preset increment</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>0.5</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom Out</Tooltip>
-      <Label>Zoom Out</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuInitialMapView</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Fit the extents of the map to the window</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>extent</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map View</Tooltip>
-      <Label>Initial Map View</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU PREVIOUS VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuPreviousView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to previous view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>previous</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-back.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Previous View</Tooltip>
-      <Label>View Previous</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU NEXT VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuNextView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to next view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>next</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-forward.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Next View</Tooltip>
-      <Label>View Next</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuInitialMapScaleAndCenter</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Zoom to initial map center and scale.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>center</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map Center and Scale</Tooltip>
-      <Label>Initial Center and Scale</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomSelection</Name>
-      <Type>ZoomToSelection</Type>
-      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom to selection.</Tooltip>
-      <Label>Zoom Selection</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelect</Name>
-      <Type>Select</Type>
-      <StatusItem>Select features by clicking and dragging.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select mode</Tooltip>
-      <Label>Select mode</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU CLEAR SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuClearSelection</Name>
-      <Type>ClearSelection</Type>
-      <StatusItem>Clears the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-clear.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Clear Selection</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT RADIUS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectRadius</Name>
-      <Type>SelectRadius</Type>
-      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
-      <ImageUrl>images/icons/select-radius.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Radius</Tooltip>
-      <Label>Select Radius</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT POLYGON -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectPolygon</Name>
-      <Type>SelectPolygon</Type>
-      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
-      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Polygon</Tooltip>
-      <Label>Select Polygon</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT WITHIN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectWithin</Name>
-      <Type>SelectWithin</Type>
-      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
-      <ImageUrl>images/icons/select-within.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Within</Tooltip>
-      <Label>Select Within</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU BUFFER -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuBuffer</Name>
-      <Type>BufferPanel</Type>
-      <StatusItem>Create buffers around the selected features</StatusItem>
-      <ImageUrl>images/icons/buffer.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Buffer</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU  VIEW OPTIONS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuViewOptions</Name>
-      <Type>ViewOptions</Type>
-      <StatusItem>Switch between Imperial and Metric units</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <DisplayUnits>meters</DisplayUnits>
-      </Extension>
-      <ImageUrl>images/icons/view-options.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>View Options</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU HELP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuHelp</Name>
-      <Type>Help</Type>
-      <StatusItem/>
-      <ImageUrl>images/icons/help.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Help</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ABOUT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuAbout</Name>
-      <Type>About</Type>
-      <StatusItem/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>About</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU MEASURE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuMeasure</Name>
-      <Type>Measure</Type>
-      <StatusItem>Measure distances on the map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Type>both</Type>
-        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
-        <MeasureTooltipType>dynamic</MeasureTooltipType>
-        <DistancePrecision>0</DistancePrecision>
-        <AreaPrecision>0</AreaPrecision>
-        <Units>meters</Units>
-      </Extension>
-      <ImageUrl>images/icons/measure.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Measure</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- ****************************************** 
-* Toolbar - Widgets
-*
-* Widgets belonging to the main toolbar
- ****************************************** -->
-
-<!-- TOOLBAR BUFFER -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarBuffer</Name>
-      <Type>BufferPanel</Type>
-      <StatusItem>Create buffers around the selected features</StatusItem>
-      <ImageUrl>images/icons/buffer.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Buffer</Label>
-      <Extension>
-        <Target>TaskPane</Target>
-      </Extension>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR REFRESH MAP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarRefreshMap</Name>
-      <Type>RefreshMap</Type>
-      <StatusItem>Refreshes the map image.</StatusItem>
-      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
-      <Label>Refresh Map</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR MEASURE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarMeasure</Name>
-      <Type>Measure</Type>
-      <StatusItem>Measure distances on the map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Type>both</Type>
-        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
-        <MeasureTooltipType>dynamic</MeasureTooltipType>
-        <DistancePrecision>0</DistancePrecision>
-        <AreaPrecision>0</AreaPrecision>
-        <Units>meters</Units>
-        <Target>TaskPane</Target>
-      </Extension>
-      <ImageUrl>images/icons/measure.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Measure</Tooltip>
-      <Label>Measure</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR VIEW OPTIONS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarViewOptions</Name>
-      <Type>ViewOptions</Type>
-      <StatusItem>Switch between Imperial and Metric units</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <DisplayUnits>meters</DisplayUnits>
-      </Extension>
-      <ImageUrl>images/icons/view-options.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>View Options</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR HELP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarHelp</Name>
-      <Type>Help</Type>
-      <StatusItem/>
-      <ImageUrl>images/icons/help.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR ABOUT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarAbout</Name>
-      <Type>About</Type>
-      <StatusItem/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>About</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR CLEAR SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarClearSelection</Name>
-      <Type>ClearSelection</Type>
-      <StatusItem>Clears the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-clear.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR SELECT RADIUS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectRadius</Name>
-      <Type>SelectRadius</Type>
-      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
-      <ImageUrl>images/icons/select-radius.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Radius</Tooltip>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR SELECT POLYGON -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectPolygon</Name>
-      <Type>SelectPolygon</Type>
-      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
-      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Polygon</Tooltip>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Secondary toolbar - Widgets
-*
-* Widgets belonging to the secondary toolbar
- ****************************************** -->
-
-<!-- SECONDARY TOOLBAR INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryInitialMapView</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Fit the extents of the map to the window</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>extent</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR PREVIOUS VIEW-->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryPreviousView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to previous view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>previous</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-back.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Previous View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR NEXT VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryNextView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to next view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>next</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-forward.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Next View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR ZOOM SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryZoomSelection</Name>
-      <Type>ZoomToSelection</Type>
-      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom to selection.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR SELECT WITHIN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectWithin</Name>
-      <Type>SelectWithin</Type>
-      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Within</Tooltip>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Status Bar - Widgets
-*
-* Widgets belonging to the status bar
- ****************************************** -->
-
-<!-- STATUS POSITION -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusCoords</Name>
-      <Type>CursorPosition</Type>
-      <StatusItem/>
-      <Extension xsi:type="CustomContentType">
-        <Template>X: {x} {units}, Y: {y} {units}</Template>
-        <Precision>4</Precision>
-        <EmptyText>&amp;nbsp;</EmptyText>
-      </Extension>
-    </Widget>
-
-<!-- STATUS SELECTION INFO -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusSelection</Name>
-      <Type>SelectionInfo</Type>
-      <StatusItem/>
-      <Extension>
-          <EmptyText>No selection.</EmptyText>
-     </Extension>
-    </Widget>
-
-<!-- STATUS SCALE -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusScale</Name>
-      <Type>EditableScale</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- STATUS VIEWSIZE -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusViewSize</Name>
-      <Type>ViewSize</Type>
-      <StatusItem/>
-      <Extension xsi:type="CustomContentType">
-        <Template>{w} x {h} ({units})</Template>
-        <Precision>2</Precision>
-      </Extension>
-    </Widget>
-
-<!-- ****************************************** 
-* Panels - Widgets
-*
-* Widgets belonging to the status bar
- ****************************************** -->
-
-<!-- LEGEND -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>Legend</Name>
-      <Type>Legend</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- SELECTION -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>SelectionPanel</Name>
-      <Type>SelectionPanel</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- TASKS -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>TaskPane</Name>
-      <Type>TaskPane</Type>
-      <StatusItem/>
-      <Extension>
-        <MenuContainer>TaskContextMenu</MenuContainer>
-      </Extension>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Misc - Widgets
- ****************************************** -->
-
-<!-- INMAP NAVIGATOR -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>Navigator</Name>
-      <Type>Navigator</Type>
-      <Extension xsi:type="CustomContentType">
-      </Extension>
-    </Widget>
-
-<!-- ZOOM IN RECTANGLE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomInRectangle</Name>
-      <Type>Zoom</Type>
-      <StatusItem>Zoom in on an area.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Tolerance>5</Tolerance>
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom in to a rectangular region.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- ZOOM ON CLICK (IN) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomInFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom in by a preset increment.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom in by a fixed factor.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- ZOOM ON CLICK (OUT) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomOutFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom out by a preset increment</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>0.5</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom Out by a fixed factor</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SELECT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>Select</Name>
-      <Type>Select</Type>
-      <StatusItem>Select features by clicking and dragging.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select mode</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- MAPMENU -->
-
-    <Widget>
-      <Name>MapMenu</Name>
-      <Type>MapMenu</Type>
-      <StatusItem/>
-      <Extension/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Maps</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- MAP -->
-
-    <MapWidget xsi:type="WidgetType">
-      <Name>Map</Name>
-      <Type>Map</Type>
-      <StatusItem>The map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <MenuContainer>MapContextMenu</MenuContainer>
-      </Extension>
-      <MapId>sheboygan</MapId>
-    </MapWidget>
-
-<!-- OVERVIEW MAP -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>OverviewMap</Name>
-      <Type>OverviewMap</Type>
-      <Description/>
-      <Extension xsi:type="CustomContentType">
-        <!--MapId>sheboyganOverview</MapId-->
-      </Extension>
-    </Widget>
-
-<!-- PRINT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>GetPrintablePage</Name>
-      <Type>Print</Type>
-      <StatusItem>Get printer-friendly page.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ShowPrintUI>true</ShowPrintUI>
-        <ShowTitle>true</ShowTitle>
-        <PageTitle>Some Title</PageTitle>
-        <ShowLegend>true</ShowLegend>
-        <ShowNorthArrow>true</ShowNorthArrow>
-        <ImageBaseUrl>images/</ImageBaseUrl>
-      </Extension>
-      <ImageUrl>images/icons/file-print.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Get printable page.</Tooltip>
-      <Label></Label>
-      <Disabled/>
-    </Widget>
-
-<!-- PAN -->
-    <Widget xsi:type="UiWidgetType">
-    
-      <Name>Pan</Name>
-      <Type>Pan</Type>
-      <StatusItem>Drag the map to view areas out of range.</StatusItem>
-      <ImageUrl>images/icons/pan.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Pan mode</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-    </WidgetSet>
-
-  <Extension/>
-
-</ApplicationDefinition>

Copied: sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml (from rev 1352, trunk/templates/mapguide/standard/ApplicationDefinition.xml)
===================================================================
--- sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml	                        (rev 0)
+++ sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,1036 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ApplicationDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="ApplicationDefinition-1.0.0.xsd">
+
+<!-- ****************************************** 
+* MapSet
+* 
+* Contains the map(s) you want available to your
+* application.
+ ****************************************** -->
+
+  <MapSet xsi:type="MapSetType">
+    <MapGroup id="sheboygan" xsi:type="MapType">
+      <Map xsi:type="MapGuideLayerType">
+        <Type>MapGuide</Type>
+        <SingleTile>true</SingleTile>
+        <Extension>
+          <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId>
+        </Extension>
+      </Map>
+    </MapGroup>
+  </MapSet>
+
+<!-- ****************************************** 
+* WidgetSet
+*
+* Contains the widgets you want available to your 
+* application.
+ ****************************************** -->
+
+  <WidgetSet xsi:type="WidgetSetType">
+
+<!-- ****************************************** 
+* ContextMenu (Tasks)
+*
+* Menu available to the Task Pane
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>TaskContextMenu</Name>
+      <Type>ContextMenu</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuMeasure</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuBuffer</Widget>
+      </Item>
+    </Container>
+
+<!-- ****************************************** 
+* ContextMenu (Map)
+*
+* Menu available to the Map on right-click
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>MapContextMenu</Name>
+      <Type>ContextMenu</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuRefreshMap</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuPan</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomInRectangle</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomInFixed</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomOutFixed</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="FlyoutItemType">
+        <Function>Flyout</Function>
+        <Label>Zoom</Label>
+        <Tooltip>Open the zoom menu</Tooltip>
+        <ImageUrl/>
+        <ImageClass/>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuInitialMapView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuPreviousView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuNextView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuInitialMapScaleAndCenter</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuZoomSelection</Widget>
+        </Item>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuSelect</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuClearSelection</Widget>
+      </Item>
+      <Item xsi:type="FlyoutItemType">
+        <Function>Flyout</Function>
+        <Label>Select More</Label>
+        <Tooltip>Open the select menu</Tooltip>
+        <ImageUrl/>
+        <ImageClass/>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectRadius</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectPolygon</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectWithin</Widget>
+        </Item>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuBuffer</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuMeasure</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuViewOptions</Widget>
+      </Item>
+
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuHelp</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuAbout</Widget>
+      </Item>
+    </Container>
+
+<!-- ****************************************** 
+* Toolbar (Primary)
+*
+* 
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>Toolbar</Name>
+      <Type>Toolbar</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarHelp</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarViewOptions</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>GetPrintablePage</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>Select</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>Pan</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomInRectangle</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomInFixed</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomOutFixed</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryInitialMapView</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryPreviousView</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryNextView</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryZoomSelection</Widget>
+      </Item>
+    </Container>
+
+
+<!-- ****************************************** 
+* Statusbar (Status Bar)
+*
+* 
+ ****************************************** -->
+
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>Statusbar</Name>
+      <Type>Splitterbar</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusCoords</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusSelection</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusScale</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusViewSize</Widget>
+      </Item>
+    </Container>
+
+<!-- ****************************************** 
+* Context Menu - Widgets
+*
+* Widgets belonging to the map context menu
+ ****************************************** -->
+
+<!-- CONTEXT MENU PAN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuPan</Name>
+      <Type>Pan</Type>
+      <StatusItem>Drag the map to view areas out of range.</StatusItem>
+      <ImageUrl>images/icons/pan.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Pan mode</Tooltip>
+      <Label>Pan</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM RECTANGLE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomInRectangle</Name>
+      <Type>Zoom</Type>
+      <StatusItem>Zoom in on an area.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Tolerance>5</Tolerance>
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom In</Tooltip>
+      <Label>Zoom Rectangle</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM FIXED (IN) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomInFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom in by a preset increment.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom In</Tooltip>
+      <Label>Zoom In</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU REFRESH MAP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuRefreshMap</Name>
+      <Type>RefreshMap</Type>
+      <StatusItem>Refreshes the map image.</StatusItem>
+      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
+      <Label>Refresh Map</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM FIXED (OUT) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomOutFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom out by a preset increment</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>0.5</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom Out</Tooltip>
+      <Label>Zoom Out</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuInitialMapView</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Fit the extents of the map to the window</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>extent</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map View</Tooltip>
+      <Label>Initial Map View</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU PREVIOUS VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuPreviousView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to previous view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>previous</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-back.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Previous View</Tooltip>
+      <Label>View Previous</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU NEXT VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuNextView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to next view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>next</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-forward.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Next View</Tooltip>
+      <Label>View Next</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuInitialMapScaleAndCenter</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Zoom to initial map center and scale.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>center</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map Center and Scale</Tooltip>
+      <Label>Initial Center and Scale</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomSelection</Name>
+      <Type>ZoomToSelection</Type>
+      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom to selection.</Tooltip>
+      <Label>Zoom Selection</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelect</Name>
+      <Type>Select</Type>
+      <StatusItem>Select features by clicking and dragging.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select mode</Tooltip>
+      <Label>Select mode</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU CLEAR SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuClearSelection</Name>
+      <Type>ClearSelection</Type>
+      <StatusItem>Clears the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-clear.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Clear Selection</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT RADIUS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectRadius</Name>
+      <Type>SelectRadius</Type>
+      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
+      <ImageUrl>images/icons/select-radius.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Radius</Tooltip>
+      <Label>Select Radius</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT POLYGON -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectPolygon</Name>
+      <Type>SelectPolygon</Type>
+      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
+      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Polygon</Tooltip>
+      <Label>Select Polygon</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT WITHIN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectWithin</Name>
+      <Type>SelectWithin</Type>
+      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
+      <ImageUrl>images/icons/select-within.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Within</Tooltip>
+      <Label>Select Within</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU BUFFER -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuBuffer</Name>
+      <Type>BufferPanel</Type>
+      <StatusItem>Create buffers around the selected features</StatusItem>
+      <ImageUrl>images/icons/buffer.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Buffer</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU  VIEW OPTIONS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuViewOptions</Name>
+      <Type>ViewOptions</Type>
+      <StatusItem>Switch between Imperial and Metric units</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <DisplayUnits>meters</DisplayUnits>
+      </Extension>
+      <ImageUrl>images/icons/view-options.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>View Options</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU HELP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuHelp</Name>
+      <Type>Help</Type>
+      <StatusItem/>
+      <ImageUrl>images/icons/help.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Help</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ABOUT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuAbout</Name>
+      <Type>About</Type>
+      <StatusItem/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>About</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU MEASURE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuMeasure</Name>
+      <Type>Measure</Type>
+      <StatusItem>Measure distances on the map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Type>both</Type>
+        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
+        <MeasureTooltipType>dynamic</MeasureTooltipType>
+        <DistancePrecision>0</DistancePrecision>
+        <AreaPrecision>0</AreaPrecision>
+        <Units>meters</Units>
+      </Extension>
+      <ImageUrl>images/icons/measure.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Measure</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- ****************************************** 
+* Toolbar - Widgets
+*
+* Widgets belonging to the main toolbar
+ ****************************************** -->
+
+<!-- TOOLBAR BUFFER -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarBuffer</Name>
+      <Type>BufferPanel</Type>
+      <StatusItem>Create buffers around the selected features</StatusItem>
+      <ImageUrl>images/icons/buffer.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Buffer</Label>
+      <Extension>
+        <Target>TaskPane</Target>
+      </Extension>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR REFRESH MAP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarRefreshMap</Name>
+      <Type>RefreshMap</Type>
+      <StatusItem>Refreshes the map image.</StatusItem>
+      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
+      <Label>Refresh Map</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR MEASURE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarMeasure</Name>
+      <Type>Measure</Type>
+      <StatusItem>Measure distances on the map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Type>both</Type>
+        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
+        <MeasureTooltipType>dynamic</MeasureTooltipType>
+        <DistancePrecision>0</DistancePrecision>
+        <AreaPrecision>0</AreaPrecision>
+        <Units>meters</Units>
+        <Target>TaskPane</Target>
+      </Extension>
+      <ImageUrl>images/icons/measure.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Measure</Tooltip>
+      <Label>Measure</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR VIEW OPTIONS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarViewOptions</Name>
+      <Type>ViewOptions</Type>
+      <StatusItem>Switch between Imperial and Metric units</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <DisplayUnits>meters</DisplayUnits>
+      </Extension>
+      <ImageUrl>images/icons/view-options.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>View Options</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR HELP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarHelp</Name>
+      <Type>Help</Type>
+      <StatusItem/>
+      <ImageUrl>images/icons/help.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR ABOUT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarAbout</Name>
+      <Type>About</Type>
+      <StatusItem/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>About</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR CLEAR SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarClearSelection</Name>
+      <Type>ClearSelection</Type>
+      <StatusItem>Clears the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-clear.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR SELECT RADIUS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectRadius</Name>
+      <Type>SelectRadius</Type>
+      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
+      <ImageUrl>images/icons/select-radius.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Radius</Tooltip>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR SELECT POLYGON -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectPolygon</Name>
+      <Type>SelectPolygon</Type>
+      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
+      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Polygon</Tooltip>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Secondary toolbar - Widgets
+*
+* Widgets belonging to the secondary toolbar
+ ****************************************** -->
+
+<!-- SECONDARY TOOLBAR INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryInitialMapView</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Fit the extents of the map to the window</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>extent</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR PREVIOUS VIEW-->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryPreviousView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to previous view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>previous</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-back.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Previous View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR NEXT VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryNextView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to next view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>next</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-forward.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Next View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR ZOOM SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryZoomSelection</Name>
+      <Type>ZoomToSelection</Type>
+      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom to selection.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR SELECT WITHIN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectWithin</Name>
+      <Type>SelectWithin</Type>
+      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Within</Tooltip>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Status Bar - Widgets
+*
+* Widgets belonging to the status bar
+ ****************************************** -->
+
+<!-- STATUS POSITION -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusCoords</Name>
+      <Type>CursorPosition</Type>
+      <StatusItem/>
+      <Extension xsi:type="CustomContentType">
+        <Template>X: {x} {units}, Y: {y} {units}</Template>
+        <Precision>4</Precision>
+        <EmptyText>&amp;nbsp;</EmptyText>
+      </Extension>
+    </Widget>
+
+<!-- STATUS SELECTION INFO -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusSelection</Name>
+      <Type>SelectionInfo</Type>
+      <StatusItem/>
+      <Extension>
+          <EmptyText>No selection.</EmptyText>
+     </Extension>
+    </Widget>
+
+<!-- STATUS SCALE -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusScale</Name>
+      <Type>EditableScale</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- STATUS VIEWSIZE -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusViewSize</Name>
+      <Type>ViewSize</Type>
+      <StatusItem/>
+      <Extension xsi:type="CustomContentType">
+        <Template>{w} x {h} ({units})</Template>
+        <Precision>2</Precision>
+      </Extension>
+    </Widget>
+
+<!-- ****************************************** 
+* Panels - Widgets
+*
+* Widgets belonging to the status bar
+ ****************************************** -->
+
+<!-- LEGEND -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>Legend</Name>
+      <Type>Legend</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- SELECTION -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>SelectionPanel</Name>
+      <Type>SelectionPanel</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- TASKS -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>TaskPane</Name>
+      <Type>TaskPane</Type>
+      <StatusItem/>
+      <Extension>
+        <MenuContainer>TaskContextMenu</MenuContainer>
+      </Extension>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Misc - Widgets
+ ****************************************** -->
+
+<!-- INMAP NAVIGATOR -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>Navigator</Name>
+      <Type>Navigator</Type>
+      <Extension xsi:type="CustomContentType">
+      </Extension>
+    </Widget>
+
+<!-- ZOOM IN RECTANGLE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomInRectangle</Name>
+      <Type>Zoom</Type>
+      <StatusItem>Zoom in on an area.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Tolerance>5</Tolerance>
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom in to a rectangular region.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- ZOOM ON CLICK (IN) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomInFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom in by a preset increment.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom in by a fixed factor.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- ZOOM ON CLICK (OUT) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomOutFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom out by a preset increment</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>0.5</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom Out by a fixed factor</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SELECT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>Select</Name>
+      <Type>Select</Type>
+      <StatusItem>Select features by clicking and dragging.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select mode</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- MAPMENU -->
+
+    <Widget>
+      <Name>MapMenu</Name>
+      <Type>MapMenu</Type>
+      <StatusItem/>
+      <Extension/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Maps</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- MAP -->
+
+    <MapWidget xsi:type="WidgetType">
+      <Name>Map</Name>
+      <Type>Map</Type>
+      <StatusItem>The map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <MenuContainer>MapContextMenu</MenuContainer>
+      </Extension>
+      <MapId>sheboygan</MapId>
+    </MapWidget>
+
+<!-- OVERVIEW MAP -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>OverviewMap</Name>
+      <Type>OverviewMap</Type>
+      <Description/>
+      <Extension xsi:type="CustomContentType">
+        <!--MapId>sheboyganOverview</MapId-->
+      </Extension>
+    </Widget>
+
+<!-- PRINT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>GetPrintablePage</Name>
+      <Type>Print</Type>
+      <StatusItem>Get printer-friendly page.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ShowPrintUI>true</ShowPrintUI>
+        <ShowTitle>true</ShowTitle>
+        <PageTitle>Some Title</PageTitle>
+        <ShowLegend>true</ShowLegend>
+        <ShowNorthArrow>true</ShowNorthArrow>
+        <ImageBaseUrl>images/</ImageBaseUrl>
+      </Extension>
+      <ImageUrl>images/icons/file-print.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Get printable page.</Tooltip>
+      <Label></Label>
+      <Disabled/>
+    </Widget>
+
+<!-- PAN -->
+    <Widget xsi:type="UiWidgetType">
+    
+      <Name>Pan</Name>
+      <Type>Pan</Type>
+      <StatusItem>Drag the map to view areas out of range.</StatusItem>
+      <ImageUrl>images/icons/pan.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Pan mode</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+    </WidgetSet>
+
+  <Extension/>
+
+</ApplicationDefinition>

Copied: sandbox/aboudreault/templates/mapguide/standard/images (from rev 1352, trunk/templates/mapguide/standard/images)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/a_pixel.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/a_pixel.png (from rev 1352, trunk/templates/mapguide/standard/images/a_pixel.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/grab.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/grab.cur (from rev 1352, trunk/templates/mapguide/standard/images/grab.cur)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/grabbing.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/grabbing.cur (from rev 1352, trunk/templates/mapguide/standard/images/grabbing.cur)
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons (from rev 1352, trunk/templates/mapguide/standard/images/icons)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/buffer.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/buffer.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/buffer.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-copy.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-copy.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-copy.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-cut.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-cut.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-cut.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-duplicate.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-duplicate.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-duplicate.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-paste.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-paste.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-paste.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-redo.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-redo.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-redo.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-undo.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/edit-undo.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/edit-undo.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-open.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-open.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/file-open.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-print.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-print.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/file-print.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-save.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/file-save.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/file-save.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/help.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/help.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/help.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-layer.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-layer.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/legend-layer.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-map.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-map.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/legend-map.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-raster.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-raster.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/legend-raster.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-theme.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/legend-theme.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/legend-theme.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/measure.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/measure.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/measure.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/move-down.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/move-down.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/move-down.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/move-up.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/move-up.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/move-up.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/navigator.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/navigator.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/navigator.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-east.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-east.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/pan-east.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-north.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-north.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/pan-north.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-south.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan-south.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/pan-south.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/pan.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/pan.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/search.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/search.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/search.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-attribute.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-attribute.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-attribute.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-centre.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-centre.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-centre.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-clear.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-clear.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-clear.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-features.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-features.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-features.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-polygon.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-polygon.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-polygon.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-query.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-query.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-query.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-radius.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-radius.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-radius.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-rectangle.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-rectangle.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-rectangle.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-zoom.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select-zoom.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select-zoom.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/select.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/select.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/select.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-back.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-back.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/view-back.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-forward.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-forward.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/view-forward.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-refresh.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/view-refresh.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/view-refresh.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/warning.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/warning.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/warning.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/west.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/west.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/west.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-full.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-full.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/zoom-full.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in-fixed.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in-fixed.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/zoom-in-fixed.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-in.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/zoom-in.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out-fixed.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out-fixed.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/zoom-out-fixed.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapguide/standard/images/icons/zoom-out.png (from rev 1352, trunk/templates/mapguide/standard/images/icons/zoom-out.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapguide/standard/index.html
===================================================================
--- trunk/templates/mapguide/standard/index.html	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/templates/mapguide/standard/index.html	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,144 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
-    "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Sample Fusion Application</title>
-<!-- change the source of the following tag to point to your fusion installation -->
-<script type="text/javascript" src="../../../lib/fusion.js"></script>
-
-<style type="text/css">
-    @import url(../../../jx/css/jxskin-border.css);
-
-    .jxSplitterBar {
-        width: 2px;
-        background-color: #999;
-        cursor: 'col-resize';
-    }
-
-    #Toolbar .jxToolbar {
-        /*width: 100%;*/
-    }
-
-    #TaskPane .jxPanelContent {
-        border-left: 1px solid #fff;
-    }
-
-    #Map {
-        position: relative;
-        border-right: 1px solid #999;
-        border-bottom: 1px solid #999;
-    }
-
-    #Statusbar {
-        overflow: hidden;
-        background-color: #d9d9d9;
-        font-family: Arial, Helvetica, sans-serif;
-        font-size: 11px;
-    }
-
-    #Statusbar .jxSplitterBar {
-        width: 1px;
-        border-left: 1px solid #999;
-        border-right: 1px solid #fff;
-        cursor: 'col-resize';
-    }
-
-    #Statusbar .spanCursorPosition,
-    #Statusbar .inputEditableScale,
-    #Statusbar .spanViewSize,
-    #Statusbar .spanSelectionInfo {
-        background-color: #fff;
-        padding: 2px 4px;
-        line-height: 18px;
-    }
-
-
-    li.jxToolItem.activityIndicator {
-        float: right;
-        padding: 6px 3px;
-    }
-
-</style>
-<!--[if IE]>
-<style>
-</style>
-<![endif]-->
-<script type="text/javascript">
-window.onload = function() {
-    /* make 'thePage' just fill the browser window and resize automagically
-       the user resizes the browser */
-    new Jx.Layout('thePage');
-    /* the height of toolbars.  For jxskin-border,
-     * its 28 and for jxskin-graphic its 30 */
-    var h = 28;
-    new Jx.Layout('Main', {bottom: 22, right: 250});
-    new Jx.Layout('Statusbar', {height: 22, top: null});
-    new Jx.Layout('TaskPane', {bottom: 22, width: 250, left: null});
-    new Jx.Layout('Toolbar', {height: h, bottom: null});
-    new Jx.Layout('Splitter', {top: h});
-
-    var splitter = new Jx.Splitter('Splitter', {elements: [$('PanelPane'), $('Map')], containerOptions: [{width: 200}, {}]});
-
-    //new Jx.Splitter('Statusbar', {elements: [$('CursorPosition'), $('SelectionInfo'), $('EditableScale'), $('ViewSize'), $('PoweredBy')], containerOptions: [{}, {}, {}, {}, {width: 143, maxWidth: 143, minWidth: 143}]});
-
-    var p1 = new Jx.Panel({label: 'Legend'});
-    p1.content.id = 'Legend';
-    var p2 = new Jx.Panel({label: 'Selection'});
-    p2.content.id = 'SelectionPanel';
-    var p3 = new Jx.Panel({label: 'Overview Map'});
-    p3.content.id = 'OverviewMap';
-    var pm = new Jx.PanelManager('PanelPane', [p1, p2, p3]);
-
-    $('thePage').resize();
-    $('thePage').style.visibility = 'visible';
-
-    Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, fusionInitialized);
-    Fusion.registerForEvent(Fusion.Event.FUSION_ERROR, fusionError);
-    Fusion.initialize();
-}
-
-function fusionError(eventId, error) {
-    console.log('Fusion Error: \n' + error.toString());
-}
-
-function fusionInitialized() {
-    $('thePage').jxLayout.resize({forceResize:true});
-    $('Toolbar').jxLayout.resize({forceResize:true});
-    //var map = Fusion.getWidgetById('Map');
-    //var l = new Jx.Layout($('Toolbar').childNodes[0]);
-    //l.resize();
-}
-
-</script>
-</head>
-
-<body>
-
-<div id="thePage" style="visibility: hidden">
-
-  <div id="Main">
-    <div id="Toolbar"></div>
-    <div id="Splitter">
-      <div id="PanelPane"></div>
-      <div id="Map">
-        <div id="Navigator"></div>
-      </div>
-    </div>
-  </div>
-
-  <div id="TaskPane"></div>
-  <div id="Statusbar"></div>
-  <div id="PoweredBy" class="statusBarItem">
-    <a href="http://mapserver.gis.umn.edu.org/" target="_blank">
-      <img src="images/PoweredBy_MapServer.gif" width="137" height="18" border="0">
-    </a>
-  </div>
-
-</div>
-
-<div id="BusyIndicator" style="visibility: hidden;">
-  <img src="images/icon_loading.gif" width="30" height="14">
-</div>
-
-</body>
-</html>
\ No newline at end of file

Copied: sandbox/aboudreault/templates/mapguide/standard/index.html (from rev 1352, trunk/templates/mapguide/standard/index.html)
===================================================================
--- sandbox/aboudreault/templates/mapguide/standard/index.html	                        (rev 0)
+++ sandbox/aboudreault/templates/mapguide/standard/index.html	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+    "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Sample Fusion Application</title>
+<!-- change the source of the following tag to point to your fusion installation -->
+<script type="text/javascript" src="../../../lib/fusion.js"></script>
+
+<style type="text/css">
+    @import url(../../../jx/css/jxskin-border.css);
+
+    .jxSplitterBar {
+        width: 2px;
+        background-color: #999;
+        cursor: 'col-resize';
+    }
+
+    #Toolbar .jxToolbar {
+        /*width: 100%;*/
+    }
+
+    #TaskPane .jxPanelContent {
+        border-left: 1px solid #fff;
+    }
+
+    #Map {
+        position: relative;
+        border-right: 1px solid #999;
+        border-bottom: 1px solid #999;
+    }
+
+    #Statusbar {
+        overflow: hidden;
+        background-color: #d9d9d9;
+        font-family: Arial, Helvetica, sans-serif;
+        font-size: 11px;
+    }
+
+    #Statusbar .jxSplitterBar {
+        width: 1px;
+        border-left: 1px solid #999;
+        border-right: 1px solid #fff;
+        cursor: 'col-resize';
+    }
+
+    #Statusbar .spanCursorPosition,
+    #Statusbar .inputEditableScale,
+    #Statusbar .spanViewSize,
+    #Statusbar .spanSelectionInfo {
+        background-color: #fff;
+        padding: 2px 4px;
+        line-height: 18px;
+    }
+
+
+    li.jxToolItem.activityIndicator {
+        float: right;
+        padding: 6px 3px;
+    }
+
+</style>
+<!--[if IE]>
+<style>
+</style>
+<![endif]-->
+<script type="text/javascript">
+window.onload = function() {
+    /* make 'thePage' just fill the browser window and resize automagically
+       the user resizes the browser */
+    new Jx.Layout('thePage');
+    /* the height of toolbars.  For jxskin-border,
+     * its 28 and for jxskin-graphic its 30 */
+    var h = 28;
+    new Jx.Layout('Main', {bottom: 22, right: 250});
+    new Jx.Layout('Statusbar', {height: 22, top: null});
+    new Jx.Layout('TaskPane', {bottom: 22, width: 250, left: null});
+    new Jx.Layout('Toolbar', {height: h, bottom: null});
+    new Jx.Layout('Splitter', {top: h});
+
+    var splitter = new Jx.Splitter('Splitter', {elements: [$('PanelPane'), $('Map')], containerOptions: [{width: 200}, {}]});
+
+    //new Jx.Splitter('Statusbar', {elements: [$('CursorPosition'), $('SelectionInfo'), $('EditableScale'), $('ViewSize'), $('PoweredBy')], containerOptions: [{}, {}, {}, {}, {width: 143, maxWidth: 143, minWidth: 143}]});
+
+    var p1 = new Jx.Panel({label: 'Legend'});
+    p1.content.id = 'Legend';
+    var p2 = new Jx.Panel({label: 'Selection'});
+    p2.content.id = 'SelectionPanel';
+    var p3 = new Jx.Panel({label: 'Overview Map'});
+    p3.content.id = 'OverviewMap';
+    var pm = new Jx.PanelManager('PanelPane', [p1, p2, p3]);
+
+    $('thePage').resize();
+    $('thePage').style.visibility = 'visible';
+
+    Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, fusionInitialized);
+    Fusion.registerForEvent(Fusion.Event.FUSION_ERROR, fusionError);
+    Fusion.initialize();
+}
+
+function fusionError(eventId, error) {
+    console.log('Fusion Error: \n' + error.toString());
+}
+
+function fusionInitialized() {
+    $('thePage').jxLayout.resize({forceResize:true});
+    $('Toolbar').jxLayout.resize({forceResize:true});
+    //var map = Fusion.getWidgetById('Map');
+    //var l = new Jx.Layout($('Toolbar').childNodes[0]);
+    //l.resize();
+}
+
+</script>
+</head>
+
+<body>
+
+<div id="thePage" style="visibility: hidden">
+
+  <div id="Main">
+    <div id="Toolbar"></div>
+    <div id="Splitter">
+      <div id="PanelPane"></div>
+      <div id="Map">
+        <div id="Navigator"></div>
+      </div>
+    </div>
+  </div>
+
+  <div id="TaskPane"></div>
+  <div id="Statusbar"></div>
+  <div id="PoweredBy" class="statusBarItem">
+    <a href="http://mapserver.gis.umn.edu.org/" target="_blank">
+      <img src="images/PoweredBy_MapServer.gif" width="137" height="18" border="0">
+    </a>
+  </div>
+
+</div>
+
+<div id="BusyIndicator" style="visibility: hidden;">
+  <img src="images/icon_loading.gif" width="30" height="14">
+</div>
+
+</body>
+</html>
\ No newline at end of file

Copied: sandbox/aboudreault/templates/mapserver (from rev 1352, trunk/templates/mapserver)

Copied: sandbox/aboudreault/templates/mapserver/standard (from rev 1352, trunk/templates/mapserver/standard)

Deleted: sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml
===================================================================
--- trunk/templates/mapserver/standard/ApplicationDefinition.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,1103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ApplicationDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="ApplicationDefinition-1.0.0.xsd">
-
-<!-- ****************************************** 
-* MapSet
-* 
-* Contains the map(s) you want available to your
-* application.
- ****************************************** -->
-
-  <MapSet xsi:type="MapSetType">
-    <MapGroup id="gmap" xsi:type="MapType">
-      <Map xsi:type="MapLayerType">
-        <Type>MapServer</Type>
-        <SingleTile>true</SingleTile>
-        <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmap75.map</MapFile>
-        </Extension>
-      </Map>
-    </MapGroup>
-    <MapGroup id="mapserverKeymap" xsi:type="MapType">
-      <Map xsi:type="MapLayerType">
-        <Type>MapServer</Type>
-        <SingleTile>true</SingleTile>
-        <Extension>
-            <MapFile>/ms4w/apps/gmap/htdocs/gmap75_key.map</MapFile>
-        </Extension>
-      </Map>
-    </MapGroup>
-  </MapSet>
-
-<!-- ****************************************** 
-* WidgetSet
-*
-* Contains the widgets you want available to your 
-* application.
- ****************************************** -->
-
-  <WidgetSet xsi:type="WidgetSetType">
-
-<!-- ****************************************** 
-* ContextMenu (Tasks)
-*
-* Menu available to the Task Pane
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>TaskContextMenu</Name>
-      <Type>ContextMenu</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuMeasure</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuBuffer</Widget>
-      </Item>
-    </Container>
-
-<!-- ****************************************** 
-* ContextMenu (Map)
-*
-* Menu available to the Map on right-click
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>MapContextMenu</Name>
-      <Type>ContextMenu</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuRefreshMap</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuPan</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomInRectangle</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomInFixed</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuZoomOutFixed</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="FlyoutItemType">
-        <Function>Flyout</Function>
-        <Label>Zoom</Label>
-        <Tooltip>Open the zoom menu</Tooltip>
-        <ImageUrl/>
-        <ImageClass/>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuInitialMapView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuPreviousView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuNextView</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuInitialMapScaleAndCenter</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuZoomSelection</Widget>
-        </Item>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuSelect</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuClearSelection</Widget>
-      </Item>
-      <Item xsi:type="FlyoutItemType">
-        <Function>Flyout</Function>
-        <Label>Select More</Label>
-        <Tooltip>Open the select menu</Tooltip>
-        <ImageUrl/>
-        <ImageClass/>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectRadius</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectPolygon</Widget>
-        </Item>
-        <Item xsi:type="WidgetItemType">
-          <Function>Widget</Function>
-          <Widget>menuSelectWithin</Widget>
-        </Item>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuBuffer</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuMeasure</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuViewOptions</Widget>
-      </Item>
-
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuHelp</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>menuAbout</Widget>
-      </Item>
-    </Container>
-
-<!-- ****************************************** 
-* Toolbar (Primary)
-*
-* 
- ****************************************** -->
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>Toolbar</Name>
-      <Type>Toolbar</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarHelp</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarViewOptions</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>GetPrintablePage</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>Select</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>Pan</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomInRectangle</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomInFixed</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>ZoomOutFixed</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryInitialMapView</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryPreviousView</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryNextView</Widget>
-      </Item>
-      <Item xsi:type="SeparatorItemType">
-        <Function>Separator</Function>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>toolbarSecondaryZoomSelection</Widget>
-      </Item>
-    </Container>
-
-
-<!-- ****************************************** 
-* Statusbar (Status Bar)
-*
-* 
- ****************************************** -->
-
-
-    <Container xsi:type="UiItemContainerType">
-      <Name>Statusbar</Name>
-      <Type>Splitterbar</Type>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusCoords</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusSelection</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusScale</Widget>
-      </Item>
-      <Item xsi:type="WidgetItemType">
-        <Function>Widget</Function>
-        <Widget>StatusViewSize</Widget>
-      </Item>
-    </Container>
-
-   
-<!-- ****************************************** 
-* Placeholder Widget
- ****************************************** -->
-    
-    <Widget xsi:type="WidgetType">
-      <Name>menuPlaceholder</Name>
-      <Type>InvokeScript</Type>
-      <StatusItem/>
-      <Extension>
-        <Script>return true</Script>
-      </Extension>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>menu item</Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Context Menu - Widgets
-*
-* Widgets belonging to the map context menu
- ****************************************** -->
-
-<!-- CONTEXT MENU PAN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuPan</Name>
-      <Type>Pan</Type>
-      <StatusItem>Drag the map to view areas out of range.</StatusItem>
-      <ImageUrl>images/icons/pan.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Pan mode</Tooltip>
-      <Label>Pan</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM RECTANGLE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomInRectangle</Name>
-      <Type>Zoom</Type>
-      <StatusItem>Zoom in on an area.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Tolerance>5</Tolerance>
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom In</Tooltip>
-      <Label>Zoom Rectangle</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM FIXED (IN) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomInFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom in by a preset increment.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom In</Tooltip>
-      <Label>Zoom In</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU REFRESH MAP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuRefreshMap</Name>
-      <Type>RefreshMap</Type>
-      <StatusItem>Refreshes the map image.</StatusItem>
-      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
-      <Label>Refresh Map</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM FIXED (OUT) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomOutFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom out by a preset increment</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>0.5</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom Out</Tooltip>
-      <Label>Zoom Out</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuInitialMapView</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Fit the extents of the map to the window</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>extent</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map View</Tooltip>
-      <Label>Initial Map View</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU PREVIOUS VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuPreviousView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to previous view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>previous</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-back.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Previous View</Tooltip>
-      <Label>View Previous</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU NEXT VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuNextView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to next view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>next</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-forward.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Next View</Tooltip>
-      <Label>View Next</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuInitialMapScaleAndCenter</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Zoom to initial map center and scale.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>center</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map Center and Scale</Tooltip>
-      <Label>Initial Center and Scale</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ZOOM SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuZoomSelection</Name>
-      <Type>ZoomToSelection</Type>
-      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom to selection.</Tooltip>
-      <Label>Zoom Selection</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelect</Name>
-      <Type>Select</Type>
-      <StatusItem>Select features by clicking and dragging.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select mode</Tooltip>
-      <Label>Select mode</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU CLEAR SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuClearSelection</Name>
-      <Type>ClearSelection</Type>
-      <StatusItem>Clears the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-clear.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Clear Selection</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT RADIUS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectRadius</Name>
-      <Type>SelectRadius</Type>
-      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
-      <ImageUrl>images/icons/select-radius.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Radius</Tooltip>
-      <Label>Select Radius</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT POLYGON -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectPolygon</Name>
-      <Type>SelectPolygon</Type>
-      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
-      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Polygon</Tooltip>
-      <Label>Select Polygon</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU SELECT WITHIN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuSelectWithin</Name>
-      <Type>SelectWithin</Type>
-      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
-      <ImageUrl>images/icons/select-within.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Within</Tooltip>
-      <Label>Select Within</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU BUFFER -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuBuffer</Name>
-      <Type>BufferPanel</Type>
-      <StatusItem>Create buffers around the selected features</StatusItem>
-      <ImageUrl>images/icons/buffer.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Buffer</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU  VIEW OPTIONS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuViewOptions</Name>
-      <Type>ViewOptions</Type>
-      <StatusItem>Switch between Imperial and Metric units</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <DisplayUnits>meters</DisplayUnits>
-      </Extension>
-      <ImageUrl>images/icons/view-options.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>View Options</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU HELP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuHelp</Name>
-      <Type>Help</Type>
-      <StatusItem/>
-      <ImageUrl>images/icons/help.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Help</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU ABOUT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuAbout</Name>
-      <Type>About</Type>
-      <StatusItem/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>About</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- CONTEXT MENU MEASURE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>menuMeasure</Name>
-      <Type>Measure</Type>
-      <StatusItem>Measure distances on the map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Type>both</Type>
-        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
-        <MeasureTooltipType>dynamic</MeasureTooltipType>
-        <DistancePrecision>0</DistancePrecision>
-        <AreaPrecision>0</AreaPrecision>
-        <Units>meters</Units>
-      </Extension>
-      <ImageUrl>images/icons/measure.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Measure</Label>
-      <Disabled/>
-    </Widget>
-
-
-<!-- FILE MENU LAUNCH NAVIGATOR -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>showOverviewMap</Name>
-      <Type>InvokeScript</Type>
-      <StatusItem/>
-      <Extension>
-        <Script>showOverviewMap()</Script>
-      </Extension>
-      <ImageUrl>images/icons/navigator.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Launch Overview Map</Tooltip>
-      <Label>Launch Overview Map</Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Toolbar - Widgets
-*
-* Widgets belonging to the main toolbar
- ****************************************** -->
-
-<!-- TOOLBAR BUFFER -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarBuffer</Name>
-      <Type>BufferPanel</Type>
-      <StatusItem>Create buffers around the selected features</StatusItem>
-      <ImageUrl>images/icons/buffer.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Buffer</Tooltip>
-      <Label>Buffer</Label>
-      <Extension>
-        <Target>TaskPane</Target>
-      </Extension>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR REFRESH MAP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarRefreshMap</Name>
-      <Type>RefreshMap</Type>
-      <StatusItem>Refreshes the map image.</StatusItem>
-      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
-      <Label>Refresh Map</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR MEASURE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarMeasure</Name>
-      <Type>Measure</Type>
-      <StatusItem>Measure distances on the map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Type>both</Type>
-        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
-        <MeasureTooltipType>dynamic</MeasureTooltipType>
-        <DistancePrecision>0</DistancePrecision>
-        <AreaPrecision>0</AreaPrecision>
-        <Units>meters</Units>
-        <Target>TaskPane</Target>
-      </Extension>
-      <ImageUrl>images/icons/measure.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Measure</Tooltip>
-      <Label>Measure</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR VIEW OPTIONS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarViewOptions</Name>
-      <Type>ViewOptions</Type>
-      <StatusItem>Switch between Imperial and Metric units</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <DisplayUnits>meters</DisplayUnits>
-      </Extension>
-      <ImageUrl>images/icons/view-options.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>View Options</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR HELP -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarHelp</Name>
-      <Type>Help</Type>
-      <StatusItem/>
-      <ImageUrl>images/icons/help.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Help</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR ABOUT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarAbout</Name>
-      <Type>About</Type>
-      <StatusItem/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>About</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR CLEAR SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarClearSelection</Name>
-      <Type>ClearSelection</Type>
-      <StatusItem>Clears the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-clear.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Clear Selection</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR SELECT RADIUS -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectRadius</Name>
-      <Type>SelectRadius</Type>
-      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
-      <ImageUrl>images/icons/select-radius.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Radius</Tooltip>
-      <Label>Select Radius</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- TOOLBAR SELECT POLYGON -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectPolygon</Name>
-      <Type>SelectPolygon</Type>
-      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
-      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Polygon</Tooltip>
-      <Label>Select Polygon</Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Secondary toolbar - Widgets
-*
-* Widgets belonging to the secondary toolbar
- ****************************************** -->
-
-<!-- SECONDARY TOOLBAR INITIAL MAP VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryInitialMapView</Name>
-      <Type>InitialMapView</Type>
-      <StatusItem>Fit the extents of the map to the window</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ViewType>extent</ViewType>
-      </Extension>
-      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Initial Map View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR PREVIOUS VIEW-->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryPreviousView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to previous view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>previous</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-back.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Previous View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR NEXT VIEW -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryNextView</Name>
-      <Type>ExtentHistory</Type>
-      <StatusItem>Go to next view.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Direction>next</Direction>
-      </Extension>
-      <ImageUrl>images/icons/view-forward.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Next View</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR ZOOM SELECTION -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSecondaryZoomSelection</Name>
-      <Type>ZoomToSelection</Type>
-      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
-      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom to selection.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SECONDARY TOOLBAR SELECT WITHIN -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>toolbarSelectWithin</Name>
-      <Type>SelectWithin</Type>
-      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select Within</Tooltip>
-      <Label>Select Within</Label>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Status Bar - Widgets
-*
-* Widgets belonging to the status bar
- ****************************************** -->
-
-<!-- STATUS POSITION -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusCoords</Name>
-      <Type>CursorPosition</Type>
-      <StatusItem/>
-      <Extension xsi:type="CustomContentType">
-        <Template>X: {x} {units}, Y: {y} {units}</Template>
-        <Precision>4</Precision>
-        <EmptyText>&amp;nbsp;</EmptyText>
-      </Extension>
-    </Widget>
-
-<!-- STATUS SELECTION INFO -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusSelection</Name>
-      <Type>SelectionInfo</Type>
-      <StatusItem/>
-      <Extension>
-          <EmptyText>No selection.</EmptyText>
-     </Extension>
-    </Widget>
-
-<!-- STATUS SCALE -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusScale</Name>
-      <Type>EditableScale</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- STATUS VIEWSIZE -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusViewSize</Name>
-      <Type>ViewSize</Type>
-      <StatusItem/>
-      <Extension xsi:type="CustomContentType">
-        <Template>{w} x {h} ({units})</Template>
-        <Precision>2</Precision>
-      </Extension>
-    </Widget>
-
-<!-- STATUS NAVIGATOR -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>StatusNavigator</Name>
-      <Type>InvokeScript</Type>
-      <StatusItem/>
-      <Extension>
-        <Script>showOverviewMap()</Script>
-      </Extension>
-      <ImageUrl>images/icons/navigator.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Launch Overview Map</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Panels - Widgets
-*
-* Widgets belonging to the status bar
- ****************************************** -->
-
-<!-- LEGEND -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>Legend</Name>
-      <Type>Legend</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- SELECTION -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>SelectionPanel</Name>
-      <Type>SelectionPanel</Type>
-      <StatusItem/>
-    </Widget>
-
-<!-- TASKS -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>TaskPane</Name>
-      <Type>TaskPane</Type>
-      <StatusItem/>
-      <Extension>
-        <MenuContainer>TaskContextMenu</MenuContainer>
-      </Extension>
-    </Widget>
-
-
-
-<!-- ****************************************** 
-* Misc - Widgets
- ****************************************** -->
-
-<!-- INMAP NAVIGATOR -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>Navigator</Name>
-      <Type>Navigator</Type>
-      <Extension xsi:type="CustomContentType">
-      </Extension>
-    </Widget>
-
-<!-- ZOOM IN RECTANGLE -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomInRectangle</Name>
-      <Type>Zoom</Type>
-      <StatusItem>Zoom in on an area.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Tolerance>5</Tolerance>
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom in to a rectangular region.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- ZOOM ON CLICK (IN) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomInFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom in by a preset increment.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>2</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom in by a fixed factor.</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- ZOOM ON CLICK (OUT) -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>ZoomOutFixed</Name>
-      <Type>ZoomOnClick</Type>
-      <StatusItem>Zoom out by a preset increment</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <Factor>0.5</Factor>
-      </Extension>
-      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Zoom Out by a fixed factor</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- SELECT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>Select</Name>
-      <Type>Select</Type>
-      <StatusItem>Select features by clicking and dragging.</StatusItem>
-      <ImageUrl>images/icons/select-features.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Select mode</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-<!-- MAPMENU -->
-
-    <Widget>
-      <Name>MapMenu</Name>
-      <Type>MapMenu</Type>
-      <StatusItem/>
-      <Extension/>
-      <ImageUrl/>
-      <ImageClass/>
-      <Tooltip/>
-      <Label>Maps</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- MAP -->
-
-    <MapWidget xsi:type="WidgetType">
-      <Name>Map</Name>
-      <Type>Map</Type>
-      <StatusItem>The map.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <MenuContainer>MapContextMenu</MenuContainer>
-      </Extension>
-      <MapId>gmap</MapId>
-    </MapWidget>
-
-<!-- OVERVIEW MAP -->
-
-    <Widget xsi:type="WidgetType">
-      <Name>OverviewMap</Name>
-      <Type>OverviewMap</Type>
-      <Description/>
-      <Extension xsi:type="CustomContentType">
-        <!--MapId>sheboyganOverview</MapId-->
-      </Extension>
-    </Widget>
-
-<!-- PRINT -->
-
-    <Widget xsi:type="UiWidgetType">
-      <Name>GetPrintablePage</Name>
-      <Type>Print</Type>
-      <StatusItem>Get printer-friendly page.</StatusItem>
-      <Extension xsi:type="CustomContentType">
-        <ShowPrintUI>true</ShowPrintUI>
-        <ShowTitle>true</ShowTitle>
-        <PageTitle>Some Title</PageTitle>
-        <ShowLegend>true</ShowLegend>
-        <ShowNorthArrow>true</ShowNorthArrow>
-        <ImageBaseUrl>images/</ImageBaseUrl>
-      </Extension>
-      <ImageUrl>images/icons/file-print.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Get printable page.</Tooltip>
-      <Label>Print</Label>
-      <Disabled/>
-    </Widget>
-
-<!-- PAN -->
-    <Widget xsi:type="UiWidgetType">
-    
-      <Name>Pan</Name>
-      <Type>Pan</Type>
-      <StatusItem>Drag the map to view areas out of range.</StatusItem>
-      <ImageUrl>images/icons/pan.png</ImageUrl>
-      <ImageClass/>
-      <Tooltip>Pan mode</Tooltip>
-      <Label/>
-      <Disabled/>
-    </Widget>
-
-    </WidgetSet>
-
-  <Extension/>
-
-</ApplicationDefinition>

Copied: sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml (from rev 1352, trunk/templates/mapserver/standard/ApplicationDefinition.xml)
===================================================================
--- sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml	                        (rev 0)
+++ sandbox/aboudreault/templates/mapserver/standard/ApplicationDefinition.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,1103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ApplicationDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="ApplicationDefinition-1.0.0.xsd">
+
+<!-- ****************************************** 
+* MapSet
+* 
+* Contains the map(s) you want available to your
+* application.
+ ****************************************** -->
+
+  <MapSet xsi:type="MapSetType">
+    <MapGroup id="gmap" xsi:type="MapType">
+      <Map xsi:type="MapLayerType">
+        <Type>MapServer</Type>
+        <SingleTile>true</SingleTile>
+        <Extension>
+            <MapFile>/ms4w/apps/gmap/htdocs/gmap75.map</MapFile>
+        </Extension>
+      </Map>
+    </MapGroup>
+    <MapGroup id="mapserverKeymap" xsi:type="MapType">
+      <Map xsi:type="MapLayerType">
+        <Type>MapServer</Type>
+        <SingleTile>true</SingleTile>
+        <Extension>
+            <MapFile>/ms4w/apps/gmap/htdocs/gmap75_key.map</MapFile>
+        </Extension>
+      </Map>
+    </MapGroup>
+  </MapSet>
+
+<!-- ****************************************** 
+* WidgetSet
+*
+* Contains the widgets you want available to your 
+* application.
+ ****************************************** -->
+
+  <WidgetSet xsi:type="WidgetSetType">
+
+<!-- ****************************************** 
+* ContextMenu (Tasks)
+*
+* Menu available to the Task Pane
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>TaskContextMenu</Name>
+      <Type>ContextMenu</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuMeasure</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuBuffer</Widget>
+      </Item>
+    </Container>
+
+<!-- ****************************************** 
+* ContextMenu (Map)
+*
+* Menu available to the Map on right-click
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>MapContextMenu</Name>
+      <Type>ContextMenu</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuRefreshMap</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuPan</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomInRectangle</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomInFixed</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuZoomOutFixed</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="FlyoutItemType">
+        <Function>Flyout</Function>
+        <Label>Zoom</Label>
+        <Tooltip>Open the zoom menu</Tooltip>
+        <ImageUrl/>
+        <ImageClass/>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuInitialMapView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuPreviousView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuNextView</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuInitialMapScaleAndCenter</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuZoomSelection</Widget>
+        </Item>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuSelect</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuClearSelection</Widget>
+      </Item>
+      <Item xsi:type="FlyoutItemType">
+        <Function>Flyout</Function>
+        <Label>Select More</Label>
+        <Tooltip>Open the select menu</Tooltip>
+        <ImageUrl/>
+        <ImageClass/>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectRadius</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectPolygon</Widget>
+        </Item>
+        <Item xsi:type="WidgetItemType">
+          <Function>Widget</Function>
+          <Widget>menuSelectWithin</Widget>
+        </Item>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuBuffer</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuMeasure</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuViewOptions</Widget>
+      </Item>
+
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuHelp</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>menuAbout</Widget>
+      </Item>
+    </Container>
+
+<!-- ****************************************** 
+* Toolbar (Primary)
+*
+* 
+ ****************************************** -->
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>Toolbar</Name>
+      <Type>Toolbar</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarHelp</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarViewOptions</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>GetPrintablePage</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>Select</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>Pan</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomInRectangle</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomInFixed</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>ZoomOutFixed</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryInitialMapView</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryPreviousView</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryNextView</Widget>
+      </Item>
+      <Item xsi:type="SeparatorItemType">
+        <Function>Separator</Function>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>toolbarSecondaryZoomSelection</Widget>
+      </Item>
+    </Container>
+
+
+<!-- ****************************************** 
+* Statusbar (Status Bar)
+*
+* 
+ ****************************************** -->
+
+
+    <Container xsi:type="UiItemContainerType">
+      <Name>Statusbar</Name>
+      <Type>Splitterbar</Type>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusCoords</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusSelection</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusScale</Widget>
+      </Item>
+      <Item xsi:type="WidgetItemType">
+        <Function>Widget</Function>
+        <Widget>StatusViewSize</Widget>
+      </Item>
+    </Container>
+
+   
+<!-- ****************************************** 
+* Placeholder Widget
+ ****************************************** -->
+    
+    <Widget xsi:type="WidgetType">
+      <Name>menuPlaceholder</Name>
+      <Type>InvokeScript</Type>
+      <StatusItem/>
+      <Extension>
+        <Script>return true</Script>
+      </Extension>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>menu item</Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Context Menu - Widgets
+*
+* Widgets belonging to the map context menu
+ ****************************************** -->
+
+<!-- CONTEXT MENU PAN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuPan</Name>
+      <Type>Pan</Type>
+      <StatusItem>Drag the map to view areas out of range.</StatusItem>
+      <ImageUrl>images/icons/pan.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Pan mode</Tooltip>
+      <Label>Pan</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM RECTANGLE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomInRectangle</Name>
+      <Type>Zoom</Type>
+      <StatusItem>Zoom in on an area.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Tolerance>5</Tolerance>
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom In</Tooltip>
+      <Label>Zoom Rectangle</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM FIXED (IN) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomInFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom in by a preset increment.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom In</Tooltip>
+      <Label>Zoom In</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU REFRESH MAP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuRefreshMap</Name>
+      <Type>RefreshMap</Type>
+      <StatusItem>Refreshes the map image.</StatusItem>
+      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
+      <Label>Refresh Map</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM FIXED (OUT) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomOutFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom out by a preset increment</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>0.5</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom Out</Tooltip>
+      <Label>Zoom Out</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuInitialMapView</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Fit the extents of the map to the window</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>extent</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map View</Tooltip>
+      <Label>Initial Map View</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU PREVIOUS VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuPreviousView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to previous view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>previous</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-back.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Previous View</Tooltip>
+      <Label>View Previous</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU NEXT VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuNextView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to next view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>next</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-forward.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Next View</Tooltip>
+      <Label>View Next</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuInitialMapScaleAndCenter</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Zoom to initial map center and scale.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>center</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map Center and Scale</Tooltip>
+      <Label>Initial Center and Scale</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ZOOM SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuZoomSelection</Name>
+      <Type>ZoomToSelection</Type>
+      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom to selection.</Tooltip>
+      <Label>Zoom Selection</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelect</Name>
+      <Type>Select</Type>
+      <StatusItem>Select features by clicking and dragging.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select mode</Tooltip>
+      <Label>Select mode</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU CLEAR SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuClearSelection</Name>
+      <Type>ClearSelection</Type>
+      <StatusItem>Clears the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-clear.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Clear Selection</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT RADIUS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectRadius</Name>
+      <Type>SelectRadius</Type>
+      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
+      <ImageUrl>images/icons/select-radius.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Radius</Tooltip>
+      <Label>Select Radius</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT POLYGON -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectPolygon</Name>
+      <Type>SelectPolygon</Type>
+      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
+      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Polygon</Tooltip>
+      <Label>Select Polygon</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU SELECT WITHIN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuSelectWithin</Name>
+      <Type>SelectWithin</Type>
+      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
+      <ImageUrl>images/icons/select-within.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Within</Tooltip>
+      <Label>Select Within</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU BUFFER -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuBuffer</Name>
+      <Type>BufferPanel</Type>
+      <StatusItem>Create buffers around the selected features</StatusItem>
+      <ImageUrl>images/icons/buffer.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Buffer</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU  VIEW OPTIONS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuViewOptions</Name>
+      <Type>ViewOptions</Type>
+      <StatusItem>Switch between Imperial and Metric units</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <DisplayUnits>meters</DisplayUnits>
+      </Extension>
+      <ImageUrl>images/icons/view-options.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>View Options</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU HELP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuHelp</Name>
+      <Type>Help</Type>
+      <StatusItem/>
+      <ImageUrl>images/icons/help.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Help</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU ABOUT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuAbout</Name>
+      <Type>About</Type>
+      <StatusItem/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>About</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- CONTEXT MENU MEASURE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>menuMeasure</Name>
+      <Type>Measure</Type>
+      <StatusItem>Measure distances on the map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Type>both</Type>
+        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
+        <MeasureTooltipType>dynamic</MeasureTooltipType>
+        <DistancePrecision>0</DistancePrecision>
+        <AreaPrecision>0</AreaPrecision>
+        <Units>meters</Units>
+      </Extension>
+      <ImageUrl>images/icons/measure.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Measure</Label>
+      <Disabled/>
+    </Widget>
+
+
+<!-- FILE MENU LAUNCH NAVIGATOR -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>showOverviewMap</Name>
+      <Type>InvokeScript</Type>
+      <StatusItem/>
+      <Extension>
+        <Script>showOverviewMap()</Script>
+      </Extension>
+      <ImageUrl>images/icons/navigator.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Launch Overview Map</Tooltip>
+      <Label>Launch Overview Map</Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Toolbar - Widgets
+*
+* Widgets belonging to the main toolbar
+ ****************************************** -->
+
+<!-- TOOLBAR BUFFER -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarBuffer</Name>
+      <Type>BufferPanel</Type>
+      <StatusItem>Create buffers around the selected features</StatusItem>
+      <ImageUrl>images/icons/buffer.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Buffer</Tooltip>
+      <Label>Buffer</Label>
+      <Extension>
+        <Target>TaskPane</Target>
+      </Extension>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR REFRESH MAP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarRefreshMap</Name>
+      <Type>RefreshMap</Type>
+      <StatusItem>Refreshes the map image.</StatusItem>
+      <ImageUrl>images/icons/view-refresh.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Refresh map and reload all layers, keeping the current center point and scale.</Tooltip>
+      <Label>Refresh Map</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR MEASURE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarMeasure</Name>
+      <Type>Measure</Type>
+      <StatusItem>Measure distances on the map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Type>both</Type>
+        <MeasureTooltipContainer>MeasureResult</MeasureTooltipContainer>
+        <MeasureTooltipType>dynamic</MeasureTooltipType>
+        <DistancePrecision>0</DistancePrecision>
+        <AreaPrecision>0</AreaPrecision>
+        <Units>meters</Units>
+        <Target>TaskPane</Target>
+      </Extension>
+      <ImageUrl>images/icons/measure.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Measure</Tooltip>
+      <Label>Measure</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR VIEW OPTIONS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarViewOptions</Name>
+      <Type>ViewOptions</Type>
+      <StatusItem>Switch between Imperial and Metric units</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <DisplayUnits>meters</DisplayUnits>
+      </Extension>
+      <ImageUrl>images/icons/view-options.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>View Options</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR HELP -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarHelp</Name>
+      <Type>Help</Type>
+      <StatusItem/>
+      <ImageUrl>images/icons/help.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Help</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR ABOUT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarAbout</Name>
+      <Type>About</Type>
+      <StatusItem/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>About</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR CLEAR SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarClearSelection</Name>
+      <Type>ClearSelection</Type>
+      <StatusItem>Clears the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-clear.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Clear Selection</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR SELECT RADIUS -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectRadius</Name>
+      <Type>SelectRadius</Type>
+      <StatusItem>Click and drag to select all features inside a circle.</StatusItem>
+      <ImageUrl>images/icons/select-radius.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Radius</Tooltip>
+      <Label>Select Radius</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- TOOLBAR SELECT POLYGON -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectPolygon</Name>
+      <Type>SelectPolygon</Type>
+      <StatusItem>Create a polygon and select all features that fall within.</StatusItem>
+      <ImageUrl>images/icons/select-polygon.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Polygon</Tooltip>
+      <Label>Select Polygon</Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Secondary toolbar - Widgets
+*
+* Widgets belonging to the secondary toolbar
+ ****************************************** -->
+
+<!-- SECONDARY TOOLBAR INITIAL MAP VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryInitialMapView</Name>
+      <Type>InitialMapView</Type>
+      <StatusItem>Fit the extents of the map to the window</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ViewType>extent</ViewType>
+      </Extension>
+      <ImageUrl>images/icons/zoom-full.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Initial Map View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR PREVIOUS VIEW-->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryPreviousView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to previous view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>previous</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-back.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Previous View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR NEXT VIEW -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryNextView</Name>
+      <Type>ExtentHistory</Type>
+      <StatusItem>Go to next view.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Direction>next</Direction>
+      </Extension>
+      <ImageUrl>images/icons/view-forward.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Next View</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR ZOOM SELECTION -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSecondaryZoomSelection</Name>
+      <Type>ZoomToSelection</Type>
+      <StatusItem>Zoom to the extents of the current selection.</StatusItem>
+      <ImageUrl>images/icons/select-zoom.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom to selection.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SECONDARY TOOLBAR SELECT WITHIN -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>toolbarSelectWithin</Name>
+      <Type>SelectWithin</Type>
+      <StatusItem>Select all features that fall within the currently selected area.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select Within</Tooltip>
+      <Label>Select Within</Label>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Status Bar - Widgets
+*
+* Widgets belonging to the status bar
+ ****************************************** -->
+
+<!-- STATUS POSITION -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusCoords</Name>
+      <Type>CursorPosition</Type>
+      <StatusItem/>
+      <Extension xsi:type="CustomContentType">
+        <Template>X: {x} {units}, Y: {y} {units}</Template>
+        <Precision>4</Precision>
+        <EmptyText>&amp;nbsp;</EmptyText>
+      </Extension>
+    </Widget>
+
+<!-- STATUS SELECTION INFO -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusSelection</Name>
+      <Type>SelectionInfo</Type>
+      <StatusItem/>
+      <Extension>
+          <EmptyText>No selection.</EmptyText>
+     </Extension>
+    </Widget>
+
+<!-- STATUS SCALE -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusScale</Name>
+      <Type>EditableScale</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- STATUS VIEWSIZE -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusViewSize</Name>
+      <Type>ViewSize</Type>
+      <StatusItem/>
+      <Extension xsi:type="CustomContentType">
+        <Template>{w} x {h} ({units})</Template>
+        <Precision>2</Precision>
+      </Extension>
+    </Widget>
+
+<!-- STATUS NAVIGATOR -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>StatusNavigator</Name>
+      <Type>InvokeScript</Type>
+      <StatusItem/>
+      <Extension>
+        <Script>showOverviewMap()</Script>
+      </Extension>
+      <ImageUrl>images/icons/navigator.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Launch Overview Map</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Panels - Widgets
+*
+* Widgets belonging to the status bar
+ ****************************************** -->
+
+<!-- LEGEND -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>Legend</Name>
+      <Type>Legend</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- SELECTION -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>SelectionPanel</Name>
+      <Type>SelectionPanel</Type>
+      <StatusItem/>
+    </Widget>
+
+<!-- TASKS -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>TaskPane</Name>
+      <Type>TaskPane</Type>
+      <StatusItem/>
+      <Extension>
+        <MenuContainer>TaskContextMenu</MenuContainer>
+      </Extension>
+    </Widget>
+
+
+
+<!-- ****************************************** 
+* Misc - Widgets
+ ****************************************** -->
+
+<!-- INMAP NAVIGATOR -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>Navigator</Name>
+      <Type>Navigator</Type>
+      <Extension xsi:type="CustomContentType">
+      </Extension>
+    </Widget>
+
+<!-- ZOOM IN RECTANGLE -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomInRectangle</Name>
+      <Type>Zoom</Type>
+      <StatusItem>Zoom in on an area.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Tolerance>5</Tolerance>
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom in to a rectangular region.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- ZOOM ON CLICK (IN) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomInFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom in by a preset increment.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>2</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom in by a fixed factor.</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- ZOOM ON CLICK (OUT) -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>ZoomOutFixed</Name>
+      <Type>ZoomOnClick</Type>
+      <StatusItem>Zoom out by a preset increment</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <Factor>0.5</Factor>
+      </Extension>
+      <ImageUrl>images/icons/zoom-out-fixed.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Zoom Out by a fixed factor</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- SELECT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>Select</Name>
+      <Type>Select</Type>
+      <StatusItem>Select features by clicking and dragging.</StatusItem>
+      <ImageUrl>images/icons/select-features.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Select mode</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+<!-- MAPMENU -->
+
+    <Widget>
+      <Name>MapMenu</Name>
+      <Type>MapMenu</Type>
+      <StatusItem/>
+      <Extension/>
+      <ImageUrl/>
+      <ImageClass/>
+      <Tooltip/>
+      <Label>Maps</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- MAP -->
+
+    <MapWidget xsi:type="WidgetType">
+      <Name>Map</Name>
+      <Type>Map</Type>
+      <StatusItem>The map.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <MenuContainer>MapContextMenu</MenuContainer>
+      </Extension>
+      <MapId>gmap</MapId>
+    </MapWidget>
+
+<!-- OVERVIEW MAP -->
+
+    <Widget xsi:type="WidgetType">
+      <Name>OverviewMap</Name>
+      <Type>OverviewMap</Type>
+      <Description/>
+      <Extension xsi:type="CustomContentType">
+        <!--MapId>sheboyganOverview</MapId-->
+      </Extension>
+    </Widget>
+
+<!-- PRINT -->
+
+    <Widget xsi:type="UiWidgetType">
+      <Name>GetPrintablePage</Name>
+      <Type>Print</Type>
+      <StatusItem>Get printer-friendly page.</StatusItem>
+      <Extension xsi:type="CustomContentType">
+        <ShowPrintUI>true</ShowPrintUI>
+        <ShowTitle>true</ShowTitle>
+        <PageTitle>Some Title</PageTitle>
+        <ShowLegend>true</ShowLegend>
+        <ShowNorthArrow>true</ShowNorthArrow>
+        <ImageBaseUrl>images/</ImageBaseUrl>
+      </Extension>
+      <ImageUrl>images/icons/file-print.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Get printable page.</Tooltip>
+      <Label>Print</Label>
+      <Disabled/>
+    </Widget>
+
+<!-- PAN -->
+    <Widget xsi:type="UiWidgetType">
+    
+      <Name>Pan</Name>
+      <Type>Pan</Type>
+      <StatusItem>Drag the map to view areas out of range.</StatusItem>
+      <ImageUrl>images/icons/pan.png</ImageUrl>
+      <ImageClass/>
+      <Tooltip>Pan mode</Tooltip>
+      <Label/>
+      <Disabled/>
+    </Widget>
+
+    </WidgetSet>
+
+  <Extension/>
+
+</ApplicationDefinition>

Copied: sandbox/aboudreault/templates/mapserver/standard/images (from rev 1352, trunk/templates/mapserver/standard/images)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/PoweredBy_en.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/PoweredBy_en.gif (from rev 1352, trunk/templates/mapserver/standard/images/PoweredBy_en.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/Thumbs.db
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/Thumbs.db (from rev 1352, trunk/templates/mapserver/standard/images/Thumbs.db)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/a_pixel.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/a_pixel.png (from rev 1352, trunk/templates/mapserver/standard/images/a_pixel.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/grab.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/grab.cur (from rev 1352, trunk/templates/mapserver/standard/images/grab.cur)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/grabbing.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/grabbing.cur (from rev 1352, trunk/templates/mapserver/standard/images/grabbing.cur)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_back.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_back.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_back.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_forward.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_forward.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_forward.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_home.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_home.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_home.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_invokeurl.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl_disabled.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_invokeurl_disabled.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_invokeurl_disabled.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_loading.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_loading.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_loading.gif)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icon_tasks.gif
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icon_tasks.gif (from rev 1352, trunk/templates/mapserver/standard/images/icon_tasks.gif)
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons (from rev 1352, trunk/templates/mapserver/standard/images/icons)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/Thumbs.db
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/Thumbs.db (from rev 1352, trunk/templates/mapserver/standard/images/icons/Thumbs.db)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/buffer.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/buffer.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/buffer.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-copy.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-copy.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-copy.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-cut.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-cut.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-cut.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-duplicate.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-duplicate.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-duplicate.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-paste.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-paste.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-paste.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-redo.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-redo.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-redo.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-undo.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/edit-undo.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/edit-undo.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-open.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-open.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/file-open.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-print.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-print.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/file-print.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-save.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/file-save.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/file-save.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/help.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/help.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/help.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-layer.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-layer.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/legend-layer.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-map.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-map.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/legend-map.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-raster.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-raster.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/legend-raster.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-theme.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/legend-theme.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/legend-theme.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/measure.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/measure.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/measure.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/move-down.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/move-down.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/move-down.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/move-up.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/move-up.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/move-up.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/navigator.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/navigator.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/navigator.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-east.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-east.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/pan-east.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-north.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-north.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/pan-north.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-south.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan-south.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/pan-south.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/pan.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/pan.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/search.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/search.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/search.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-attribute.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-attribute.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-attribute.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-centre.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-centre.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-centre.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-clear.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-clear.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-clear.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-features.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-features.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-features.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-polygon.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-polygon.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-polygon.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-query.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-query.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-query.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-radius.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-radius.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-radius.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-rectangle.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-rectangle.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-rectangle.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-zoom.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select-zoom.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select-zoom.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/select.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/select.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/select.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-back.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-back.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/view-back.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-forward.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-forward.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/view-forward.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-refresh.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/view-refresh.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/view-refresh.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/warning.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/warning.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/warning.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/west.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/west.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/west.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-full.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-full.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/zoom-full.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in-fixed.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in-fixed.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/zoom-in-fixed.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-in.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/zoom-in.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out-fixed.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out-fixed.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/zoom-out-fixed.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out.png
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/icons/zoom-out.png (from rev 1352, trunk/templates/mapserver/standard/images/icons/zoom-out.png)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/zoomin.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/zoomin.cur (from rev 1352, trunk/templates/mapserver/standard/images/zoomin.cur)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/images/zoomout.cur
===================================================================
(Binary files differ)

Copied: sandbox/aboudreault/templates/mapserver/standard/images/zoomout.cur (from rev 1352, trunk/templates/mapserver/standard/images/zoomout.cur)
===================================================================
(Binary files differ)

Deleted: sandbox/aboudreault/templates/mapserver/standard/index.html
===================================================================
--- trunk/templates/mapserver/standard/index.html	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/templates/mapserver/standard/index.html	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,144 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
-    "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Sample Fusion Application</title>
-<!-- change the source of the following tag to point to your fusion installation -->
-<script type="text/javascript" src="../../../lib/fusion.js"></script>
-
-<style type="text/css">
-    @import url(../../../jx/css/jxskin-border.css);
-
-    .jxSplitterBar {
-        width: 2px;
-        background-color: #999;
-        cursor: 'col-resize';
-    }
-
-    #Toolbar .jxToolbar {
-        /*width: 100%;*/
-    }
-
-    #TaskPane .jxPanelContent {
-        border-left: 1px solid #fff;
-    }
-
-    #Map {
-        position: relative;
-        border-right: 1px solid #999;
-        border-bottom: 1px solid #999;
-    }
-
-    #Statusbar {
-        overflow: hidden;
-        background-color: #d9d9d9;
-        font-family: Arial, Helvetica, sans-serif;
-        font-size: 11px;
-    }
-
-    #Statusbar .jxSplitterBar {
-        width: 1px;
-        border-left: 1px solid #999;
-        border-right: 1px solid #fff;
-        cursor: 'col-resize';
-    }
-
-    #Statusbar .spanCursorPosition,
-    #Statusbar .inputEditableScale,
-    #Statusbar .spanViewSize,
-    #Statusbar .spanSelectionInfo {
-        background-color: #fff;
-        padding: 2px 4px;
-        line-height: 18px;
-    }
-
-
-    li.jxToolItem.activityIndicator {
-        float: right;
-        padding: 6px 3px;
-    }
-
-</style>
-<!--[if IE]>
-<style>
-</style>
-<![endif]-->
-<script type="text/javascript">
-window.onload = function() {
-    /* make 'thePage' just fill the browser window and resize automagically
-       the user resizes the browser */
-    new Jx.Layout('thePage');
-    /* the height of toolbars.  For jxskin-border,
-     * its 28 and for jxskin-graphic its 30 */
-    var h = 28;
-    new Jx.Layout('Main', {bottom: 22, right: 250});
-    new Jx.Layout('Statusbar', {height: 22, top: null});
-    new Jx.Layout('TaskPane', {bottom: 22, width: 250, left: null});
-    new Jx.Layout('Toolbar', {height: h, bottom: null});
-    new Jx.Layout('Splitter', {top: h});
-
-    var splitter = new Jx.Splitter('Splitter', {elements: [$('PanelPane'), $('Map')], containerOptions: [{width: 200}, {}]});
-
-    //new Jx.Splitter('Statusbar', {elements: [$('CursorPosition'), $('SelectionInfo'), $('EditableScale'), $('ViewSize'), $('PoweredBy')], containerOptions: [{}, {}, {}, {}, {width: 143, maxWidth: 143, minWidth: 143}]});
-
-    var p1 = new Jx.Panel({label: 'Legend'});
-    p1.content.id = 'Legend';
-    var p2 = new Jx.Panel({label: 'Selection'});
-    p2.content.id = 'SelectionPanel';
-    var p3 = new Jx.Panel({label: 'Overview Map'});
-    p3.content.id = 'OverviewMap';
-    var pm = new Jx.PanelManager('PanelPane', [p1, p2, p3]);
-
-    $('thePage').resize();
-    $('thePage').style.visibility = 'visible';
-
-    Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, fusionInitialized);
-    Fusion.registerForEvent(Fusion.Event.FUSION_ERROR, fusionError);
-    Fusion.initialize();
-}
-
-function fusionError(eventId, error) {
-    console.log('Fusion Error: \n' + error.toString());
-}
-
-function fusionInitialized() {
-    $('thePage').jxLayout.resize({forceResize:true});
-    $('Toolbar').jxLayout.resize({forceResize:true});
-    //var map = Fusion.getWidgetById('Map');
-    //var l = new Jx.Layout($('Toolbar').childNodes[0]);
-    //l.resize();
-}
-
-</script>
-</head>
-
-<body>
-
-<div id="thePage" style="visibility: hidden">
-
-  <div id="Main">
-    <div id="Toolbar"></div>
-    <div id="Splitter">
-      <div id="PanelPane"></div>
-      <div id="Map">
-        <div id="Navigator"></div>
-      </div>
-    </div>
-  </div>
-
-  <div id="TaskPane"></div>
-  <div id="Statusbar"></div>
-  <div id="PoweredBy" class="statusBarItem">
-    <a href="http://mapserver.gis.umn.edu.org/" target="_blank">
-      <img src="images/PoweredBy_MapServer.gif" width="137" height="18" border="0">
-    </a>
-  </div>
-
-</div>
-
-<div id="BusyIndicator" style="visibility: hidden;">
-  <img src="images/icon_loading.gif" width="30" height="14">
-</div>
-
-</body>
-</html>
\ No newline at end of file

Copied: sandbox/aboudreault/templates/mapserver/standard/index.html (from rev 1352, trunk/templates/mapserver/standard/index.html)
===================================================================
--- sandbox/aboudreault/templates/mapserver/standard/index.html	                        (rev 0)
+++ sandbox/aboudreault/templates/mapserver/standard/index.html	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+    "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Sample Fusion Application</title>
+<!-- change the source of the following tag to point to your fusion installation -->
+<script type="text/javascript" src="../../../lib/fusion.js"></script>
+
+<style type="text/css">
+    @import url(../../../jx/css/jxskin-border.css);
+
+    .jxSplitterBar {
+        width: 2px;
+        background-color: #999;
+        cursor: 'col-resize';
+    }
+
+    #Toolbar .jxToolbar {
+        /*width: 100%;*/
+    }
+
+    #TaskPane .jxPanelContent {
+        border-left: 1px solid #fff;
+    }
+
+    #Map {
+        position: relative;
+        border-right: 1px solid #999;
+        border-bottom: 1px solid #999;
+    }
+
+    #Statusbar {
+        overflow: hidden;
+        background-color: #d9d9d9;
+        font-family: Arial, Helvetica, sans-serif;
+        font-size: 11px;
+    }
+
+    #Statusbar .jxSplitterBar {
+        width: 1px;
+        border-left: 1px solid #999;
+        border-right: 1px solid #fff;
+        cursor: 'col-resize';
+    }
+
+    #Statusbar .spanCursorPosition,
+    #Statusbar .inputEditableScale,
+    #Statusbar .spanViewSize,
+    #Statusbar .spanSelectionInfo {
+        background-color: #fff;
+        padding: 2px 4px;
+        line-height: 18px;
+    }
+
+
+    li.jxToolItem.activityIndicator {
+        float: right;
+        padding: 6px 3px;
+    }
+
+</style>
+<!--[if IE]>
+<style>
+</style>
+<![endif]-->
+<script type="text/javascript">
+window.onload = function() {
+    /* make 'thePage' just fill the browser window and resize automagically
+       the user resizes the browser */
+    new Jx.Layout('thePage');
+    /* the height of toolbars.  For jxskin-border,
+     * its 28 and for jxskin-graphic its 30 */
+    var h = 28;
+    new Jx.Layout('Main', {bottom: 22, right: 250});
+    new Jx.Layout('Statusbar', {height: 22, top: null});
+    new Jx.Layout('TaskPane', {bottom: 22, width: 250, left: null});
+    new Jx.Layout('Toolbar', {height: h, bottom: null});
+    new Jx.Layout('Splitter', {top: h});
+
+    var splitter = new Jx.Splitter('Splitter', {elements: [$('PanelPane'), $('Map')], containerOptions: [{width: 200}, {}]});
+
+    //new Jx.Splitter('Statusbar', {elements: [$('CursorPosition'), $('SelectionInfo'), $('EditableScale'), $('ViewSize'), $('PoweredBy')], containerOptions: [{}, {}, {}, {}, {width: 143, maxWidth: 143, minWidth: 143}]});
+
+    var p1 = new Jx.Panel({label: 'Legend'});
+    p1.content.id = 'Legend';
+    var p2 = new Jx.Panel({label: 'Selection'});
+    p2.content.id = 'SelectionPanel';
+    var p3 = new Jx.Panel({label: 'Overview Map'});
+    p3.content.id = 'OverviewMap';
+    var pm = new Jx.PanelManager('PanelPane', [p1, p2, p3]);
+
+    $('thePage').resize();
+    $('thePage').style.visibility = 'visible';
+
+    Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, fusionInitialized);
+    Fusion.registerForEvent(Fusion.Event.FUSION_ERROR, fusionError);
+    Fusion.initialize();
+}
+
+function fusionError(eventId, error) {
+    console.log('Fusion Error: \n' + error.toString());
+}
+
+function fusionInitialized() {
+    $('thePage').jxLayout.resize({forceResize:true});
+    $('Toolbar').jxLayout.resize({forceResize:true});
+    //var map = Fusion.getWidgetById('Map');
+    //var l = new Jx.Layout($('Toolbar').childNodes[0]);
+    //l.resize();
+}
+
+</script>
+</head>
+
+<body>
+
+<div id="thePage" style="visibility: hidden">
+
+  <div id="Main">
+    <div id="Toolbar"></div>
+    <div id="Splitter">
+      <div id="PanelPane"></div>
+      <div id="Map">
+        <div id="Navigator"></div>
+      </div>
+    </div>
+  </div>
+
+  <div id="TaskPane"></div>
+  <div id="Statusbar"></div>
+  <div id="PoweredBy" class="statusBarItem">
+    <a href="http://mapserver.gis.umn.edu.org/" target="_blank">
+      <img src="images/PoweredBy_MapServer.gif" width="137" height="18" border="0">
+    </a>
+  </div>
+
+</div>
+
+<div id="BusyIndicator" style="visibility: hidden;">
+  <img src="images/icon_loading.gif" width="30" height="14">
+</div>
+
+</body>
+</html>
\ No newline at end of file

Copied: sandbox/aboudreault/text (from rev 1352, trunk/text)

Copied: sandbox/aboudreault/text/en (from rev 1352, trunk/text/en)

Deleted: sandbox/aboudreault/text/en/strings.json
===================================================================
--- trunk/text/en/strings.json	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/text/en/strings.json	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,49 +0,0 @@
-Fusion.Strings.en = {
-'scriptFailed': 'failed to load script: {0}',
-'configParseError': 'Error parsing fusion configuration file, initialization aborted',
-'configLoadError': 'Error loading fusion configuration file, initialization aborted',
-'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
-'importFailed': 'failed to import stylesheet: {0}',
-'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
-'appDefLoadFailed': 'failed to load: {0}',
-'appDefParseError': 'failed to parse ApplicationDefinition',
-'widgetSetParseError': 'failed to parse the WidgetSet',
-'fusionError': 'Fusion Error: {0}\n{1}',
-'nullExtents': 'Map.setExtents called with null extents',
-'mapLoadError': 'Failed to load requested map:\n{0}',
-'setLayersError': "setLayers failure: {0}",
-'printTitle': 'Printable Page ',
-'noSelection': 'No Selection',
-'selectionInfo': '{0} features selected on {1} layers',
-'attribute': 'Attribute',
-'value': 'Value',
-'taskHome': 'return to the task pane home',
-'prevTask': 'go to previous task executed',
-'nextTask': 'go to next task executed',
-'taskList': 'Task List',
-'taskPane': 'Task Pane',
-'imperial': 'Imperial',
-'metric': 'Metric',
-'deg': 'Degrees',
-'refresh': 'Refresh',
-'expandAll': 'Expand All',
-'expand': 'Expand',
-'collapseAll': 'Collapse All',
-'collapse': 'Collapse',
-'defaultMapTitle': 'Map',
-'legendTitle': 'Legend',
-'selectionPanelTitle': 'Selection',
-'ovmapTitle': 'Overview Map',
-'ovmapTitleShort': 'Overview',
-'taskPaneTitle': 'Tasks',
-'segment': 'Segment {0}',
-'calculating': 'calculating ...',
-'panWest': 'Pan West',
-'panEast': 'Pan East',
-'panSouth': 'Pan South',
-'panNorth': 'Pan North',
-'zoomOut': 'Zoom Out',
-'zoomIn': 'Zoom In',
-
-'end': ''
-};

Copied: sandbox/aboudreault/text/en/strings.json (from rev 1352, trunk/text/en/strings.json)
===================================================================
--- sandbox/aboudreault/text/en/strings.json	                        (rev 0)
+++ sandbox/aboudreault/text/en/strings.json	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,49 @@
+Fusion.Strings.en = {
+'scriptFailed': 'failed to load script: {0}',
+'configParseError': 'Error parsing fusion configuration file, initialization aborted',
+'configLoadError': 'Error loading fusion configuration file, initialization aborted',
+'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
+'importFailed': 'failed to import stylesheet: {0}',
+'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
+'appDefLoadFailed': 'failed to load: {0}',
+'appDefParseError': 'failed to parse ApplicationDefinition',
+'widgetSetParseError': 'failed to parse the WidgetSet',
+'fusionError': 'Fusion Error: {0}\n{1}',
+'nullExtents': 'Map.setExtents called with null extents',
+'mapLoadError': 'Failed to load requested map:\n{0}',
+'setLayersError': "setLayers failure: {0}",
+'printTitle': 'Printable Page ',
+'noSelection': 'No Selection',
+'selectionInfo': '{0} features selected on {1} layers',
+'attribute': 'Attribute',
+'value': 'Value',
+'taskHome': 'return to the task pane home',
+'prevTask': 'go to previous task executed',
+'nextTask': 'go to next task executed',
+'taskList': 'Task List',
+'taskPane': 'Task Pane',
+'imperial': 'Imperial',
+'metric': 'Metric',
+'deg': 'Degrees',
+'refresh': 'Refresh',
+'expandAll': 'Expand All',
+'expand': 'Expand',
+'collapseAll': 'Collapse All',
+'collapse': 'Collapse',
+'defaultMapTitle': 'Map',
+'legendTitle': 'Legend',
+'selectionPanelTitle': 'Selection',
+'ovmapTitle': 'Overview Map',
+'ovmapTitleShort': 'Overview',
+'taskPaneTitle': 'Tasks',
+'segment': 'Segment {0}',
+'calculating': 'calculating ...',
+'panWest': 'Pan West',
+'panEast': 'Pan East',
+'panSouth': 'Pan South',
+'panNorth': 'Pan North',
+'zoomOut': 'Zoom Out',
+'zoomIn': 'Zoom In',
+
+'end': ''
+};

Deleted: sandbox/aboudreault/text/en/strings.php
===================================================================
--- trunk/text/en/strings.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/text/en/strings.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,240 +0,0 @@
-# Web surround localized strings
-# English language
-#
-# Important: This file must be saved with UTF-8 encoding
-#
-
-# General
-
-# Fonts - the 6 following entries are mandatory
- at fontWindows        = Arial
- at fontsizeWindows    = 8pt
- at fontLinux          = Arial
- at fontsizeLinux      = 8pt
- at fontMacintosh      = Arial
- at fontsizeMacintosh  = 8pt
-
-# Distances
-DISTANCEMILES       = Miles
-DISTANCEKILOMETERS  = Kilometers
-DISTANCEFEET        = Feet
-DISTANCEMETERS      = Meters
-
-# Fill Patterns/Values
-FILLSOLID           = Solid
-FILLNET             = Net
-FILLLINE            = Line
-FILLLINE45          = Line_45
-FILLLINE90          = Line_90
-FILLLINE135         = Line_135
-FILLSQUARE          = Square
-FILLBOX             = Box
-FILLCROSS           = Cross
-FILLDASH            = Dash
-FILLDOLMIT          = Dolmit
-FILLHEX             = Hex
-FILLSACNCR          = Sacncr
-FILLSTEEL           = Steel
-
-# Transparency
-TRANSPARENT         = transparent
-
-# Line Styles/Values
-LINESOLID           = Solid
-LINEDASH            = Dash
-LINEDOT             = Dot
-LINEDASHDOT         = DashDot
-LINEDASHDOTDOT      = DashDotDot
-LINERAIL            = Rail
-LINEBORDER          = Border
-LINEDIVIDE          = Divide
-LINEFENCELINE       = FenceLine
-
-# Buttons
-BUTTONOK            = OK
-BUTTONDONE          = Done
-BUTTONCANCEL        = Cancel
-BUTTONREFRESH       = Refresh
-BUTTONCLOSE         = Close
-BUTTONCLEAR         = Clear
-BUTTONSAVE          = Save
-
-# Colors
-COLORRED            = Red
-COLORGREEN          = Green
-COLORBLUE           = Blue
-
-# BufferReport
-BUFFERREPORTTITLE               = Create Buffer
-BUFFERREPORTCREATED             = %s has been created.
-BUFFERREPORTUPDATED             = %s has been updated.
-BUFFERREPORTFEATURESSINGULAR    = %s buffer feature was created.
-BUFFERREPORTFEATURESPLURAL      = %s buffer features were created.
-BUFFERREPORTWARNINGSINGULAR     = <b>Warning:</b> %s layer was excluded from buffer computation because its coordinate system is incompatible with the coordinate system of the map, or because it has no coordinate system at all
-BUFFERREPORTWARNINGPLURAL       = <b>Warning:</b> %s layers were excluded from buffer computation because their coordinate systems are incompatible with the coordinate system of the map, or because they have no coordinate system at all
-BUFFERREPORTERRORTITLE          = Buffer Error
-
-# Buffer
-BUFFERCLASSDESCR                = Feature class for buffer layer
-BUFFERSCHEMADESCR               = Temporary buffer schema
-BUFFERDIFFARBXY                 = Cannot compute a unique buffer around features with different 'Arbitrary X-Y' coordinate systems. Please uncheck the option 'Merge buffer areas' or select only one layer
-
-# BufferUI
-BUFFERTITLE                     = Create a Buffer
-BUFFERSUBTITLE                  = &nbsp;Buffer settings
-BUFFERINFOTEXT                  = Select features on the image.
-BUFFERDISTANCE                  = Distance around features:
-BUFFERLAYERS                    = Layers to include in the buffer:
-BUFFERNOLAYER                   = <No layer selected>
-BUFFERNAME                      = Name for the resulting buffer layer:
-BUFFERNAMETEXT                  = Buffer 1
-BUFFERMERGE                     = Merge buffer areas
-BUFFERFILLSTYLE                 = &nbsp;Fill style
-BUFFERFILLPATTERN               = Fill pattern:
-BUFFERFOREGROUNDCOLOR           = Foreground color:
-BUFFERTRANSPARENCY              = Transparency:
-BUFFERBACKGROUNDCOLOR           = Background color:
-BUFFERBORDERSTYLE               = &nbsp;Border style
-BUFFERBORDERLINEPATTERN         = Line pattern:
-BUFFERBORDERLINECOLOR           = Line color:
-BUFFERBORDERLINETHICKNESS       = Line thickness:
-BUFFERHELP                      = <li><p align="left">Results of the buffer are put into a new layer above the top feature layer. This buffer layer has the name you enter here.</li><li><p align="left">To create multiple buffer layers, use different buffer names.</li><li><p align="left">To hide buffer layers, turn them off.</li><li><p align="left">Buffer layers are temporary and are removed when you close the viewer.</li>
-BUFFERERRORZERODISTANCE         = Please enter a nonzero distance.
-BUFFERERRORNOLAYERNAME          = Please enter a layer name.
-BUFFERERRORNEGATIVETHICKNESS    = Please enter positive or null thickness.
-BUFFERERRORNOSELECTION          = Please select feature(s) to calculate a buffer around.
-
-# ColorPicker
-COLORPICKERDLGTITLE             = Select a color
-COLORPICKERTITLE                = Color palette
-COLORPICKERSUBTITLE             = Specify a color
-COLORPICKER100TRANSPARENCY      = 100%% transparency
-COLORPICKERHEXFORMAT            = Hex format
-
-# MeasureUI
-MEASURETITLE            = Measure Distance
-MEASUREINFO             = Click a start and end point.
-RESUME                  = Resume
-STOP                    = Stop
-CLEAR                   = Clear
-MILES                   = Miles
-KILOMETERS              = Kilometers
-MEASUREHELP             = <li>To measure multiple distances, continue clicking new points.</li><li>To finish, click &quot;Stop&quot;.</li><li>You can pan or zoom and continue measuring by clicking &quot;Resume&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
-SEGMENT                 = Segment
-TOTAL                   = Total
-LENGTH                  = Length
-MEASUREERROR            = Measure Error
-
-# Measure
-MEASUREFEATURECLASS     = Feature class for measure layer
-MEASURESCHEMADESCR      = Temporary measure schema
-MEASUREPARTIAL          = Partial
-MEASURETOTAL            = total
-MEASURELAYER            = Measure
-
-# HtmlViewerAbout
-HTMLABOUTTITLE          = About %s
-HTMLABOUTTITLEBAR       = MapGuide Viewer
-HTMLABOUTSERVERTITLE    = MapGuide Server
-HTMLABOUTVIEWERTITLE    = MapGuide Viewer
-HTMLABOUTSERVERVERSION  = %s (Version %s)
-HTMLABOUTVIEWERVERSION  = %s (Version %s)
-HTMLABOUTTEXT           = <br>This product is made available subject to the terms of GNU Lesser General Public License Version 2.1 ("LGPL").  A copy of the LGPL, as well as additional copyright notices and license terms applicable to portions of this product are set forth in the <a href="../localized/license_en.htm" target="blank">license</a> file.<br><br>All trademarks and registered trademarks mentioned herein are the property of their respective owners.<br><br>Copyright &copy; 2007 Autodesk, Inc.<br><br>
-HTMLABOUTLICENSE        = license file
-HTMLABOUTLICENSEFILE    = license_en.htm
-
-# LegendUI
-LEGENDLISTSEPARATOR     = ,
-
-# PrintablePageUi
-PRINTTITLE              = Get Printable Page
-PRINTELEMENTS           = Select the elements to include in the print layout.
-PRINTPAGETITLE          = Page title:
-PRINTLEGEND             = Legend
-PRINTNORTHARROW         = North arrow
-PRINTCREATEPAGE         = Create Page
-
-# PropertyCtrl
-PROPERTIESNONE          = None Selected
-PROPERTIESNAME          = Name
-PROPERTIESVALUE         = Value
-PROPERTIESITEMSEL       = Items selected: {0}
-
-# Search
-SEARCHDLGTITLE          = Search features
-SEARCHTITLE             = Search results
-SEARCHERROR             = Search error
-SEARCHREPORT            = Search report
-SEARCHLAYERNOTFOUND     = Layer {0} not found!
-SEARCHNOMULTIPROP       = Multi-properties identity not supported yet
-SEARCHTYYPENOTSUP       = Identity property type not supported yet ({0})
-SEARCHNOMATCHES         = No matches.
-
-# SearchPrompt
-SEARCHPROMPTFIND        = Find
-
-# SelectWithinUi
-SELECTWITHINTITLE       = Select Within
-SELECTWITHINAREAS       = Select areas on the image.
-SELECTWITHINRESTRICTION = Restrict results to selected layers:
-SELECTWITHINTEXT        = <li>If you continue to select areas on the image, click &quot;Refresh&quot; to update the layer list.</li><li>To finish and select all features within the highlighted areas, click &quot;Done&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
-
-# Error/Report
-REPORTTITLE             = Report
-
-# Legend UI
-REFRESH                 = Refresh
-EXPANDALL               = Expand
-COLLAPSEALL             = Collapse All
-DISPLAYALLINGROUP       = Display All in Group
-HIDEALLINGROUP          = Hide All in Group
-SHOWLONGTHEME           = Show Long Theme
-
-# Task Bar
-TASKS                   = Tasks
-
-# Viewer Options
-OPTIONSTITLE            = Viewer Options
-OPTIONSINFOTEXT         = Select viewing options for status bar and tool tips.
-OPTIONSDISTANCE         = Display distances in
-OPTIONSMETRIC           = Metric (Kilometers, Meters)
-OPTIONSUSENGLISH        = US/English (Miles, Feet)
-OPTIONSPOSITION         = Display cursor position in
-OPTIONSLATLON           = Latitude, Longitude (Degrees)
-OPTIONSMAPUNITS         = Map Coordinate System (X,Y)
-
-# AJAX Viewer
-VIEWERLAYERS            = Layers
-VIEWERPROPS             = Properties
-VIEWERPANNORTH          = Pan North
-VIEWERPANWEST           = Pan West
-VIEWERPANSOUTH          = Pan South
-VIEWERPANEAST           = Pan East
-VIEWERZOOMIN            = Zoom In
-VIEWERZOOMOUT           = Zoom Out
-VIEWERMOVESLIDER        = Drag to move slider
-VIEWERDRAGZOOM          = Drag to zoom
-ENDSEL                  = CTRL + click to end
-ENDSELSAFARI            = SHIFT + click to end
-DECIMALSEPARATOR        = .
-THOUSANDSEPARATOR       = ,
-
-# Main Frame
-NEEDLOGIN               = You must enter a valid login ID and password to access this site
-ALREADYINMEASURE        = Only one measure command is allowed in a web layout
-ACCESSDENIED            = Access Denied   
-LATLONCURPOS            = Lat: {0}, Lon: {1}
-MAPUNITSCURPOS          = X: {0}, Y: {1}
-FEATURESSELECTED        = {0} features selected
-FEATURESELECTED         = {0} feature selected
-MI                      = mi
-FT                      = ft
-IN                      = in
-KM                      = km
-MT                      = m
-CM                      = cm
-DIGALREADYRUNNING       = Cannot execute measure: A digitization command is in progress.
-MEASALREADYRUNNING      = Cannot execute digitization: A measure is in progress.
-
-# Localized Icon Files
-POWEREDBYICON           = PoweredBy_en.gif

Copied: sandbox/aboudreault/text/en/strings.php (from rev 1352, trunk/text/en/strings.php)
===================================================================
--- sandbox/aboudreault/text/en/strings.php	                        (rev 0)
+++ sandbox/aboudreault/text/en/strings.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,240 @@
+# Web surround localized strings
+# English language
+#
+# Important: This file must be saved with UTF-8 encoding
+#
+
+# General
+
+# Fonts - the 6 following entries are mandatory
+ at fontWindows        = Arial
+ at fontsizeWindows    = 8pt
+ at fontLinux          = Arial
+ at fontsizeLinux      = 8pt
+ at fontMacintosh      = Arial
+ at fontsizeMacintosh  = 8pt
+
+# Distances
+DISTANCEMILES       = Miles
+DISTANCEKILOMETERS  = Kilometers
+DISTANCEFEET        = Feet
+DISTANCEMETERS      = Meters
+
+# Fill Patterns/Values
+FILLSOLID           = Solid
+FILLNET             = Net
+FILLLINE            = Line
+FILLLINE45          = Line_45
+FILLLINE90          = Line_90
+FILLLINE135         = Line_135
+FILLSQUARE          = Square
+FILLBOX             = Box
+FILLCROSS           = Cross
+FILLDASH            = Dash
+FILLDOLMIT          = Dolmit
+FILLHEX             = Hex
+FILLSACNCR          = Sacncr
+FILLSTEEL           = Steel
+
+# Transparency
+TRANSPARENT         = transparent
+
+# Line Styles/Values
+LINESOLID           = Solid
+LINEDASH            = Dash
+LINEDOT             = Dot
+LINEDASHDOT         = DashDot
+LINEDASHDOTDOT      = DashDotDot
+LINERAIL            = Rail
+LINEBORDER          = Border
+LINEDIVIDE          = Divide
+LINEFENCELINE       = FenceLine
+
+# Buttons
+BUTTONOK            = OK
+BUTTONDONE          = Done
+BUTTONCANCEL        = Cancel
+BUTTONREFRESH       = Refresh
+BUTTONCLOSE         = Close
+BUTTONCLEAR         = Clear
+BUTTONSAVE          = Save
+
+# Colors
+COLORRED            = Red
+COLORGREEN          = Green
+COLORBLUE           = Blue
+
+# BufferReport
+BUFFERREPORTTITLE               = Create Buffer
+BUFFERREPORTCREATED             = %s has been created.
+BUFFERREPORTUPDATED             = %s has been updated.
+BUFFERREPORTFEATURESSINGULAR    = %s buffer feature was created.
+BUFFERREPORTFEATURESPLURAL      = %s buffer features were created.
+BUFFERREPORTWARNINGSINGULAR     = <b>Warning:</b> %s layer was excluded from buffer computation because its coordinate system is incompatible with the coordinate system of the map, or because it has no coordinate system at all
+BUFFERREPORTWARNINGPLURAL       = <b>Warning:</b> %s layers were excluded from buffer computation because their coordinate systems are incompatible with the coordinate system of the map, or because they have no coordinate system at all
+BUFFERREPORTERRORTITLE          = Buffer Error
+
+# Buffer
+BUFFERCLASSDESCR                = Feature class for buffer layer
+BUFFERSCHEMADESCR               = Temporary buffer schema
+BUFFERDIFFARBXY                 = Cannot compute a unique buffer around features with different 'Arbitrary X-Y' coordinate systems. Please uncheck the option 'Merge buffer areas' or select only one layer
+
+# BufferUI
+BUFFERTITLE                     = Create a Buffer
+BUFFERSUBTITLE                  = &nbsp;Buffer settings
+BUFFERINFOTEXT                  = Select features on the image.
+BUFFERDISTANCE                  = Distance around features:
+BUFFERLAYERS                    = Layers to include in the buffer:
+BUFFERNOLAYER                   = <No layer selected>
+BUFFERNAME                      = Name for the resulting buffer layer:
+BUFFERNAMETEXT                  = Buffer 1
+BUFFERMERGE                     = Merge buffer areas
+BUFFERFILLSTYLE                 = &nbsp;Fill style
+BUFFERFILLPATTERN               = Fill pattern:
+BUFFERFOREGROUNDCOLOR           = Foreground color:
+BUFFERTRANSPARENCY              = Transparency:
+BUFFERBACKGROUNDCOLOR           = Background color:
+BUFFERBORDERSTYLE               = &nbsp;Border style
+BUFFERBORDERLINEPATTERN         = Line pattern:
+BUFFERBORDERLINECOLOR           = Line color:
+BUFFERBORDERLINETHICKNESS       = Line thickness:
+BUFFERHELP                      = <li><p align="left">Results of the buffer are put into a new layer above the top feature layer. This buffer layer has the name you enter here.</li><li><p align="left">To create multiple buffer layers, use different buffer names.</li><li><p align="left">To hide buffer layers, turn them off.</li><li><p align="left">Buffer layers are temporary and are removed when you close the viewer.</li>
+BUFFERERRORZERODISTANCE         = Please enter a nonzero distance.
+BUFFERERRORNOLAYERNAME          = Please enter a layer name.
+BUFFERERRORNEGATIVETHICKNESS    = Please enter positive or null thickness.
+BUFFERERRORNOSELECTION          = Please select feature(s) to calculate a buffer around.
+
+# ColorPicker
+COLORPICKERDLGTITLE             = Select a color
+COLORPICKERTITLE                = Color palette
+COLORPICKERSUBTITLE             = Specify a color
+COLORPICKER100TRANSPARENCY      = 100%% transparency
+COLORPICKERHEXFORMAT            = Hex format
+
+# MeasureUI
+MEASURETITLE            = Measure Distance
+MEASUREINFO             = Click a start and end point.
+RESUME                  = Resume
+STOP                    = Stop
+CLEAR                   = Clear
+MILES                   = Miles
+KILOMETERS              = Kilometers
+MEASUREHELP             = <li>To measure multiple distances, continue clicking new points.</li><li>To finish, click &quot;Stop&quot;.</li><li>You can pan or zoom and continue measuring by clicking &quot;Resume&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
+SEGMENT                 = Segment
+TOTAL                   = Total
+LENGTH                  = Length
+MEASUREERROR            = Measure Error
+
+# Measure
+MEASUREFEATURECLASS     = Feature class for measure layer
+MEASURESCHEMADESCR      = Temporary measure schema
+MEASUREPARTIAL          = Partial
+MEASURETOTAL            = total
+MEASURELAYER            = Measure
+
+# HtmlViewerAbout
+HTMLABOUTTITLE          = About %s
+HTMLABOUTTITLEBAR       = MapGuide Viewer
+HTMLABOUTSERVERTITLE    = MapGuide Server
+HTMLABOUTVIEWERTITLE    = MapGuide Viewer
+HTMLABOUTSERVERVERSION  = %s (Version %s)
+HTMLABOUTVIEWERVERSION  = %s (Version %s)
+HTMLABOUTTEXT           = <br>This product is made available subject to the terms of GNU Lesser General Public License Version 2.1 ("LGPL").  A copy of the LGPL, as well as additional copyright notices and license terms applicable to portions of this product are set forth in the <a href="../localized/license_en.htm" target="blank">license</a> file.<br><br>All trademarks and registered trademarks mentioned herein are the property of their respective owners.<br><br>Copyright &copy; 2007 Autodesk, Inc.<br><br>
+HTMLABOUTLICENSE        = license file
+HTMLABOUTLICENSEFILE    = license_en.htm
+
+# LegendUI
+LEGENDLISTSEPARATOR     = ,
+
+# PrintablePageUi
+PRINTTITLE              = Get Printable Page
+PRINTELEMENTS           = Select the elements to include in the print layout.
+PRINTPAGETITLE          = Page title:
+PRINTLEGEND             = Legend
+PRINTNORTHARROW         = North arrow
+PRINTCREATEPAGE         = Create Page
+
+# PropertyCtrl
+PROPERTIESNONE          = None Selected
+PROPERTIESNAME          = Name
+PROPERTIESVALUE         = Value
+PROPERTIESITEMSEL       = Items selected: {0}
+
+# Search
+SEARCHDLGTITLE          = Search features
+SEARCHTITLE             = Search results
+SEARCHERROR             = Search error
+SEARCHREPORT            = Search report
+SEARCHLAYERNOTFOUND     = Layer {0} not found!
+SEARCHNOMULTIPROP       = Multi-properties identity not supported yet
+SEARCHTYYPENOTSUP       = Identity property type not supported yet ({0})
+SEARCHNOMATCHES         = No matches.
+
+# SearchPrompt
+SEARCHPROMPTFIND        = Find
+
+# SelectWithinUi
+SELECTWITHINTITLE       = Select Within
+SELECTWITHINAREAS       = Select areas on the image.
+SELECTWITHINRESTRICTION = Restrict results to selected layers:
+SELECTWITHINTEXT        = <li>If you continue to select areas on the image, click &quot;Refresh&quot; to update the layer list.</li><li>To finish and select all features within the highlighted areas, click &quot;Done&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
+
+# Error/Report
+REPORTTITLE             = Report
+
+# Legend UI
+REFRESH                 = Refresh
+EXPANDALL               = Expand
+COLLAPSEALL             = Collapse All
+DISPLAYALLINGROUP       = Display All in Group
+HIDEALLINGROUP          = Hide All in Group
+SHOWLONGTHEME           = Show Long Theme
+
+# Task Bar
+TASKS                   = Tasks
+
+# Viewer Options
+OPTIONSTITLE            = Viewer Options
+OPTIONSINFOTEXT         = Select viewing options for status bar and tool tips.
+OPTIONSDISTANCE         = Display distances in
+OPTIONSMETRIC           = Metric (Kilometers, Meters)
+OPTIONSUSENGLISH        = US/English (Miles, Feet)
+OPTIONSPOSITION         = Display cursor position in
+OPTIONSLATLON           = Latitude, Longitude (Degrees)
+OPTIONSMAPUNITS         = Map Coordinate System (X,Y)
+
+# AJAX Viewer
+VIEWERLAYERS            = Layers
+VIEWERPROPS             = Properties
+VIEWERPANNORTH          = Pan North
+VIEWERPANWEST           = Pan West
+VIEWERPANSOUTH          = Pan South
+VIEWERPANEAST           = Pan East
+VIEWERZOOMIN            = Zoom In
+VIEWERZOOMOUT           = Zoom Out
+VIEWERMOVESLIDER        = Drag to move slider
+VIEWERDRAGZOOM          = Drag to zoom
+ENDSEL                  = CTRL + click to end
+ENDSELSAFARI            = SHIFT + click to end
+DECIMALSEPARATOR        = .
+THOUSANDSEPARATOR       = ,
+
+# Main Frame
+NEEDLOGIN               = You must enter a valid login ID and password to access this site
+ALREADYINMEASURE        = Only one measure command is allowed in a web layout
+ACCESSDENIED            = Access Denied   
+LATLONCURPOS            = Lat: {0}, Lon: {1}
+MAPUNITSCURPOS          = X: {0}, Y: {1}
+FEATURESSELECTED        = {0} features selected
+FEATURESELECTED         = {0} feature selected
+MI                      = mi
+FT                      = ft
+IN                      = in
+KM                      = km
+MT                      = m
+CM                      = cm
+DIGALREADYRUNNING       = Cannot execute measure: A digitization command is in progress.
+MEASALREADYRUNNING      = Cannot execute digitization: A measure is in progress.
+
+# Localized Icon Files
+POWEREDBYICON           = PoweredBy_en.gif

Copied: sandbox/aboudreault/text/fr (from rev 1352, trunk/text/fr)

Deleted: sandbox/aboudreault/text/fr/strings.json
===================================================================
--- trunk/text/fr/strings.json	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/text/fr/strings.json	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,50 +0,0 @@
-Fusion.Strings.fr = {
-'scriptFailed': 'failed to load script: {0}',
-'configParseError': 'Error parsing fusion configuration file, initialization aborted',
-'configLoadError': 'Error loading fusion configuration file, initialization aborted',
-'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
-'importFailed': 'failed to import stylesheet: {0}',
-'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
-'appDefLoadFailed': 'failed to load: {0}',
-'appDefParseError': 'failed to parse ApplicationDefinition',
-'widgetSetParseError': 'failed to parse the WidgetSet',
-'fusionError': 'Fusion Error: {0}\n{1}',
-'nullExtents': 'Map.setExtents called with null extents',
-'mapLoadError': 'Failed to load requested map:\n{0}',
-'setLayersError': "setLayers failure: {0}",
-'printTitle': 'Printable Page ',
-'noSelection': 'Aucun Sélection',
-'No Selection': 'Aucun Sélection',
-'selectionInfo': '{0} features selected on {1} layers - translate me',
-'attribute': 'Attribute',
-'value': 'Value',
-'taskHome': 'return to the task pane home',
-'prevTask': 'go to previous task executed',
-'nextTask': 'go to next task executed',
-'taskList': 'Task List',
-'taskPane': 'Task Pane',
-'imperial': 'Imperial',
-'metric': 'Metric',
-'deg': 'Degrees',
-'refresh': 'Refresh',
-'expandAll': 'Expand All',
-'expand': 'Expand',
-'collapseAll': 'Collapse All',
-'collapse': 'Collapse',
-'defaultMapTitle': 'Map',
-'legendTitle': 'Legend',
-'selectionPanelTitle': 'Sélection',
-'ovmapTitle': 'Overview Map',
-'ovmapTitleShort': 'Overview',
-'taskPaneTitle': 'Tasks',
-'segment': 'Segment {0}',
-'calculating': 'calculating ...',
-'panWest': 'Ouest',
-'panEast': 'Est',
-'panSouth': 'Sud',
-'panNorth': 'Nord',
-'zoomOut': 'Cliquer pour réduire',
-'zoomIn': 'Cliquer pour agrandir',
-
-'end': ''
-};

Copied: sandbox/aboudreault/text/fr/strings.json (from rev 1352, trunk/text/fr/strings.json)
===================================================================
--- sandbox/aboudreault/text/fr/strings.json	                        (rev 0)
+++ sandbox/aboudreault/text/fr/strings.json	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,50 @@
+Fusion.Strings.fr = {
+'scriptFailed': 'failed to load script: {0}',
+'configParseError': 'Error parsing fusion configuration file, initialization aborted',
+'configLoadError': 'Error loading fusion configuration file, initialization aborted',
+'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
+'importFailed': 'failed to import stylesheet: {0}',
+'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
+'appDefLoadFailed': 'failed to load: {0}',
+'appDefParseError': 'failed to parse ApplicationDefinition',
+'widgetSetParseError': 'failed to parse the WidgetSet',
+'fusionError': 'Fusion Error: {0}\n{1}',
+'nullExtents': 'Map.setExtents called with null extents',
+'mapLoadError': 'Failed to load requested map:\n{0}',
+'setLayersError': "setLayers failure: {0}",
+'printTitle': 'Printable Page ',
+'noSelection': 'Aucun Sélection',
+'No Selection': 'Aucun Sélection',
+'selectionInfo': '{0} features selected on {1} layers - translate me',
+'attribute': 'Attribute',
+'value': 'Value',
+'taskHome': 'return to the task pane home',
+'prevTask': 'go to previous task executed',
+'nextTask': 'go to next task executed',
+'taskList': 'Task List',
+'taskPane': 'Task Pane',
+'imperial': 'Imperial',
+'metric': 'Metric',
+'deg': 'Degrees',
+'refresh': 'Refresh',
+'expandAll': 'Expand All',
+'expand': 'Expand',
+'collapseAll': 'Collapse All',
+'collapse': 'Collapse',
+'defaultMapTitle': 'Map',
+'legendTitle': 'Legend',
+'selectionPanelTitle': 'Sélection',
+'ovmapTitle': 'Overview Map',
+'ovmapTitleShort': 'Overview',
+'taskPaneTitle': 'Tasks',
+'segment': 'Segment {0}',
+'calculating': 'calculating ...',
+'panWest': 'Ouest',
+'panEast': 'Est',
+'panSouth': 'Sud',
+'panNorth': 'Nord',
+'zoomOut': 'Cliquer pour réduire',
+'zoomIn': 'Cliquer pour agrandir',
+
+'end': ''
+};

Deleted: sandbox/aboudreault/text/fr/strings.php
===================================================================
--- trunk/text/fr/strings.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/text/fr/strings.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,240 +0,0 @@
-# Web surround localized strings
-# English language
-#
-# Important: This file must be saved with UTF-8 encoding
-#
-
-# General
-
-# Fonts - the 6 following entries are mandatory
- at fontWindows        = Arial
- at fontsizeWindows    = 8pt
- at fontLinux          = Arial
- at fontsizeLinux      = 8pt
- at fontMacintosh      = Arial
- at fontsizeMacintosh  = 8pt
-
-# Distances
-DISTANCEMILES       = Miles
-DISTANCEKILOMETERS  = Kilometers
-DISTANCEFEET        = Feet
-DISTANCEMETERS      = Meters
-
-# Fill Patterns/Values
-FILLSOLID           = Solid
-FILLNET             = Net
-FILLLINE            = Line
-FILLLINE45          = Line_45
-FILLLINE90          = Line_90
-FILLLINE135         = Line_135
-FILLSQUARE          = Square
-FILLBOX             = Box
-FILLCROSS           = Cross
-FILLDASH            = Dash
-FILLDOLMIT          = Dolmit
-FILLHEX             = Hex
-FILLSACNCR          = Sacncr
-FILLSTEEL           = Steel
-
-# Transparency
-TRANSPARENT         = transparent
-
-# Line Styles/Values
-LINESOLID           = Solid
-LINEDASH            = Dash
-LINEDOT             = Dot
-LINEDASHDOT         = DashDot
-LINEDASHDOTDOT      = DashDotDot
-LINERAIL            = Rail
-LINEBORDER          = Border
-LINEDIVIDE          = Divide
-LINEFENCELINE       = FenceLine
-
-# Buttons
-BUTTONOK            = OK
-BUTTONDONE          = Done
-BUTTONCANCEL        = Cancel
-BUTTONREFRESH       = Refresh
-BUTTONCLOSE         = Close
-BUTTONCLEAR         = Clear
-BUTTONSAVE          = Save
-
-# Colors
-COLORRED            = Red
-COLORGREEN          = Green
-COLORBLUE           = Blue
-
-# BufferReport
-BUFFERREPORTTITLE               = Create Buffer
-BUFFERREPORTCREATED             = %s has been created.
-BUFFERREPORTUPDATED             = %s has been updated.
-BUFFERREPORTFEATURESSINGULAR    = %s buffer feature was created.
-BUFFERREPORTFEATURESPLURAL      = %s buffer features were created.
-BUFFERREPORTWARNINGSINGULAR     = <b>Warning:</b> %s layer was excluded from buffer computation because its coordinate system is incompatible with the coordinate system of the map, or because it has no coordinate system at all
-BUFFERREPORTWARNINGPLURAL       = <b>Warning:</b> %s layers were excluded from buffer computation because their coordinate systems are incompatible with the coordinate system of the map, or because they have no coordinate system at all
-BUFFERREPORTERRORTITLE          = Buffer Error
-
-# Buffer
-BUFFERCLASSDESCR                = Feature class for buffer layer
-BUFFERSCHEMADESCR               = Temporary buffer schema
-BUFFERDIFFARBXY                 = Cannot compute a unique buffer around features with different 'Arbitrary X-Y' coordinate systems. Please uncheck the option 'Merge buffer areas' or select only one layer
-
-# BufferUI
-BUFFERTITLE                     = Create a Buffer
-BUFFERSUBTITLE                  = &nbsp;Buffer settings
-BUFFERINFOTEXT                  = Select features on the image.
-BUFFERDISTANCE                  = Distance around features:
-BUFFERLAYERS                    = Layers to include in the buffer:
-BUFFERNOLAYER                   = <No layer selected>
-BUFFERNAME                      = Name for the resulting buffer layer:
-BUFFERNAMETEXT                  = Buffer 1
-BUFFERMERGE                     = Merge buffer areas
-BUFFERFILLSTYLE                 = &nbsp;Fill style
-BUFFERFILLPATTERN               = Fill pattern:
-BUFFERFOREGROUNDCOLOR           = Foreground color:
-BUFFERTRANSPARENCY              = Transparency:
-BUFFERBACKGROUNDCOLOR           = Background color:
-BUFFERBORDERSTYLE               = &nbsp;Border style
-BUFFERBORDERLINEPATTERN         = Line pattern:
-BUFFERBORDERLINECOLOR           = Line color:
-BUFFERBORDERLINETHICKNESS       = Line thickness:
-BUFFERHELP                      = <li><p align="left">Results of the buffer are put into a new layer above the top feature layer. This buffer layer has the name you enter here.</li><li><p align="left">To create multiple buffer layers, use different buffer names.</li><li><p align="left">To hide buffer layers, turn them off.</li><li><p align="left">Buffer layers are temporary and are removed when you close the viewer.</li>
-BUFFERERRORZERODISTANCE         = Please enter a nonzero distance.
-BUFFERERRORNOLAYERNAME          = Please enter a layer name.
-BUFFERERRORNEGATIVETHICKNESS    = Please enter positive or null thickness.
-BUFFERERRORNOSELECTION          = Please select feature(s) to calculate a buffer around.
-
-# ColorPicker
-COLORPICKERDLGTITLE             = Select a color
-COLORPICKERTITLE                = Color palette
-COLORPICKERSUBTITLE             = Specify a color
-COLORPICKER100TRANSPARENCY      = 100%% transparency
-COLORPICKERHEXFORMAT            = Hex format
-
-# MeasureUI
-MEASURETITLE            = Measure Distance
-MEASUREINFO             = Click a start and end point.
-RESUME                  = Resume
-STOP                    = Stop
-CLEAR                   = Clear
-MILES                   = Miles
-KILOMETERS              = Kilometers
-MEASUREHELP             = <li>To measure multiple distances, continue clicking new points.</li><li>To finish, click &quot;Stop&quot;.</li><li>You can pan or zoom and continue measuring by clicking &quot;Resume&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
-SEGMENT                 = Segment
-TOTAL                   = Total
-LENGTH                  = Length
-MEASUREERROR            = Measure Error
-
-# Measure
-MEASUREFEATURECLASS     = Feature class for measure layer
-MEASURESCHEMADESCR      = Temporary measure schema
-MEASUREPARTIAL          = Partial
-MEASURETOTAL            = total
-MEASURELAYER            = Measure
-
-# HtmlViewerAbout
-HTMLABOUTTITLE          = About %s
-HTMLABOUTTITLEBAR       = MapGuide Viewer
-HTMLABOUTSERVERTITLE    = MapGuide Server
-HTMLABOUTVIEWERTITLE    = MapGuide Viewer
-HTMLABOUTSERVERVERSION  = %s (Version %s)
-HTMLABOUTVIEWERVERSION  = %s (Version %s)
-HTMLABOUTTEXT           = <br>This product is made available subject to the terms of GNU Lesser General Public License Version 2.1 ("LGPL").  A copy of the LGPL, as well as additional copyright notices and license terms applicable to portions of this product are set forth in the <a href="../localized/license_en.htm" target="blank">license</a> file.<br><br>All trademarks and registered trademarks mentioned herein are the property of their respective owners.<br><br>Copyright &copy; 2007 Autodesk, Inc.<br><br>
-HTMLABOUTLICENSE        = license file
-HTMLABOUTLICENSEFILE    = license_en.htm
-
-# LegendUI
-LEGENDLISTSEPARATOR     = ,
-
-# PrintablePageUi
-PRINTTITLE              = Get Printable Page
-PRINTELEMENTS           = Select the elements to include in the print layout.
-PRINTPAGETITLE          = Page title:
-PRINTLEGEND             = Legend
-PRINTNORTHARROW         = North arrow
-PRINTCREATEPAGE         = Create Page
-
-# PropertyCtrl
-PROPERTIESNONE          = None Selected
-PROPERTIESNAME          = Name
-PROPERTIESVALUE         = Value
-PROPERTIESITEMSEL       = Items selected: {0}
-
-# Search
-SEARCHDLGTITLE          = Search features
-SEARCHTITLE             = Search results
-SEARCHERROR             = Search error
-SEARCHREPORT            = Search report
-SEARCHLAYERNOTFOUND     = Layer {0} not found!
-SEARCHNOMULTIPROP       = Multi-properties identity not supported yet
-SEARCHTYYPENOTSUP       = Identity property type not supported yet ({0})
-SEARCHNOMATCHES         = No matches.
-
-# SearchPrompt
-SEARCHPROMPTFIND        = Find
-
-# SelectWithinUi
-SELECTWITHINTITLE       = Select Within
-SELECTWITHINAREAS       = Select areas on the image.
-SELECTWITHINRESTRICTION = Restrict results to selected layers:
-SELECTWITHINTEXT        = <li>If you continue to select areas on the image, click &quot;Refresh&quot; to update the layer list.</li><li>To finish and select all features within the highlighted areas, click &quot;Done&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
-
-# Error/Report
-REPORTTITLE             = Report
-
-# Legend UI
-REFRESH                 = Refresh
-EXPANDALL               = Expand
-COLLAPSEALL             = Collapse All
-DISPLAYALLINGROUP       = Display All in Group
-HIDEALLINGROUP          = Hide All in Group
-SHOWLONGTHEME           = Show Long Theme
-
-# Task Bar
-TASKS                   = Tasks
-
-# Viewer Options
-OPTIONSTITLE            = Viewer Options
-OPTIONSINFOTEXT         = Select viewing options for status bar and tool tips.
-OPTIONSDISTANCE         = Display distances in
-OPTIONSMETRIC           = Metric (Kilometers, Meters)
-OPTIONSUSENGLISH        = US/English (Miles, Feet)
-OPTIONSPOSITION         = Display cursor position in
-OPTIONSLATLON           = Latitude, Longitude (Degrees)
-OPTIONSMAPUNITS         = Map Coordinate System (X,Y)
-
-# AJAX Viewer
-VIEWERLAYERS            = Layers
-VIEWERPROPS             = Properties
-VIEWERPANNORTH          = Pan North
-VIEWERPANWEST           = Pan West
-VIEWERPANSOUTH          = Pan South
-VIEWERPANEAST           = Pan East
-VIEWERZOOMIN            = Zoom In
-VIEWERZOOMOUT           = Zoom Out
-VIEWERMOVESLIDER        = Drag to move slider
-VIEWERDRAGZOOM          = Drag to zoom
-ENDSEL                  = CTRL + click to end
-ENDSELSAFARI            = SHIFT + click to end
-DECIMALSEPARATOR        = .
-THOUSANDSEPARATOR       = ,
-
-# Main Frame
-NEEDLOGIN               = You must enter a valid login ID and password to access this site
-ALREADYINMEASURE        = Only one measure command is allowed in a web layout
-ACCESSDENIED            = Access Denied   
-LATLONCURPOS            = Lat: {0}, Lon: {1}
-MAPUNITSCURPOS          = X: {0}, Y: {1}
-FEATURESSELECTED        = {0} features selected
-FEATURESELECTED         = {0} feature selected
-MI                      = mi
-FT                      = ft
-IN                      = in
-KM                      = km
-MT                      = m
-CM                      = cm
-DIGALREADYRUNNING       = Cannot execute measure: A digitization command is in progress.
-MEASALREADYRUNNING      = Cannot execute digitization: A measure is in progress.
-
-# Localized Icon Files
-POWEREDBYICON           = PoweredBy_en.gif

Copied: sandbox/aboudreault/text/fr/strings.php (from rev 1352, trunk/text/fr/strings.php)
===================================================================
--- sandbox/aboudreault/text/fr/strings.php	                        (rev 0)
+++ sandbox/aboudreault/text/fr/strings.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,240 @@
+# Web surround localized strings
+# English language
+#
+# Important: This file must be saved with UTF-8 encoding
+#
+
+# General
+
+# Fonts - the 6 following entries are mandatory
+ at fontWindows        = Arial
+ at fontsizeWindows    = 8pt
+ at fontLinux          = Arial
+ at fontsizeLinux      = 8pt
+ at fontMacintosh      = Arial
+ at fontsizeMacintosh  = 8pt
+
+# Distances
+DISTANCEMILES       = Miles
+DISTANCEKILOMETERS  = Kilometers
+DISTANCEFEET        = Feet
+DISTANCEMETERS      = Meters
+
+# Fill Patterns/Values
+FILLSOLID           = Solid
+FILLNET             = Net
+FILLLINE            = Line
+FILLLINE45          = Line_45
+FILLLINE90          = Line_90
+FILLLINE135         = Line_135
+FILLSQUARE          = Square
+FILLBOX             = Box
+FILLCROSS           = Cross
+FILLDASH            = Dash
+FILLDOLMIT          = Dolmit
+FILLHEX             = Hex
+FILLSACNCR          = Sacncr
+FILLSTEEL           = Steel
+
+# Transparency
+TRANSPARENT         = transparent
+
+# Line Styles/Values
+LINESOLID           = Solid
+LINEDASH            = Dash
+LINEDOT             = Dot
+LINEDASHDOT         = DashDot
+LINEDASHDOTDOT      = DashDotDot
+LINERAIL            = Rail
+LINEBORDER          = Border
+LINEDIVIDE          = Divide
+LINEFENCELINE       = FenceLine
+
+# Buttons
+BUTTONOK            = OK
+BUTTONDONE          = Done
+BUTTONCANCEL        = Cancel
+BUTTONREFRESH       = Refresh
+BUTTONCLOSE         = Close
+BUTTONCLEAR         = Clear
+BUTTONSAVE          = Save
+
+# Colors
+COLORRED            = Red
+COLORGREEN          = Green
+COLORBLUE           = Blue
+
+# BufferReport
+BUFFERREPORTTITLE               = Create Buffer
+BUFFERREPORTCREATED             = %s has been created.
+BUFFERREPORTUPDATED             = %s has been updated.
+BUFFERREPORTFEATURESSINGULAR    = %s buffer feature was created.
+BUFFERREPORTFEATURESPLURAL      = %s buffer features were created.
+BUFFERREPORTWARNINGSINGULAR     = <b>Warning:</b> %s layer was excluded from buffer computation because its coordinate system is incompatible with the coordinate system of the map, or because it has no coordinate system at all
+BUFFERREPORTWARNINGPLURAL       = <b>Warning:</b> %s layers were excluded from buffer computation because their coordinate systems are incompatible with the coordinate system of the map, or because they have no coordinate system at all
+BUFFERREPORTERRORTITLE          = Buffer Error
+
+# Buffer
+BUFFERCLASSDESCR                = Feature class for buffer layer
+BUFFERSCHEMADESCR               = Temporary buffer schema
+BUFFERDIFFARBXY                 = Cannot compute a unique buffer around features with different 'Arbitrary X-Y' coordinate systems. Please uncheck the option 'Merge buffer areas' or select only one layer
+
+# BufferUI
+BUFFERTITLE                     = Create a Buffer
+BUFFERSUBTITLE                  = &nbsp;Buffer settings
+BUFFERINFOTEXT                  = Select features on the image.
+BUFFERDISTANCE                  = Distance around features:
+BUFFERLAYERS                    = Layers to include in the buffer:
+BUFFERNOLAYER                   = <No layer selected>
+BUFFERNAME                      = Name for the resulting buffer layer:
+BUFFERNAMETEXT                  = Buffer 1
+BUFFERMERGE                     = Merge buffer areas
+BUFFERFILLSTYLE                 = &nbsp;Fill style
+BUFFERFILLPATTERN               = Fill pattern:
+BUFFERFOREGROUNDCOLOR           = Foreground color:
+BUFFERTRANSPARENCY              = Transparency:
+BUFFERBACKGROUNDCOLOR           = Background color:
+BUFFERBORDERSTYLE               = &nbsp;Border style
+BUFFERBORDERLINEPATTERN         = Line pattern:
+BUFFERBORDERLINECOLOR           = Line color:
+BUFFERBORDERLINETHICKNESS       = Line thickness:
+BUFFERHELP                      = <li><p align="left">Results of the buffer are put into a new layer above the top feature layer. This buffer layer has the name you enter here.</li><li><p align="left">To create multiple buffer layers, use different buffer names.</li><li><p align="left">To hide buffer layers, turn them off.</li><li><p align="left">Buffer layers are temporary and are removed when you close the viewer.</li>
+BUFFERERRORZERODISTANCE         = Please enter a nonzero distance.
+BUFFERERRORNOLAYERNAME          = Please enter a layer name.
+BUFFERERRORNEGATIVETHICKNESS    = Please enter positive or null thickness.
+BUFFERERRORNOSELECTION          = Please select feature(s) to calculate a buffer around.
+
+# ColorPicker
+COLORPICKERDLGTITLE             = Select a color
+COLORPICKERTITLE                = Color palette
+COLORPICKERSUBTITLE             = Specify a color
+COLORPICKER100TRANSPARENCY      = 100%% transparency
+COLORPICKERHEXFORMAT            = Hex format
+
+# MeasureUI
+MEASURETITLE            = Measure Distance
+MEASUREINFO             = Click a start and end point.
+RESUME                  = Resume
+STOP                    = Stop
+CLEAR                   = Clear
+MILES                   = Miles
+KILOMETERS              = Kilometers
+MEASUREHELP             = <li>To measure multiple distances, continue clicking new points.</li><li>To finish, click &quot;Stop&quot;.</li><li>You can pan or zoom and continue measuring by clicking &quot;Resume&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
+SEGMENT                 = Segment
+TOTAL                   = Total
+LENGTH                  = Length
+MEASUREERROR            = Measure Error
+
+# Measure
+MEASUREFEATURECLASS     = Feature class for measure layer
+MEASURESCHEMADESCR      = Temporary measure schema
+MEASUREPARTIAL          = Partial
+MEASURETOTAL            = total
+MEASURELAYER            = Measure
+
+# HtmlViewerAbout
+HTMLABOUTTITLE          = About %s
+HTMLABOUTTITLEBAR       = MapGuide Viewer
+HTMLABOUTSERVERTITLE    = MapGuide Server
+HTMLABOUTVIEWERTITLE    = MapGuide Viewer
+HTMLABOUTSERVERVERSION  = %s (Version %s)
+HTMLABOUTVIEWERVERSION  = %s (Version %s)
+HTMLABOUTTEXT           = <br>This product is made available subject to the terms of GNU Lesser General Public License Version 2.1 ("LGPL").  A copy of the LGPL, as well as additional copyright notices and license terms applicable to portions of this product are set forth in the <a href="../localized/license_en.htm" target="blank">license</a> file.<br><br>All trademarks and registered trademarks mentioned herein are the property of their respective owners.<br><br>Copyright &copy; 2007 Autodesk, Inc.<br><br>
+HTMLABOUTLICENSE        = license file
+HTMLABOUTLICENSEFILE    = license_en.htm
+
+# LegendUI
+LEGENDLISTSEPARATOR     = ,
+
+# PrintablePageUi
+PRINTTITLE              = Get Printable Page
+PRINTELEMENTS           = Select the elements to include in the print layout.
+PRINTPAGETITLE          = Page title:
+PRINTLEGEND             = Legend
+PRINTNORTHARROW         = North arrow
+PRINTCREATEPAGE         = Create Page
+
+# PropertyCtrl
+PROPERTIESNONE          = None Selected
+PROPERTIESNAME          = Name
+PROPERTIESVALUE         = Value
+PROPERTIESITEMSEL       = Items selected: {0}
+
+# Search
+SEARCHDLGTITLE          = Search features
+SEARCHTITLE             = Search results
+SEARCHERROR             = Search error
+SEARCHREPORT            = Search report
+SEARCHLAYERNOTFOUND     = Layer {0} not found!
+SEARCHNOMULTIPROP       = Multi-properties identity not supported yet
+SEARCHTYYPENOTSUP       = Identity property type not supported yet ({0})
+SEARCHNOMATCHES         = No matches.
+
+# SearchPrompt
+SEARCHPROMPTFIND        = Find
+
+# SelectWithinUi
+SELECTWITHINTITLE       = Select Within
+SELECTWITHINAREAS       = Select areas on the image.
+SELECTWITHINRESTRICTION = Restrict results to selected layers:
+SELECTWITHINTEXT        = <li>If you continue to select areas on the image, click &quot;Refresh&quot; to update the layer list.</li><li>To finish and select all features within the highlighted areas, click &quot;Done&quot;.</li><li>To start over, click &quot;Clear&quot;.</li>
+
+# Error/Report
+REPORTTITLE             = Report
+
+# Legend UI
+REFRESH                 = Refresh
+EXPANDALL               = Expand
+COLLAPSEALL             = Collapse All
+DISPLAYALLINGROUP       = Display All in Group
+HIDEALLINGROUP          = Hide All in Group
+SHOWLONGTHEME           = Show Long Theme
+
+# Task Bar
+TASKS                   = Tasks
+
+# Viewer Options
+OPTIONSTITLE            = Viewer Options
+OPTIONSINFOTEXT         = Select viewing options for status bar and tool tips.
+OPTIONSDISTANCE         = Display distances in
+OPTIONSMETRIC           = Metric (Kilometers, Meters)
+OPTIONSUSENGLISH        = US/English (Miles, Feet)
+OPTIONSPOSITION         = Display cursor position in
+OPTIONSLATLON           = Latitude, Longitude (Degrees)
+OPTIONSMAPUNITS         = Map Coordinate System (X,Y)
+
+# AJAX Viewer
+VIEWERLAYERS            = Layers
+VIEWERPROPS             = Properties
+VIEWERPANNORTH          = Pan North
+VIEWERPANWEST           = Pan West
+VIEWERPANSOUTH          = Pan South
+VIEWERPANEAST           = Pan East
+VIEWERZOOMIN            = Zoom In
+VIEWERZOOMOUT           = Zoom Out
+VIEWERMOVESLIDER        = Drag to move slider
+VIEWERDRAGZOOM          = Drag to zoom
+ENDSEL                  = CTRL + click to end
+ENDSELSAFARI            = SHIFT + click to end
+DECIMALSEPARATOR        = .
+THOUSANDSEPARATOR       = ,
+
+# Main Frame
+NEEDLOGIN               = You must enter a valid login ID and password to access this site
+ALREADYINMEASURE        = Only one measure command is allowed in a web layout
+ACCESSDENIED            = Access Denied   
+LATLONCURPOS            = Lat: {0}, Lon: {1}
+MAPUNITSCURPOS          = X: {0}, Y: {1}
+FEATURESSELECTED        = {0} features selected
+FEATURESELECTED         = {0} feature selected
+MI                      = mi
+FT                      = ft
+IN                      = in
+KM                      = km
+MT                      = m
+CM                      = cm
+DIGALREADYRUNNING       = Cannot execute measure: A digitization command is in progress.
+MEASALREADYRUNNING      = Cannot execute digitization: A measure is in progress.
+
+# Localized Icon Files
+POWEREDBYICON           = PoweredBy_en.gif

Modified: sandbox/aboudreault/widgets/About.js
===================================================================
--- sandbox/aboudreault/widgets/About.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/About.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.About
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/About.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/ActivityIndicator.js
===================================================================
--- sandbox/aboudreault/widgets/ActivityIndicator.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/ActivityIndicator.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.ActivityIndicator
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/ActivityIndicator.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Buffer.js
===================================================================
--- sandbox/aboudreault/widgets/Buffer.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Buffer.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -212,6 +212,7 @@
         var s = aMaps[0].arch + '/' + Fusion.getScriptLanguage() + "/Buffer." + Fusion.getScriptLanguage();
         var params = {};
         params.parameters = 'locale='+Fusion.locale +
+                            '&merge=1' +
                             '&session='+aMaps[0].getSessionID() +
                             '&mapname='+ aMaps[0].getMapName()+
                             layer+distance+borderColor+fillColor; 


Property changes on: sandbox/aboudreault/widgets/BufferPanel/AreaLayerDef.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/BufferPanel/Buffer.php
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel/Buffer.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/BufferPanel/Buffer.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Buffer
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -236,7 +236,8 @@
 
             // create a SRS transformer if necessary.
             if($srsDefDs != $srsDefMap)
-                $srsXform = new MgCoordinateSystemTransform($srsDs, $srsMap);
+                $srsXform = $srsFactory->GetTransform($srsDs, $srsMap);
+                //$srsXform = new MgCoordinateSystemTransform($srsDs, $srsMap);
             else
                 $srsXform = null;
 


Property changes on: sandbox/aboudreault/widgets/BufferPanel/Buffer.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/BufferPanel/BufferPanel.php
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel/BufferPanel.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/BufferPanel/BufferPanel.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * BufferPanel
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/BufferPanel/BufferPanel.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/BufferPanel/BufferPanel.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/BufferPanel/BufferReport.templ
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel/BufferReport.templ	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/BufferPanel/BufferReport.templ	2008-03-31 14:35:37 UTC (rev 1353)
@@ -25,11 +25,12 @@
 
 var popup = %s;
 var errors = false; //this page is only returned for success; 
+var mapName = '%s';
 
 function InitDocument()
 {
-    var map = GetParent().Fusion.getMapByName('%s');
-    map.aMaps[0].reloadMap();    //TODO: make a MapWidget reload function
+    var map = GetParent().Fusion.getMapByName(mapName);
+    map.reloadMap();
     if (!errors) {
       Back();
     }


Property changes on: sandbox/aboudreault/widgets/BufferPanel/BufferReport.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/BufferPanel/ColorPicker.php
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel/ColorPicker.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/BufferPanel/ColorPicker.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * ColorPicker
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/BufferPanel/ColorPicker.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/BufferPanel/ColorPicker.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/BufferPanel/ErrorPage.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/BufferPanel/Viewer.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/BufferPanel.js
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/BufferPanel.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.BufferPanel
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/BufferPanel.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/CTRLClick.js
===================================================================
--- sandbox/aboudreault/widgets/CTRLClick.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/CTRLClick.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.CTRLClick
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/CTRLClick.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/CursorPosition.js
===================================================================
--- sandbox/aboudreault/widgets/CursorPosition.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/CursorPosition.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -83,14 +83,14 @@
         this.enable = Fusion.Widget.CursorPosition.prototype.enable;
         this.disable = Fusion.Widget.CursorPosition.prototype.enable;
         
-        this.mouseMoveWatcher = this.mouseMove.bind(this);
-        this.mouseOutWatcher = this.mouseOut.bind(this);
-
         this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this));
         this.registerParameter('Units');
     },
     
     enable: function() {
+        this.mouseMoveWatcher = this.mouseMove.bind(this);
+        this.mouseOutWatcher = this.mouseOut.bind(this);
+
         this.getMap().observeEvent('mousemove', this.mouseMoveWatcher);
         this.getMap().observeEvent('mouseout', this.mouseOutWatcher);
     },


Property changes on: sandbox/aboudreault/widgets/EditableScale/EditableScale.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/EditableScale.js
===================================================================
--- sandbox/aboudreault/widgets/EditableScale.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/EditableScale.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.EditableScale
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -38,7 +38,11 @@
         Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
         
         var json = widgetTag.extension;
-                
+        
+        var domPrefix = document.createElement('span');
+        domPrefix.className = 'inputEditableScalePrefix';
+        domPrefix.innerHTML = '1: ';
+        this.domObj.appendChild(domPrefix);
         this.domScale = document.createElement('input');
         this.domScale.className = 'inputEditableScale';
         this.domObj.appendChild(this.domScale);


Property changes on: sandbox/aboudreault/widgets/EditableScale.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/ExtentHistory.js
===================================================================
--- sandbox/aboudreault/widgets/ExtentHistory.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/ExtentHistory.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -37,6 +37,7 @@
     events: [],
     aHistory: [],
     sDirection: null,
+    EPS: 0.00000001,  //percentage difference allowed in bounds values for test for equal
     initialize : function(widgetTag) {
         Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
         Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
@@ -85,13 +86,10 @@
             this.aHistory['index'] = 0;
         } else {
             var aExtents = this.aHistory['history'][this.aHistory['index']];
-            if (aExtents.top == extents.top &&
-                aExtents.bottom == extents.bottom &&
-                aExtents.left == extents.left &&
-                aExtents.right == extents.right) {
+            if (this.boundsEqual(extents, aExtents)) {
                 return;
             }
-            //clear forward history if we have gone backwards at some point
+            //clear forward history if we zoom to a different extent than contained in the history
             if (this.aHistory['index'] != (this.aHistory['history'].length - 1)) {
                 this.aHistory['history'] = this.aHistory['history'].slice(0, this.aHistory['index'] + 1);
             }
@@ -131,5 +129,38 @@
                 this.triggerEvent(Fusion.Event.HISTORY_CHANGED);
             }
         }
+    },
+    
+    /* 
+      * test if 2 OpenLayers.Bounds objects are equal to within some precision
+      */
+    boundsEqual: function(b1, b2) {
+      var equal = false;
+      
+      //prevent divide by 0 errors
+      var offset = 100;
+      if (b2.top == 0) {
+        b1.top += offset;
+        b2.top += offset;
+      }
+      if (b2.bottom == 0) {
+        b1.bottom += offset;
+        b2.bottom += offset;
+      }
+      if (b2.left == 0) {
+        b1.left += offset;
+        b2.left += offset;
+      }
+      if (b2.right == 0) {
+        b1.right += offset;
+        b2.right += offset;
+      }
+      //calculate difference as percentage so all ranges of coordinates can be accommodated
+      equal = (Math.abs(b1.top - b2.top)/b2.top < this.EPS &&
+               Math.abs(b1.bottom - b2.bottom)/b2.bottom < this.EPS &&
+               Math.abs(b1.left - b2.left)/b2.left < this.EPS &&
+               Math.abs(b1.right - b2.right)/b2.right < this.EPS);
+      return equal;
     }
-};
\ No newline at end of file
+};
+


Property changes on: sandbox/aboudreault/widgets/Help/Help.html
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Help.js
===================================================================
--- sandbox/aboudreault/widgets/Help.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Help.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.Help
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/Help.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/InitialMapView.js
===================================================================
--- sandbox/aboudreault/widgets/InitialMapView.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/InitialMapView.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.InitialMapView
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/InitialMapView.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/InvokeURL.js
===================================================================
--- sandbox/aboudreault/widgets/InvokeURL.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/InvokeURL.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.InvokeURL
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -99,9 +99,9 @@
         
         var map = this.getMap();
         var params = [];
-        params.push('locale='+Fusion.locale);
-        params.push('session='+map.getSessionID());
-        params.push('mapname='+map.getMapName());
+        params.push('LOCALE='+Fusion.locale);
+        params.push('SESSION='+map.getSessionID());
+        params.push('MAPNAME='+map.getMapName());
         params = params.concat(this.additionalParameters);
         if (url.indexOf('?') < 0) {
             url += '?';


Property changes on: sandbox/aboudreault/widgets/InvokeURL.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/LayerManager/LayerManager.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/LayerManager.js
===================================================================
--- sandbox/aboudreault/widgets/LayerManager.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/LayerManager.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.LayerManager
  *
- * $Id: LayerManager.js 978 2007-10-17 18:24:46Z pspencer $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/LayerManager.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Legend.js
===================================================================
--- sandbox/aboudreault/widgets/Legend.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Legend.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -86,15 +86,15 @@
         this.hideInvisibleLayers = (json.HideInvisibleLayers && json.HideInvisibleLayers[0]) == 'true' ? true : false;
         
         this.refreshAction = new Jx.Action(this.update.bind(this));
-        this.refreshItem = new Jx.MenuItem(this.refreshAction, {label: 'Refresh'});
+        this.refreshItem = new Jx.MenuItem(this.refreshAction, {label: OpenLayers.String.translate('refresh')});
         this.expandAllAction = new Jx.Action(this.expandAll.bind(this));
-        this.expandAllItem = new Jx.MenuItem(this.expandAllAction, {label: 'Expand All'});
+        this.expandAllItem = new Jx.MenuItem(this.expandAllAction, {label: OpenLayers.String.translate('expandAll')});
         this.expandBranchAction = new Jx.Action(this.expandBranch.bind(this));
-        this.expandBranchItem = new Jx.MenuItem(this.expandBranchAction, {label: 'Expand'});
+        this.expandBranchItem = new Jx.MenuItem(this.expandBranchAction, {label: OpenLayers.String.translate('expand')});
         this.collapseAllAction = new Jx.Action(this.collapseAll.bind(this));
-        this.collapseAllItem = new Jx.MenuItem(this.collapseAllAction, {label: 'Collapse All'});
+        this.collapseAllItem = new Jx.MenuItem(this.collapseAllAction, {label: OpenLayers.String.translate('collapseAll')});
         this.collapseBranchAction = new Jx.Action(this.collapseBranch.bind(this));
-        this.collapseBranchItem = new Jx.MenuItem(this.collapseBranchAction, {label: 'Collapse'});
+        this.collapseBranchItem = new Jx.MenuItem(this.collapseBranchAction, {label: OpenLayers.String.translate('collapse')});
         //this.collapseBranchItem.disable();
         
         this.contextMenu = new Jx.ContextMenu(this.sName);
@@ -107,7 +107,7 @@
         this.showMapFolder = (json.ShowMapFolder && json.ShowMapFolder[0] == 'false') ? false:true;
         if (this.showRootFolder) {
             var opt = {};
-            opt.label = 'Map';
+            opt.label = OpenLayers.String.translate('defaultMapTitle');
             opt.data = null;
             opt.imgTreeFolder = json.RootFolderIcon ? json.RootFolderIcon[0] : this.defRootFolderIcon;
             opt.imgTreeFolderOpen = opt.imgTreeFolder;
@@ -210,7 +210,6 @@
         if (this.showRootFolder) {
             this.oRoot.setName(map.getMapTitle());
         }
-        this.oMapInfo = map.oMapInfo;
         var startGroup = map.layerRoot;
         if (!this.showMapFolder) {
           startGroup = map.layerRoot.groups[0];
@@ -247,7 +246,7 @@
             group.legend.checkBox.checked = group.visible?true:false;
             Event.observe(group.legend.checkBox, 'click', this.stateChanged.bind(this, group));
             Event.observe(group.legend.treeItem.domObj, 'mouseover', this.setFolder.bind(this));
-            var groupInfo = this.getGroupInfoUrl(group.groupName);
+            var groupInfo = group.oMap.getGroupInfoUrl(group.groupName);
             if (groupInfo) {
                 var a = document.createElement('a');
                 a.href = groupInfo;
@@ -424,7 +423,7 @@
         opt.imgTreeFolder = this.imgLayerThemeIcon;
         var folder = new Jx.TreeFolder(opt);
         folder.domObj.insertBefore(layer.legend.checkBox, folder.domObj.childNodes[1]);
-        var layerInfo = this.getLayerInfoUrl(layer.layerName);
+        var layerInfo = layer.oMap.getLayerInfoUrl(layer.layerName);
         if (layerInfo) {
             var a = document.createElement('a');
             a.href = layerInfo;
@@ -468,7 +467,7 @@
         if (bCheckBox) {
             item.domObj.insertBefore(layer.legend.checkBox, item.domObj.childNodes[1]);
             /* only need to add layer info if it has a check box too */
-            var layerInfo = this.getLayerInfoUrl(layer.layerName);
+            var layerInfo = layer.oMap.getLayerInfoUrl(layer.layerName);
             if (layerInfo) {
                 var a = document.createElement('a');
                 a.href = layerInfo;
@@ -500,27 +499,5 @@
                 obj.hide();
             }
         }
-    },
-    getGroupInfoUrl: function(groupName) {
-        if (this.oMapInfo) {
-            var groups = this.oMapInfo.links.groups;
-            for (var i=0; i<groups.length; i++) {
-                if (groups[i].name == groupName) {
-                    return groups[i].url;
-                }
-            }
-        }
-        return null;
-    },
-    getLayerInfoUrl: function(layerName) {
-        if (this.oMapInfo) {
-            var layers = this.oMapInfo.links.layers;
-            for (var i=0; i<layers.length; i++) {
-                if (layers[i].name == layerName) {
-                    return layers[i].url;
-                }
-            }
-        }
-        return null;
     }
 };

Modified: sandbox/aboudreault/widgets/LinkToView.js
===================================================================
--- sandbox/aboudreault/widgets/LinkToView.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/LinkToView.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.LinkToView
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -53,13 +53,13 @@
           join = '&';
         }
 
-        this.anchorLabel = this.domObj.innerHTML;
+        this.anchorLabel = json.Label ? json.Label[0] : (this.domObj.innerHTML ? this.domObj.innerHTML : 'Link to View');
 
         this.anchor = document.createElement('a');
         this.anchor.className = 'anchorLinkToView';
         this.anchor.href = this.baseUrl;
         this.anchor.innerHTML = this.anchorLabel;
-        this.anchor.title = 
+        this.anchor.title = json.Tooltip ? json.Tooltip[0] : 'Right-click to copy or bookmark link to current view';
         this.domObj.innerHTML = '';
         this.domObj.appendChild(this.anchor);
 


Property changes on: sandbox/aboudreault/widgets/LinkToView.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Deleted: sandbox/aboudreault/widgets/MSSearch.js
===================================================================
--- sandbox/aboudreault/widgets/MSSearch.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/MSSearch.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,89 +0,0 @@
-/**
- * Fusion.Widget.MSSearch
- *
- * $Id: $
- *
- * Copyright (c) 2007, DM Solutions Group Inc.
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
- /********************************************************************
- * Class: Fusion.Widget.MSSearch
- *
- * A widget that displays a pre-configured search form to the user and then
- * runs the search.  Searches are done on the attribute of specified layer.
- *
- * **********************************************************************/
-
-Fusion.Widget.MSSearch = Class.create();
-Fusion.Widget.MSSearch.prototype = {
-    sLayerName : '',
-    oTextBox : '',
-    sMatchLimit: '',
-    sAttribute: '',
-    bCaseSensitive: false,
-    iBoxSize: 15,
-
-    initialize : function(widgetTag){
-        Object.inheritFrom(this,Fusion.Widget.prototype, [widgetTag, true]);
-       
-        
-        this.enable = Fusion.Widget.MSSearch.prototype.enable;
-
-        var json = widgetTag.extension;
-
-        this.sLayerName = json.LayerName ? json.LayerName : '';
-        this.sMatchLimit = json.MatchLimit ? json.MatchLimit : '';
-        this.sAttribute = json.Attribute ? json.Attribute : '';
-        this.bCaseSensitive = json.CaseSensitive ? json.CaseSensitive : false;
-
-        if (isNaN(parseInt(this.sMatchLimit)))
-            this.sMatchLimit = -1;
-
-        this.map = this.getMap().oMapOL;
-
-        this.oTextBox = document.createElement('input');
-        this.oTextBox.type = 'text';
-        this.oTextBox.size = this.iBoxSize; 
-        this.oTextBox.className = "searchBox";
-     
-        this.domObj.appendChild(this.oTextBox);
-        Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
-    },
-
-  enable : function() {
-            Fusion.Tool.ButtonBase.prototype.enable.apply(this,[]);
-  },
-
-  execute : function() {
-        
-      var options = {};
-      options.queryType = 'search';
-      options.attribute = this.sAttribute;
-      options.pattern = "/"+this.oTextBox.value.trim()+"/";
-      if (!this.bCaseSensitive)
-          options.pattern += "i";
-      options.matchlimit = this.sMatchLimit;
-      options.layer = this.sLayerName;
-      
-      this.getMap().query(options);
-  }
-};
-    
-    

Added: sandbox/aboudreault/widgets/MSSearch.js
===================================================================
--- sandbox/aboudreault/widgets/MSSearch.js	                        (rev 0)
+++ sandbox/aboudreault/widgets/MSSearch.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,88 @@
+/**
+ * Fusion.Widget.MSSearch
+ *
+ * $Id: $
+ *
+ * Copyright (c) 2007, DM Solutions Group Inc.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+ /********************************************************************
+ * Class: Fusion.Widget.MSSearch
+ *
+ * A widget that displays a pre-configured search form to the user and then
+ * runs the search.  Searches are done on the attribute of specified layer.
+ *
+ * **********************************************************************/
+
+Fusion.Widget.MSSearch = Class.create();
+Fusion.Widget.MSSearch.prototype = {
+    sLayerName : '',
+    oTextBox : '',
+    sMatchLimit: '',
+    sAttribute: '',
+    bCaseSensitive: false,
+    iBoxSize: 15,
+
+    initialize : function(widgetTag){
+        Object.inheritFrom(this,Fusion.Widget.prototype, [widgetTag, true]);
+       
+        
+        this.enable = Fusion.Widget.MSSearch.prototype.enable;
+
+        var json = widgetTag.extension;
+
+        this.sLayerName = json.LayerName ? json.LayerName : '';
+        this.sMatchLimit = json.MatchLimit ? json.MatchLimit : '';
+        this.sAttribute = json.Attribute ? json.Attribute : '';
+        this.bCaseSensitive = json.CaseSensitive ? json.CaseSensitive : false;
+
+        if (isNaN(parseInt(this.sMatchLimit)))
+            this.sMatchLimit = -1;
+
+        this.map = this.getMap().oMapOL;
+
+        this.oTextBox = document.createElement('input');
+        this.oTextBox.type = 'text';
+        this.oTextBox.size = this.iBoxSize; 
+        this.oTextBox.className = "searchBox";
+     
+        this.domObj.appendChild(this.oTextBox);
+        Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+    },
+
+  enable : function() {
+            Fusion.Tool.ButtonBase.prototype.enable.apply(this,[]);
+  },
+
+  execute : function() {
+        
+      var options = {};
+      options.queryType = 'search';
+      options.attribute = this.sAttribute;
+      options.pattern = "/"+this.oTextBox.value.trim()+"/";
+      if (!this.bCaseSensitive)
+          options.pattern += "i";
+      options.matchlimit = this.sMatchLimit;
+      options.layer = this.sLayerName;
+      
+      this.getMap().query(options);
+  }
+};
+

Modified: sandbox/aboudreault/widgets/MapMenu.js
===================================================================
--- sandbox/aboudreault/widgets/MapMenu.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/MapMenu.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -56,9 +56,95 @@
             var menuItem = new Jx.MenuItem(action,opt);
             this.oMenu.add(menuItem);
         }
+        
+        //get the mapdefinitions as xml if there  is a folder specified
+        //in the widget tag. All subfolders will be enumerated.
+        //FIXME: this should be platform agnostic, Library:// isn't!
+        //FIXME: use JSON rather than XML        
+        this.arch = this.getMap().getAllMaps()[0].arch;
+        if (this.arch == 'MapGuide' && json.Folder) {
+            this.sRootFolder = json.Folder ? json.Folder[0] : 'Library://';
+            var s =       this.arch + '/' + Fusion.getScriptLanguage() +
+                          '/MapMenu.' + Fusion.getScriptLanguage();
+            var params =  {parameters:'folder='+this.sRootFolder,
+                          onComplete: this.processMapMenu.bind(this)};
+            Fusion.ajaxRequest(s, params);
+        };
+
     },
+
+    processMapMenu: function(r) {
+        if (r.responseXML) {
+            this.aMenus = {};
+            var node = new DomNode(r.responseXML);
+            var mapNode = node.findFirstNode('MapDefinition');
+            while (mapNode) {
+                
+                var sId = mapNode.getNodeText('ResourceId');
+                var sPath = sId.replace(this.sRootFolder, '');
+                sPath = sPath.slice(0, sPath.lastIndexOf('/'));
+                this.createFolders(sPath);
+                var opt = {};
+                opt.label = mapNode.getNodeText('Name');
+                // create a maptag that will be passed to the map
+                // widget constructor
+                var data = {maps:[{'resourceId':mapNode.getNodeText('ResourceId'),
+                            'singleTile':true,
+                            'type': this.arch,
+                            'extension':{'ResourceId': [mapNode.getNodeText('ResourceId')]}
+                           }]};
+                //set up needed accessor
+                data.getInitialView = function() {
+                    return this.initialView;
+                };
+                var action = new Jx.Action(this.switchMap.bind(this, data));
+                var menuItem = new Jx.MenuItem(action,opt);
+                
+                if (sPath == '') {
+                    this.oMenu.add(menuItem);
+                }else {
+                    this.aMenus[sPath].add(menuItem);
+                }
+                
+                mapNode = node.findNextNode('MapDefinition');
+            }
+        }
+    },
     
+    createFolders: function(sId) {
+        var aPath = sId.split('/');
+        //loop through folders, creating them if they don't exist
+        var sParent = '';
+        var sSep = '';
+        for (var i=0; i < aPath.length; i++) {
+            if (!this.aMenus[sParent + sSep + aPath[i]]){
+                var opt = {label:aPath[i]};
+                var menu = new Jx.SubMenu(opt);
+                if (sParent == '') {
+                    this.oMenu.add(menu);
+                } else {
+                    this.aMenus[sParent].add(menu);
+                }
+                this.aMenus[sParent + sSep + aPath[i]] = menu;
+            }
+            sParent = sParent + sSep + aPath[i];
+            sSep = '/';
+        };
+    },
+    
+    //action to perform when the button is clicked
+    activateTool: function() {
+        this.oMenu.show();
+    },
+        
+    //change the map, preserving current extents
     switchMap: function(data) {
+        var ce = this.getMap().getCurrentExtents();
+        data.initialView = {minX:ce.left,
+                            minY:ce.bottom,
+                            maxX:ce.right,
+                            maxY:ce.top
+                            };        
         this.getMap().loadMapGroup(data);
     }
 };
\ No newline at end of file

Copied: sandbox/aboudreault/widgets/Maptip (from rev 1352, trunk/widgets/Maptip)

Deleted: sandbox/aboudreault/widgets/Maptip/Maptip.css
===================================================================
--- trunk/widgets/Maptip/Maptip.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Maptip/Maptip.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,119 +0,0 @@
-div.maptipContainer{
-    display: none;
-    border: 1px solid #000;
-    background-color: #E5DAC7;
-    line-height: 0px;
-    font-size: 0px;
-    position: absolute;
-    z-index: 101;
-}
-
-iframe.maptipShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}
-
-div.maptipContent {
-  font-family:  Arial, Helvetica, sans-serif;
-  font-size: 11px; 
-  line-height: 14px;
-  padding: 4px;
-}
-
-div.maptipContainer{
-    display: none;
-    border: 1px solid #000;
-    background-color: #E5DAC7;
-    line-height: 0px;
-    font-size: 0px;
-    position: absolute;
-    z-index: 101;
-}
-
-iframe.maptipShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}
-
-div.maptipContent {
-  font-family:  Arial, Helvetica, sans-serif;
-  font-size: 11px; 
-  line-height: 14px;
-  padding: 4px;
-}
-
-div.maptipContainer{
-    display: none;
-    border: 1px solid #000;
-    background-color: #E5DAC7;
-    line-height: 0px;
-    font-size: 0px;
-    position: absolute;
-    z-index: 101;
-}
-
-iframe.maptipShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}
-
-div.maptipContent {
-  font-family:  Arial, Helvetica, sans-serif;
-  font-size: 11px; 
-  line-height: 14px;
-  padding: 4px;
-}
-
-div.maptipContainer{
-    display: none;
-    border: 1px solid #000;
-    background-color: #E5DAC7;
-    line-height: 0px;
-    font-size: 0px;
-    position: absolute;
-    z-index: 101;
-}
-
-iframe.maptipShim {
-    position:absolute;
-    top: 0px;
-    left: 0px;
-    width: 100%;
-    height: 100%;
-    filter: Alpha(opacity:0);
-    opacity: 0;
-    -moz-opacity: 0;
-    z-index: -1;
-}
-
-div.maptipContent {
-  font-family:  Arial, Helvetica, sans-serif;
-  font-size: 11px; 
-  line-height: 14px;
-  padding: 4px;
-}
-
-
-
-

Copied: sandbox/aboudreault/widgets/Maptip/Maptip.css (from rev 1352, trunk/widgets/Maptip/Maptip.css)
===================================================================
--- sandbox/aboudreault/widgets/Maptip/Maptip.css	                        (rev 0)
+++ sandbox/aboudreault/widgets/Maptip/Maptip.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,119 @@
+div.maptipContainer{
+    display: none;
+    border: 1px solid #000;
+    background-color: #E5DAC7;
+    line-height: 0px;
+    font-size: 0px;
+    position: absolute;
+    z-index: 101;
+}
+
+iframe.maptipShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}
+
+div.maptipContent {
+  font-family:  Arial, Helvetica, sans-serif;
+  font-size: 11px; 
+  line-height: 14px;
+  padding: 4px;
+}
+
+div.maptipContainer{
+    display: none;
+    border: 1px solid #000;
+    background-color: #E5DAC7;
+    line-height: 0px;
+    font-size: 0px;
+    position: absolute;
+    z-index: 101;
+}
+
+iframe.maptipShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}
+
+div.maptipContent {
+  font-family:  Arial, Helvetica, sans-serif;
+  font-size: 11px; 
+  line-height: 14px;
+  padding: 4px;
+}
+
+div.maptipContainer{
+    display: none;
+    border: 1px solid #000;
+    background-color: #E5DAC7;
+    line-height: 0px;
+    font-size: 0px;
+    position: absolute;
+    z-index: 101;
+}
+
+iframe.maptipShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}
+
+div.maptipContent {
+  font-family:  Arial, Helvetica, sans-serif;
+  font-size: 11px; 
+  line-height: 14px;
+  padding: 4px;
+}
+
+div.maptipContainer{
+    display: none;
+    border: 1px solid #000;
+    background-color: #E5DAC7;
+    line-height: 0px;
+    font-size: 0px;
+    position: absolute;
+    z-index: 101;
+}
+
+iframe.maptipShim {
+    position:absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 100%;
+    filter: Alpha(opacity:0);
+    opacity: 0;
+    -moz-opacity: 0;
+    z-index: -1;
+}
+
+div.maptipContent {
+  font-family:  Arial, Helvetica, sans-serif;
+  font-size: 11px; 
+  line-height: 14px;
+  padding: 4px;
+}
+
+
+
+

Modified: sandbox/aboudreault/widgets/Maptip.js
===================================================================
--- sandbox/aboudreault/widgets/Maptip.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Maptip.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -56,6 +56,7 @@
     delay: null,
     aLayers: null,
     bOverTip: false,
+    sWinFeatures : 'menubar=no,location=no,resizable=no,status=no',
     
     initialize : function(widgetTag)
     {
@@ -63,7 +64,12 @@
         Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
         var json = widgetTag.extension;
         
+        this.sTarget = json.Target ? json.Target[0] : "MaptipWindow";
+        if (json.WinFeatures) {
+          this.sWinFeatures = json.WinFeatures[0];
+        }
         this.delay = json.Delay ? parseInt(json.Delay[0]) : 350;
+        this.nTolerance = json.Tolerance ? parseInt(json.Tolerance[0]) : 2;
         
         this.aLayers = [];
         if (json.Layer) {
@@ -72,18 +78,29 @@
             }
         }
         
-        this.domObj.parentNode.removeChild(this.domObj);
-        this.domObj.style.position = 'absolute';
+        //prepare the container div for the maptips
+        Fusion.addWidgetStyleSheet(widgetTag.location + 'Maptip/Maptip.css');
+        if (this.domObj) {
+          this.domObj.parentNode.removeChild(this.domObj);
+        } else {
+          this.domObj = document.createElement('div');
+        }
+        this.domObj.className = 'maptipContainer';
         this.domObj.style.display = 'none';
         this.domObj.style.top = '0px';
         this.domObj.style.left = '0px';
-        this.domObj.style.zIndex = 101;
         
+        //create an iframe to stick behind the maptip to prevent clicks being passed through to the map
+        this.iframe = document.createElement('iframe');
+        this.iframe.className = 'maptipShim';
+        this.iframe.scrolling = 'no';
+        this.iframe.frameborder = 0;
+        
         Event.observe(this.domObj, 'mouseover', this.mouseOverTip.bind(this));
         Event.observe(this.domObj, 'mouseout', this.mouseOutTip.bind(this));
         
         var oDomElem =  this.getMap().getDomObj();
-        oDomElem.appendChild(this.domObj);
+        document.getElementsByTagName('BODY')[0].appendChild(this.domObj);
         
         this.getMap().observeEvent('mousemove', this.mouseMove.bind(this));
         this.getMap().observeEvent('mouseout', this.mouseOut.bind(this));
@@ -107,18 +124,11 @@
             return;
         }
         var p = this.getMap().getEventPosition(e);
-        if (!this.oCurrentPosition) {
-            this.oCurrentPosition = p;
-        } else {
+        this.oCurrentPosition = p;
+        this.oMapTipPosition = {x:Event.pointerX(e), y:Event.pointerY(e)};
+        if (this.oCurrentPosition) {
             window.clearTimeout(this.nTimer);
             this.nTimer = null;
-            if (this.oMapTipPosition && this.bIsVisible &&
-                Math.abs(this.oMapTipPosition.x -this.oCurrentPosition.x) > 3 &&
-                Math.abs(this.oMapTipPosition.y - this.oCurrentPosition.y) > 3) {
-                /*console.log('mouseMove: set hide timer');*/
-                this.nHideTimer = window.setTimeout(this.hideMaptip.bind(this), 250);
-            }
-            this.oCurrentPosition = p;
         }
         this.nTimer = window.setTimeout(this.showMaptip.bind(this), this.delay);
         //Event.stop(e);
@@ -130,33 +140,27 @@
         if (map == null) {
           return;
         }
-        var cellSize = map._nCellSize;
-        cellSize = 1e-6;
 
         var oBroker = Fusion.oBroker;
         var x = this.oCurrentPosition.x;
         var y = this.oCurrentPosition.y;
-        var min = map.pixToGeo(x, y);
+        var min = map.pixToGeo(x-this.nTolerance, y-this.nTolerance);
+        var max = map.pixToGeo(x+this.nTolerance, y+this.nTolerance);
         //this can fail if no map is loaded
         if (!min) {
             return;
         }
-        min.x -= cellSize;
-        min.y -= cellSize;
-        var max = map.pixToGeo(x, y);
-        max.x += cellSize;
-        max.y += cellSize;
         var sGeometry = 'POLYGON(('+ min.x + ' ' +  min.y + ', ' +  min.x + ' ' +  max.y + ', ' + max.x + ' ' +  max.y + ', ' + max.x + ' ' +  min.y + ', ' + min.x + ' ' +  min.y + '))';
 
         //var sGeometry = 'POINT('+ min.x + ' ' +  min.y + ')';
 
-         var maxFeatures = 1;
-         var persist = 0;
-         var selection = 'INTERSECTS';
+        var maxFeatures = 1;
+        var persist = 0;
+        var selection = 'INTERSECTS';
         var maps = this.getMap().getAllMaps();
-         //TODO: possibly make the layer names configurable?
-         var layerNames = this.aLayers.toString();
-         var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(maps[0].getSessionID(),
+        //TODO: possibly make the layer names configurable?
+        var layerNames = this.aLayers.toString();
+        var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(maps[0].getSessionID(),
                                         maps[0]._sMapname,
                                         sGeometry,
                                         maxFeatures, persist, selection, layerNames);
@@ -167,19 +171,48 @@
     _display: function(r) {
       //console.log('maptip _display');
         if (r.responseXML) {
+            this.domObj.innerHTML = '&nbsp;';
+            var contentDiv = document.createElement('div');
+            contentDiv.className = 'maptipContent';
+            this.domObj.appendChild(contentDiv);
+            
+            var empty = true;
             this.bIsVisible = true;
-            this.oMapTipPosition = {x:this.oCurrentPosition.x, y: this.oCurrentPosition.y};
             var d = new DomNode(r.responseXML);
             var t = d.getNodeText('Tooltip');
             if (t != '') {
-                t = t.replace(/\\n/g, "<br>");
-                this.domObj.innerHTML = t;
+              t = t.replace(/\\n/g, "<br>");
+              contentDiv.innerHTML = t;
+              empty = false;
+            }
+            var h = d.getNodeText('Hyperlink');
+            if (h != '') {
+              var linkDiv = document.createElement('div');
+              var a = document.createElement('a');
+              a.innerHTML = h;
+              a.href = 'javascript:void(0)';
+              a.onclick = this.openLink.bindAsEventListener(this, h);
+              linkDiv.appendChild(a);
+              contentDiv.appendChild(linkDiv);
+              empty = false;
+            }
+            if (!empty) {
                 this.domObj.style.visibility = 'hidden';
                 this.domObj.style.display = 'block';
                 var size = Element.getDimensions(this.domObj);
-                this.domObj.style.top = (this.oCurrentPosition.y - size.height) + 'px';
-                this.domObj.style.left = this.oCurrentPosition.x + 'px';
+                this.domObj.style.top = (this.oMapTipPosition.y - size.height) + 'px';
+                this.domObj.style.left = (this.oMapTipPosition.x) + 'px';
+                
+                if (!window.opera) {
+                    contentDiv.appendChild(this.iframe);
+                    var size = Element.getContentBoxSize(this.domObj);
+                    this.iframe.style.width = size.width + "px";
+                    this.iframe.style.height = size.height + "px";
+                }
+                
                 this.domObj.style.visibility = 'visible';
+            } else {
+                this.hideMaptip();
             }
         } else {
             this.bIsVisible = false;
@@ -189,14 +222,13 @@
     hideMaptip: function() {
       //console.log('hideMaptip');
         this.bIsVisible = false;
-        this.hideTimer = window.setTimeout(this._hide.bind(this),250);
+        this.hideTimer = window.setTimeout(this._hide.bind(this),10);
     },
     
     _hide: function() {
       //console.log('maptip _hide');
         this.hideTimer = null;
         this.domObj.style.display = 'none';
-        this.domObj.innerHTML = '&nbsp;';
         this.oMapTipPosition = null;
     },
     
@@ -211,6 +243,21 @@
       //console.log('mouseOutTip');
         this.nHideTimer = window.setTimeout(this.hideMaptip.bind(this), 250);
         this.bOverTip = false;
+    },
+    
+    openLink : function(evt, url) {
+        var taskPaneTarget = Fusion.getWidgetById(this.sTarget);
+        if ( taskPaneTarget ) {
+            taskPaneTarget.setContent(url);
+        } else {
+            var pageElement = $(this.sTarget);
+            if ( pageElement ) {
+                pageElement.src = url;
+            } else {
+                window.open(url, this.sTarget, this.sWinFeatures);
+            }
+        }
+        OpenLayers.Event.stop(evt, true);
+        return false;
     }
-    
 };

Modified: sandbox/aboudreault/widgets/Measure/Measure.css
===================================================================
--- sandbox/aboudreault/widgets/Measure/Measure.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Measure/Measure.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -16,6 +16,10 @@
   z-index: 200;
 }
 
+.divMeasureTotal {
+  z-index: 201;
+}
+
 #MeasurementWidgetResults table, 
 #MeasurementWidgetResults tbody, 
 #MeasurementWidgetResults thead, 


Property changes on: sandbox/aboudreault/widgets/Measure/Measure.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Measure/Measure.php
===================================================================
--- sandbox/aboudreault/widgets/Measure/Measure.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Measure/Measure.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Measure
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -23,6 +23,20 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+ 
+  $fusionMGpath = '../../MapGuide/php/';
+  include $fusionMGpath . 'Common.php';
+  SetLocalizedFilesPath(GetLocalizationPath());
+  if(isset($_REQUEST['locale'])) {
+    $locale = $_REQUEST['locale'];
+  } else {
+    $locale = GetDefaultLocale();
+  }
+
+  $title = GetLocalizedString( "MEASURETITLE", $locale );
+  $total = GetLocalizedString( "TOTAL", $locale );
+  $segment = GetLocalizedString( "SEGMENT", $locale );
+  $length = GetLocalizedString( "LENGTH", $locale );
 ?>
 
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
@@ -30,86 +44,27 @@
 <html>
 <head>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8">
-    <title>Measure</title>
+    <title><?php echo $title ?></title>
     <style type="text/css" media="screen">
         @import url(Measure.css);
     </style>
-    <script type="text/javascript" charset="utf-8">
-        var Fusion;
-        var measureWidgets;
-        var currentWidget;
-        window.onload = function() {
-            Fusion = window.top.Fusion;
-            measureWidgets = Fusion.getWidgetsByType('Measure');
-            for (var i=0; i<measureWidgets.length; i++) {
-              measureWidgets[i].registerForEvent(Fusion.Event.MEASURE_NEW_SEGMENT, measureNewSegment);
-              measureWidgets[i].registerForEvent(Fusion.Event.MEASURE_CLEAR, measureClear);  
-            }
-        };
-        
-        function measureNewSegment(eventId, widget, marker) {
-            marker.registerForEvent(Fusion.Event.MARKER_DISTANCE_CHANGED, measureSegmentUpdate)
-            var tbody = document.getElementById('segmentTBody');
-            var segmentId = tbody.childNodes.length + 1;
-            var tr = document.createElement('tr');
-            tr.marker = marker;
-            var td = document.createElement('td');
-            td.innerHTML = 'Segment '+segmentId;
-            tr.appendChild(td);
-            var td = document.createElement('td');
-            td.innerHTML = '...';
-            tr.appendChild(td);
-            tbody.appendChild(tr);
-        }
-        
-        function measureSegmentUpdate(eventId, marker) {
-            var distanceText = 'calculating ...';
-            var distanceValue = 0;
-            var distance = marker.getDistanceLabel();
-            if (distance) {
-                distanceText = distance;
-                distanceValue = parseFloat(distance);
-            }
-            var totalDistance = 0;
-            var tbody = document.getElementById('segmentTBody');
-            for (var i=0; i<tbody.childNodes.length; i++) {
-                if (tbody.childNodes[i].marker == marker) {
-                    tbody.childNodes[i].childNodes[1].innerHTML = distanceText;
-                }
-                totalDistance += parseFloat(tbody.childNodes[i].childNodes[1].innerHTML);
-            }
-            var tDist = document.getElementById('totalDistance');
-            tDist.innerHTML = totalDistance + ' ' + marker.unitAbbr;
-        }
-        
-        function measureClear() {
-            var tbody = document.getElementById('segmentTBody');
-            while(tbody.firstChild) {
-                tbody.firstChild.marker.deregisterForEvent(Fusion.Event.MARKER_DISTANCE_CHANGED, measureSegmentUpdate);
-                tbody.firstChild.marker = null;
-                tbody.removeChild(tbody.firstChild);
-            }
-            var tDist = document.getElementById('totalDistance');
-            tDist.innerHTML = '';
-        }
-    </script>
 </head>
 <body id="MeasurementWidgetResults">
-    <h1>Measurement Results</h1>
+    <h1><?php echo $title ?></h1>
     <table id="MeasurementWidgetResultsTable" border="0" cellspacing="5" cellpadding="5">
         <thead>
             <tr>
-                <th>Segment</th>
-                <th>Length</th>
+                <th><?php echo $segment ?></th>
+                <th><?php echo $length ?></th>
             </tr>
         </thead>
         <tbody id="segmentTBody"></tbody>
         <tfoot>
             <tr>
-                <th>Total</th>
+                <th><?php echo $total ?></th>
                 <td id="totalDistance"></td>
             </tr>
         </tfoot>
     </table>
 </body>
-</html>
\ No newline at end of file
+</html>


Property changes on: sandbox/aboudreault/widgets/Measure/Measure.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Measure/MeasurePending.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Measure.js
===================================================================
--- sandbox/aboudreault/widgets/Measure.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Measure.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -35,10 +35,9 @@
 Fusion.Constant.MEASURE_TYPE_AREA = 1;
 Fusion.Constant.MEASURE_TYPE_BOTH = 2;
 
-Fusion.Event.MEASURE_NEW_SEGMENT = Fusion.Event.lastEventId++;
 Fusion.Event.MEASURE_SEGMENT_UPDATE = Fusion.Event.lastEventId++;
-Fusion.Event.MEASURE_SEGMENT_COMPLETE = Fusion.Event.lastEventId++;
 Fusion.Event.MEASURE_CLEAR = Fusion.Event.lastEventId++;
+Fusion.Event.MEASURE_COMPLETE = Fusion.Event.lastEventId++;
 
 Fusion.Widget.Measure = Class.create();
 Fusion.Widget.Measure.prototype = {
@@ -56,7 +55,6 @@
     //cumulativeArea
     cumulativeArea: 0,
     lastArea: 0,
-    aAreas: [],
     
     /* the units to display distances in */
     units: Fusion.UNKNOWN,
@@ -65,23 +63,11 @@
     mType: null,
 
     /* Precision of the distance displayed */
-    distPrecision: 0,
+    distPrecision: 4,
     
     /* Precision of the area displayed */
-    areaPrecision: 0,
+    areaPrecision: 4,
     
-    /* an HTML container to put the current distance in */
-    measureTip: null,
-        
-    /* Static position of Tooltip Box TOP */
-    measureTipPositionTop: null,
-   
-    /* Static position of Tooltip Box LEFT */ 
-    measureTipPositionLeft: null,
-    
-    /* Tooltip appearance: static or dynamic */
-    tooltipType: '',
-
     /* Style for the distance line used for distance draw */   
     distanceNormalStyle: null,
 
@@ -98,8 +84,8 @@
         this.asCursor = ['crosshair'];
         var json = widgetTag.extension;
         this.units = (json.Units && (json.Units[0] != '')) ?  Fusion.unitFromName(json.Units[0]): this.units;
-        this.distPrecision = json.DistancePrecision ? json.DistancePrecision[0] : 2;
-        this.areaPrecision = json.AreaPrecision ? json.AreaPrecision[0] : 2;  
+        this.distPrecision = json.DistancePrecision ? parseInt(json.DistancePrecision[0]) : 4;
+        this.areaPrecision = json.AreaPrecision ? parseInt(json.AreaPrecision[0]) : 4;  
         
         this.sTarget = json.Target ? json.Target[0] : "";
         this.sBaseUrl = Fusion.getFusionURL() + 'widgets/Measure/Measure.php';
@@ -129,17 +115,16 @@
         this.distanceMarkers = [];
         this.distances = [];
         
-        this.registerEventID(Fusion.Event.MEASURE_NEW_SEGMENT);
-        this.registerEventID(Fusion.Event.MEASURE_SEGMENT_COMPLETE);
         this.registerEventID(Fusion.Event.MEASURE_SEGMENT_UPDATE);
         this.registerEventID(Fusion.Event.MEASURE_CLEAR);
+        this.registerEventID(Fusion.Event.MEASURE_COMPLETE);
+        
         this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.resetCanvas.bind(this));
         this.keyHandler = this.onKeyPress.bind(this);
         Fusion.addWidgetStyleSheet(widgetTag.location + 'Measure/Measure.css');
 
-        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this));
+        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this, this.units));
         this.registerParameter('Units');
-        
     },
     
     onKeyPress: function(e) {
@@ -167,8 +152,6 @@
      * reset area and/or distance vars
      */    
     initVars: function() {
-        this.aDistances = [];
-        this.aAreas = [];
         this.cumulativeDistance = 0;
         this.lastDistance = 0;
         this.cumulativeArea = 0;
@@ -181,23 +164,43 @@
         this.initVars();
         this.triggerEvent(Fusion.Event.MEASURE_CLEAR, this);
         Event.observe(document,"keypress",this.keyHandler);
-        this.showPanel();
+        this.loadDisplayPanel();
     },
     
-    showPanel : function() {
+    loadDisplayPanel : function() {
         if (this.sTarget) {
             var url = this.sBaseUrl;
+            var queryStr = 'locale='+Fusion.locale;
+            if (url.indexOf('?') < 0) {
+                url += '?';
+            } else if (url.slice(-1) != '&') {
+                url += '&';
+            }
+            url += queryStr;
+            
             var taskPaneTarget = Fusion.getWidgetById(this.sTarget);
-            var pageElement = $(this.sTarget);
+            var outputWin = window;
             if ( taskPaneTarget ) {
                 taskPaneTarget.setContent(url);
+                outputWin = taskPaneTarget.iframe.contentWindow;
             } else {
-                if ( pageElement ) {
-                    pageElement.src = url;
-                } else {
-                    window.open(url, this.sTarget, this.sWinFeatures);
-                }
+                outputWin = window.open(url, this.sTarget, this.sWinFeatures);
             }
+            this.registerForEvent(Fusion.Event.MEASURE_CLEAR, this.clearDisplay.bind(this, outputWin));  
+            this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this.updateDisplay.bind(this, outputWin));
+            this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, this.updateDisplay.bind(this, outputWin));
+        } else {
+            this.totalDistanceMarker = new Fusion.Widget.Measure.DistanceMarker(this.units, this.distPrecision, 'Total:');
+            var oDomElem =  this.getMap().getDomObj();
+            if (!this.totalDistanceMarker.domObj.parentNode || 
+                this.totalDistanceMarker.domObj.parentNode != oDomElem) {
+                oDomElem.appendChild(this.totalDistanceMarker.domObj);
+            }
+            Element.addClassName(this.totalDistanceMarker.domObj, 'divMeasureTotal');
+            this.totalDistanceMarker.domObj.style.display = 'none';
+            this.registerForEvent(Fusion.Event.MEASURE_CLEAR, this.clearTotalDistance.bind(this));  
+            this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this.updateTotalDistance.bind(this));
+            this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, this.updateTotalDistance.bind(this));
         }
     },    
     
@@ -269,7 +272,7 @@
                 this.updateMarker(this.lastMarker, lastSegment, e);
             }
             //create a new marker
-            this.lastMarker = new Fusion.Widget.Measure.DistanceMarker(this.units);
+            this.lastMarker = new Fusion.Widget.Measure.DistanceMarker(this.units, this.distPrecision);
             this.distanceMarkers.push(this.lastMarker);
             this.clearContext();
             this.feature.draw(this.context);
@@ -289,10 +292,7 @@
         }
         var offset = {x:0,y:0};
         var oElement = this.getMap().getDomObj();
-        var target = e.target || e.srcElement;
-        if (target.id != 'featureDigitizer') { 
-            return;
-        }
+        //var target = e.target || e.srcElement;
         if (this.delayUpdateTimer) {
             window.clearTimeout(this.delayUpdateTimer);
         }
@@ -304,11 +304,15 @@
         lastSegment.to.set(gp.x,gp.y);
         this.clearContext();
         this.feature.draw(this.context);
-        this.delayUpdateTimer = window.setTimeout(this.delayUpdate.bind(this, lastSegment, e), 250);
         this.lastMarker.setCalculating();
-        this.triggerEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this, this.lastMarker, null);
+        this.delayUpdateTimer = window.setTimeout(this.delayUpdate.bind(this, lastSegment, e), 100);
         
         this.positionMarker(this.lastMarker, lastSegment);
+        if (this.totalDistanceMarker) {
+          var size = this.totalDistanceMarker.getSize();
+          this.totalDistanceMarker.domObj.style.top = (p.y - size.height) + 'px';
+          this.totalDistanceMarker.domObj.style.left = p.x + 'px';
+        }
     },
     
     delayUpdate: function(lastSegment, e) {
@@ -342,6 +346,11 @@
         }  
 
         this.isDigitizing = false;
+        
+        //mousedown creates a new segment before dblClick so remove the last one
+        var lastMarker = this.distanceMarkers.pop();
+        lastMarker.destroy();
+        this.triggerEvent(Fusion.Event.MEASURE_COMPLETE);                    
     },
     
     positionMarker: function(marker, segment) {
@@ -349,7 +358,6 @@
         if (!marker.domObj.parentNode || 
             marker.domObj.parentNode != oDomElem) {
             oDomElem.appendChild(marker.domObj);
-            this.triggerEvent(Fusion.Event.MEASURE_NEW_SEGMENT, this, marker);
         }
         var size = marker.getSize();
         var t = (segment.from.py + segment.to.py - size.height)/2 ;
@@ -374,7 +382,7 @@
         var s = aMaps[0].arch + '/' + Fusion.getScriptLanguage() + "/Measure." + Fusion.getScriptLanguage() ;
         var sessionId = aMaps[0].getSessionID();
         var params = {};
-        params.parameters = 'session='+sessionId+'&mapname='+ this.getMap().getMapName()+points;
+        params.parameters = 'session='+sessionId+'&locale='+Fusion.locale+'&mapname='+ this.getMap().getMapName()+points;
         params.onComplete = this.measureCompleted.bind(this, segment, marker);
         Fusion.ajaxRequest(s, params);
     },
@@ -384,29 +392,111 @@
             var o;
             eval('o='+r.responseText);
             if (o.distance) {
-              var mapUnits = Fusion.unitFromName(this.getMap().getUnits());
-              if (mapUnits != this.units)
+              /* distance returned is always in meters*/
+              //var mapUnits = Fusion.unitFromName(this.getMap().getUnits());
+              //if (mapUnits == Fusion.DEGREES || Fusion.DECIMALDEGREES)
+              mapUnits = Fusion.METERS;
+
+              if (mapUnits != this.units) {
                 o.distance = Fusion.convert(mapUnits, this.units, o.distance);
-                var p = Math.pow(1,this.distPrecision);
-                var d = Math.round(o.distance*p)/p;
-                /* convert the distance from map units to the units set bu the use*/
-                
-                marker.setDistance(d);
-                this.positionMarker(marker, segment);
-                if (segment == this.feature.lastSegment()) {
-                    this.triggerEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this, marker, d);                    
-                } else {
-                    this.triggerEvent(Fusion.Event.MEASURE_SEGMENT_COMPLETE, this, marker, d);
+              }
+              
+              marker.setDistance(o.distance);
+              this.positionMarker(marker, segment);
+              this.triggerEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE);                    
+            }
+        }
+    },
+    
+  /*
+      * updates the summary display if it is loaded in a window somewhere
+      */
+    updateDisplay: function(outputWin) {
+        var outputDoc = outputWin.document;
+        var tbody = outputDoc.getElementById('segmentTBody');
+        var value;
+        if (tbody) {
+            this.clearDisplay(outputWin);
+            var totalDistance = 0;
+            var units = Fusion.unitAbbr(this.units);
+            for (var i=0; i<this.distanceMarkers.length; i++) {
+                var distance = this.distanceMarkers[i].getDistance();
+                totalDistance += distance;
+            
+                var tr = outputDoc.createElement('tr');
+                var td = outputDoc.createElement('td');
+                td.innerHTML = OpenLayers.String.translate('segment',i+1);
+                tr.appendChild(td);
+                td = outputDoc.createElement('td');
+                if (this.distPrecision == 0) {
+                  value = Math.floor(distance);
                 }
+                else {
+                  value = distance.toPrecision(this.distPrecision);
+                }
+                td.innerHTML = value + ' ' + units;
+                tr.appendChild(td);
+                tbody.appendChild(tr);
             }
+            var tDist = outputDoc.getElementById('totalDistance');
+            if (this.distPrecision == 0) {
+                  value = Math.floor(totalDistance);
+            }
+            else {
+              value = totalDistance.toPrecision(this.distPrecision);
+            }
+            tDist.innerHTML = value + ' ' + units;
         }
     },
     
-    setUnits: function() {
-      if (this.units == Fusion.UNKNOWN) {
-        this.setParameter('Units',this.getMap().getUnits());
+  /*
+      * updates the summary display if it is loaded in a window somewhere
+      */
+    updateTotalDistance: function() {
+      if (this.distanceMarkers.length > 1) {
+        var totalDistance = 0;
+        var units = Fusion.unitAbbr(this.units);
+        for (var i=0; i<this.distanceMarkers.length; i++) {
+            var distance = this.distanceMarkers[i].getDistance();
+            totalDistance += distance;
+        }
+        this.totalDistanceMarker.domObj.style.display = 'block';
+        this.totalDistanceMarker.setDistance(totalDistance);
       }
     },
+    
+  /*
+      *clears the summary display if it is loaded in a window somewhere
+      */
+    clearDisplay: function(outputWin) {
+        var outputDoc = outputWin.document;
+        var tbody = outputDoc.getElementById('segmentTBody');
+        if (tbody) {
+          while(tbody.firstChild) {
+              tbody.firstChild.marker = null;
+              tbody.removeChild(tbody.firstChild);
+          }
+          var tDist = outputDoc.getElementById('totalDistance');
+          tDist.innerHTML = '';
+        }
+    },
+    
+  /*
+      *clears the summary display if it is loaded in a window somewhere
+      */
+    clearTotalDistance: function() {
+      this.totalDistanceMarker.domObj.style.display = 'none';
+    },
+    
+  /*
+     * Callback method for the MAP_LOADED event
+     * Set the units to whatever is specified in the AppDef, or the mapUnits if not specified
+     * Subsequent calls from a ViewOptions widget would override the value specified.
+     */
+    setUnits: function(units) {
+      units = (units == Fusion.UNKNOWN)?Fusion.unitFromName(this.getMap().getUnits()):units;
+      this.setParameter('Units', Fusion.unitName(units));
+    },
 
     setParameter: function(param, value) {
       //console.log('setParameter: ' + param + ' = ' + value);
@@ -415,43 +505,43 @@
             for (var i=0; i<this.distanceMarkers.length; i++) {
                 this.distanceMarkers[i].setUnits(this.units);
             }
+            if (this.totalDistanceMarker) {
+              this.totalDistanceMarker.setUnits(this.units);
+            }
         }
     }
 };
 
-Fusion.Event.MARKER_DISTANCE_CHANGED = Fusion.Event.lastEventId++;
-
+/*
+* A class for handling the 'tooltip' for the distance measurement.  Markers also hold the distance
+values and all markers are held in an array in the Measure widget for access.
+*/
 Fusion.Widget.Measure.DistanceMarker = Class.create();
 Fusion.Widget.Measure.DistanceMarker.prototype = {
     calculatingImg: null,
-    isCalculating: false,
-    distance: null,
-    initialize: function( units) {
-        Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
-        this.registerEventID(Fusion.Event.MARKER_DISTANCE_CHANGED);
+    distance: 0,
+    initialize: function(units, precision, label) {
+        this.precision = precision;
+        this.label = label ? label:'';
         this.domObj = document.createElement('div');
         this.domObj.className = 'divMeasureMarker';
-        this.setUnits(units);
         this.calculatingImg = document.createElement('img');
         this.calculatingImg.src = Fusion.getFusionURL() + 'widgets/Measure/MeasurePending.gif';
         this.calculatingImg.width = 19;
         this.calculatingImg.height = 4;
+        this.setUnits(units);
         this.setCalculating();
     },
     
     destroy: function() {
-        Fusion.Lib.EventMgr.destroy.apply(this, []);
-        if (this.domObj.parentNode) {
-            this.domObj.parentNode.removeChild(this.domObj);
-        }
+      if (this.domObj.parentNode) {
+          this.domObj.parentNode.removeChild(this.domObj);
+      }
     },
     
     setUnits: function(units) {
         this.unit = units;
         this.unitAbbr = Fusion.unitAbbr(units);
-        if (this.distance) {
-            this.setDistance(this.distance);
-        }
     },
     
     getDistance: function() {
@@ -459,12 +549,15 @@
     },
     
     getDistanceLabel: function() {
-        if (this.distance) {
-            var distance = this.distance;
-            return distance + ' ' + this.unitAbbr;            
-        } else {
-            return false;
-        }
+      var value;
+      if (this.precision == 0) {
+        value = Math.floor(this.distance);
+      }
+      else {
+          value = this.distance.toPrecision(this.precision);
+      }
+
+      return this.label + ' ' + value + ' ' + this.unitAbbr;  
     },
     
     setDistance: function(distance) {
@@ -473,19 +566,15 @@
         }
         this.distance = distance;
         this.domObj.innerHTML = this.getDistanceLabel();
-        this.isCalculating = false;
-        this.triggerEvent(Fusion.Event.MARKER_DISTANCE_CHANGED, this);
     },
     
     setCalculating: function() {
-        if (!this.isCalculating) {
-            this.isCalculating = true;
+        if (!this.calculatingImg.parentNode) {
             this.domObj.innerHTML = '';
             this.domObj.appendChild(this.calculatingImg);
-            this.distance = false;
-            this.triggerEvent(Fusion.Event.MARKER_DISTANCE_CHANGED, this);
         }
     },
+    
     getSize: function() {
         var size =  Element.getDimensions(this.domObj);
         var imgSize = {width:19, height:4};
@@ -495,7 +584,6 @@
         if (size.height < imgSize.height) {
             size.height += imgSize.height;
         }
-        
         return size;
     }
 };


Property changes on: sandbox/aboudreault/widgets/Navigator/slider.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Navigator/sliderscale.png
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Navigator/spinner.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Navigator.js
===================================================================
--- sandbox/aboudreault/widgets/Navigator.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Navigator.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.Navigator
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -43,48 +43,48 @@
 
         var a = document.createElement('area');
         a.shape = 'poly';
-        a.alt = 'Pan East';
-        a.title = 'Pan East';
+        a.alt = OpenLayers.String.translate('panEast');
+        a.title = OpenLayers.String.translate('panEast');
         a.coords = '27,176, 27,177, 40,190, 44,182, 44,159';
         Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, this.panAmount/100, 0) );
         m.appendChild(a);
 
         var a = document.createElement('area');
         a.shape = 'poly';
-        a.alt = 'Pan West';
-        a.title = 'Pan West';
+        a.alt = OpenLayers.String.translate('panWest');
+        a.title = OpenLayers.String.translate('panWest');
         a.coords = '24,177, 24,176, 7,159, 7,182, 11,190';
         Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, -this.panAmount/100, 0) );
         m.appendChild(a);
 
         var a = document.createElement('area');
         a.shape = 'poly';
-        a.alt = 'Pan South';
-        a.title = 'Pan South';
+        a.alt = OpenLayers.String.translate('panSouth');
+        a.title = OpenLayers.String.translate('panSouth');
         a.coords = '25,178, 12,191, 21,197, 30,197, 39,191, 26,178';
         Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, 0, -this.panAmount/100) );
         m.appendChild(a);
 
         var a = document.createElement('area');
         a.shape = 'poly';
-        a.alt = 'Pan North';
-        a.title = 'Pan North';
+        a.alt = OpenLayers.String.translate('panNorth');
+        a.title = OpenLayers.String.translate('panNorth');
         a.coords = '26,175, 43,158, 8,158, 25,175';
         Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, 0, this.panAmount/100) );
         m.appendChild(a);
 
         var a = document.createElement('area');
         a.shape = 'circle';
-        a.alt = 'Zoom Out';
-        a.title = 'Zoom Out';
+        a.alt = OpenLayers.String.translate('zoomOut');
+        a.title = OpenLayers.String.translate('zoomOut');
         a.coords = '25,142,8';
         Event.observe(a, 'mouseup', this.zoom.bindAsEventListener(this, 1/this.zoomFactor) );
         m.appendChild(a);
 
         var a = document.createElement('area');
         a.shape = 'circle';
-        a.alt = 'Zoom In';
-        a.title = 'Zoom In';
+        a.alt = OpenLayers.String.translate('zoomIn');
+        a.title = OpenLayers.String.translate('zoomIn');
         a.coords = '25,34,8';
         Event.observe(a, 'mouseup', this.zoom.bindAsEventListener(this, this.zoomFactor) );
         m.appendChild(a);


Property changes on: sandbox/aboudreault/widgets/Navigator.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Pan.js
===================================================================
--- sandbox/aboudreault/widgets/Pan.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Pan.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -37,6 +37,7 @@
         Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
         this.control = new OpenLayers.Control.DragPan();
         this.getMap().oMapOL.addControl(this.control);
+        this.control.handler.keyMask = 0;
         
         this.cursorNormal = ["url('images/grab.cur'),move", 'grab', '-moz-grab', 'move'];
         this.cursorDrag = ["url('images/grabbing.cur'),move", 'grabbing', '-moz-grabbing', 'move'];
@@ -64,4 +65,4 @@
         /*icon button*/
         this._oButton.deactivateTool();
     }
-};
\ No newline at end of file
+};


Property changes on: sandbox/aboudreault/widgets/Print/Print.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Print/pr_north.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Print/printablepage.php
===================================================================
--- sandbox/aboudreault/widgets/Print/printablepage.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Print/printablepage.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -20,7 +20,7 @@
 $fusionMGpath = '../../MapGuide/php/';
 include $fusionMGpath . 'Common.php';
 
-    $locale = "";
+    $locale = "en";
     $mapName = "";
     $sessionId = "";
     $isTitle = "";
@@ -39,7 +39,7 @@
     $templ = Localize($templ, $locale, GetClientOS());
     $agent = GetRootVirtualFolder() . "/mapagent/mapagent.fcgi";
     print sprintf($templ,
-                  $mapName,
+                  $title,
                   $agent,
                   $scale,
                   $centerX,
@@ -47,6 +47,7 @@
                   $dpi,
                   $mapName,
                   $sessionId,
+                  $locale,
                   $isTitle,
                   $isLegend,
                   $isArrow,


Property changes on: sandbox/aboudreault/widgets/Print/printablepage.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Print/printablepage.templ
===================================================================
--- sandbox/aboudreault/widgets/Print/printablepage.templ	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Print/printablepage.templ	2008-03-31 14:35:37 UTC (rev 1353)
@@ -23,6 +23,7 @@
     var dpi = %s;
     var mapName = '%s';
     var sessionId = '%s';
+    var locale = '%s';
     var isTitle = %s, isLegend= %s, isArrow = %s;
 
     function InitDocument()
@@ -47,55 +48,17 @@
             mapHeight += 58;
             document.getElementById("ScaleAndArrow").style.height = "0px";
         }
-
+        
+        var imgReq = webAgent + "?OPERATION=GETMAPIMAGE&VERSION=1.0.0&FORMAT=PNG&LOCALE="+locale+"&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SETDISPLAYWIDTH=" + mapWidth + "&SETDISPLAYHEIGHT=" + mapHeight + "&SETDISPLAYDPI=" + dpi + "&SETVIEWSCALE=" + scale + "&SETVIEWCENTERX=" + centerX + "&SETVIEWCENTERY=" + centerY + "&SEQ=" + Math.random();
+        
         var mapElt = document.getElementById("Map");
         mapElt.style.width = mapWidth + "px";
-        mapElt.innerHTML = "<img id=\"mapImage\" width=\"" + mapWidth + "\" height=\"" + mapHeight + "\" src=\"\" style=\"visibility: hidden;\" onload=\"OnImageLoaded('mapImage');\">";
+        mapElt.innerHTML = "<img id=\"mapImage\" width=\"" + mapWidth + "\" height=\"" + mapHeight + "\" src=\""+imgReq+"\" style=\"visibility: hidden;\" onload=\"OnImageLoaded('mapImage');\">";
 
         if(isArrow)
             document.getElementById("Arrow").innerHTML = "<img width=\"38\" height=\"58\" src=\"pr_north.gif\">";
-
-        var requester;
-        if(msie)
-            requester = new ActiveXObject("Microsoft.XMLHTTP");
-        else
-            requester = new XMLHttpRequest();
-
-        var reqParams = "OPERATION=GETVISIBLEMAPEXTENT&VERSION=1.0.0&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SETDISPLAYWIDTH=" + mapWidth + "&SETDISPLAYHEIGHT=" + mapHeight + "&SETDISPLAYDPI=" + dpi + "&SETVIEWSCALE=" + scale + "&SETVIEWCENTERX=" + centerX + "&SETVIEWCENTERY=" + centerY + "&SEQ=" + Math.random();
-
-        requester.open("POST", webAgent, false);
-        requester.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-        requester.send(reqParams);
-
-        if(requester.responseXML)
-        {
-            if(ValidateMapResponse(requester.responseXML.documentElement))
-                document.getElementById("mapImage").src = webAgent + "?OPERATION=GETMAPIMAGE&VERSION=1.0.0&SELECTION=&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId;
-        }
     }
 
-    function ValidateMapResponse(xmlRoot)
-    {
-        try
-        {
-            if(xmlRoot.tagName != "Envelope")
-                return false;
-
-            var xs = xmlRoot.getElementsByTagName("X");
-            var ys = xmlRoot.getElementsByTagName("Y");
-            parseFloat(xs[0].childNodes[0].nodeValue);
-            parseFloat(ys[0].childNodes[0].nodeValue);
-            parseFloat(xs[1].childNodes[0].nodeValue);
-            parseFloat(ys[1].childNodes[0].nodeValue);
-
-            return true;
-        }
-        catch(e)
-        {
-        }
-        return false;
-    }
-
     function OnImageLoaded(id)
     {
         document.getElementById(id).style.visibility = "visible";


Property changes on: sandbox/aboudreault/widgets/Print/printablepage.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Print.js
===================================================================
--- sandbox/aboudreault/widgets/Print.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Print.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -54,11 +54,12 @@
         var showNorthArrow =json.ShowNorthArrow ? json.ShowNorthArrow[0] : 'false';
         this.showNorthArrow = (showNorthArrow.toLowerCase() == 'true' || showNorthArrow == '1');
         
+        this.imageBaseUrl = json.ImageBaseUrl ? json.ImageBaseUrl[0] : null;
+        
         this.dialogContentURL = Fusion.getFusionURL() + widgetTag.location + 'Print/Print.html';
         this.printablePageURL = Fusion.getFusionURL() + widgetTag.location + 'Print/printablepage.php';
         Fusion.addWidgetStyleSheet(widgetTag.location + 'Print/Print.css');
         
-        
         /*
          * TODO: this is bad, why did we do this?
          this.getMap().registerForEvent(Fusion.Event.SELECTION_COMPLETE, this.getSelection.bind(this));
@@ -82,14 +83,16 @@
 
             var size = Element.getPageDimensions();
             var o = {
-                title: 'Printable Page ',
+                title: OpenLayers.String.translate('printTitle'),
                 id: 'printablePage',
                 contentURL : this.dialogContentURL,
                 onContentLoaded: this.contentLoaded.bind(this),
-                width: 320,
-                height: 200,
-                top: (size.height-200)/2,
-                left: (size.width-320)/2,
+                imageBaseUrl: this.imageBaseUrl,
+                width: 350,
+                height: 250,
+                resizeable: true,
+                top: (size.height-250)/2,
+                left: (size.width-350)/2,
                 buttons: ['generate', 'cancel'],
                 handler: this.handler.bind(this)
             };
@@ -116,20 +119,18 @@
         }
     },
     
-    contentLoaded: function() {
-        //    debugger;
-        //alert(this.dialog.id);
-        this.dialog.registerIds(['dialogPrintShowtitle', 
+    contentLoaded: function(dialog) {
+        dialog.registerIds(['dialogPrintShowtitle', 
                                  'dialogPrintTitle',
                                  'dialogPrintShowlegend',
-                                 'dialogPrintShowNorthArrow'], this.dialog.content);
-        this.dialog.getObj('dialogPrintShowtitle').checked = this.showTitle;
-        this.dialog.getObj('dialogPrintTitle').value = this.pageTitle;
-        this.dialog.getObj('dialogPrintTitle').disabled = !this.showTitle;
-        this.dialog.getObj('dialogPrintShowlegend').checked = this.showLegend;
-        this.dialog.getObj('dialogPrintShowNorthArrow').checked = this.showNorthArrow;
+                                 'dialogPrintShowNorthArrow'], dialog.content);
+        dialog.getObj('dialogPrintShowtitle').checked = this.showTitle;
+        dialog.getObj('dialogPrintTitle').value = this.pageTitle;
+        dialog.getObj('dialogPrintTitle').disabled = !this.showTitle;
+        dialog.getObj('dialogPrintShowlegend').checked = this.showLegend;
+        dialog.getObj('dialogPrintShowNorthArrow').checked = this.showNorthArrow;
         
-        Event.observe(this.dialog.getObj('dialogPrintShowtitle'), 'click', this.controlTitle.bind(this));
+        Event.observe(dialog.getObj('dialogPrintShowtitle'), 'click', this.controlTitle.bind(this));
     },
     
     controlTitle: function() {

Modified: sandbox/aboudreault/widgets/RefreshMap.js
===================================================================
--- sandbox/aboudreault/widgets/RefreshMap.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/RefreshMap.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.RefreshMap
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/RefreshMap.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SaveMap.js
===================================================================
--- sandbox/aboudreault/widgets/SaveMap.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SaveMap.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -29,28 +29,13 @@
  * Save the current map image on the client's computer
  *
  * usage:
- * DWF format support requires a structure like this in the weblayout:
- * scales
- * <Command xsi:type="FusionCommandType">
- *    <Name>SaveDWF</Name>
- *    <Label>Save as DWF</Label>
- *    <Tooltip>Click to save the current map as a DWF document</Tooltip>
- *    <TargetViewer>All</TargetViewer>
- *    <PrintLayout>
- *        <Name>My Layout</Name>
- *        <ResourceId>Library://PrintLayouts/first.PrintLayout</ResourceId>
- *        <Scale>25000</Scale>
- *        <Scale>10000</Scale>
- *    </PrintLayout>
- *    <PrintLayout>
- *        <Name>My Other Layout</Name>
- *        <ResourceId>Library://PrintLayouts/second.PrintLayout</ResourceId>
- *    </PrintLayout>
- *    <Action>SaveMap</Action>
- *    <Format>DWF</Format>
- * </Command>
- *
-
+ * DWF format support requires a structure like this in the application
+ * definition's widget tag extension:
+ *    <Extension>
+ *      <Format></Format>
+ *      <ResourceId></ResourceId>
+ *      <Scale></Scale>
+ *    </Extension>
  * **********************************************************************/
 
 Fusion.Widget.SaveMap = Class.create();
@@ -67,10 +52,17 @@
                        json.Format[0] : 'png';
         
         //for DWF, parse printLayouts and build menu
-        if (this.format == 'DWF' && json.PrintLayout.length) {
-            
-            this.printLayout = json.PrintLayout[0];
-            this.printScale =  this.printLayout.Scale[0];
+        if (this.format == 'DWF') {
+            if (json.ResourceId) {
+                this.printLayout = json.ResourceId[0];
+                if (json.Scale) {
+                    this.printScale =  json.Scale[0];
+                }
+            } else {
+                //TODO: Warning that the widget is improperly configured
+                //because we need  print layout for this to work.
+                //TODO: deactivate the widget?
+            }
         }
 
         this.enable = Fusion.Widget.SaveMap.prototype.enable;
@@ -84,8 +76,7 @@
      * called when the button is clicked by the Fusion.Tool.ButtonBase widget
      * prompts user to save the map.
      */
-    activateTool : function()
-    {
+    activateTool : function() {
         if (!this.iframe) {
             this.iframe = document.createElement('iframe');
             this.iframe.id = 'w';
@@ -95,18 +86,26 @@
         var szLayout = '';
         var szScale = '';
         if (this.format === 'DWF') {
-            szLayout = '&layout=' + this.printLayout;
-            szScale = '&scale=' + this.printScale;
+            if (this.printLayout) {
+                szLayout = '&layout=' + this.printLayout;                
+            } else {
+                //TODO: issue an error?
+                return;
+            }
+            if (this.printScale) {
+                szScale = '&scale=' + this.printScale;
+            }
         }
         //TODO: revisit Fusion.getWebAgentURL
+		var m = this.getMap().aMaps[0];
         if(navigator.appVersion.match(/\bMSIE\b/)) {
             //var url = Fusion.getWebAgentURL() + "OPERATION=GETDYNAMICMAPOVERLAYIMAGE&FORMAT=PNG&VERSION=1.0.0&SESSION=" + this.getMap().getSessionID() + "&MAPNAME=" + this.getMap().getMapName() + "&SEQ=" + Math.random();
             
-            var url = Fusion.fusionURL + '/' + this.getMap().arch + '/' + Fusion.getScriptLanguage() + "/SaveMapFrame." + Fusion.getScriptLanguage() + '?session='+this.getMap().getSessionID() + '&mapname=' + this.getMap().getMapName() + '&format=' + this.format + szLayout;
+            var url = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMapFrame." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout;
             //this.iframe.src = url;
             w = open(url, "Save", 'menubar=no,height=200,width=300');
         } else {
-            var s = Fusion.fusionURL + '/' + this.getMap().arch + '/' + Fusion.getScriptLanguage() + "/SaveMap." + Fusion.getScriptLanguage() + '?session='+this.getMap().getSessionID() + '&mapname=' + this.getMap().getMapName() + '&format=' + this.format + szLayout;
+            var s = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMap." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout;
             //console.log(s);
             
             this.iframe.src = s;

Copied: sandbox/aboudreault/widgets/ScalebarDual (from rev 1352, trunk/widgets/ScalebarDual)

Deleted: sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css
===================================================================
--- trunk/widgets/ScalebarDual/ScalebarDual.css	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,11 +0,0 @@
-.scaleDiv{
-    background-color: #000;
-    border: 1px solid #fff;
-    margin: 1px;
-}
-.scaleLabel{
-    font-size: 9px;
-    padding-left: 2px;
-    line-height: 12px;
-    color: #fff;
-}

Copied: sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css (from rev 1352, trunk/widgets/ScalebarDual/ScalebarDual.css)
===================================================================
--- sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css	                        (rev 0)
+++ sandbox/aboudreault/widgets/ScalebarDual/ScalebarDual.css	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,11 @@
+.scaleDiv{
+    background-color: #000;
+    border: 1px solid #fff;
+    margin: 1px;
+}
+.scaleLabel{
+    font-size: 9px;
+    padding-left: 2px;
+    line-height: 12px;
+    color: #fff;
+}

Copied: sandbox/aboudreault/widgets/ScalebarDual.js (from rev 1352, trunk/widgets/ScalebarDual.js)
===================================================================
--- sandbox/aboudreault/widgets/ScalebarDual.js	                        (rev 0)
+++ sandbox/aboudreault/widgets/ScalebarDual.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -0,0 +1,157 @@
+/**
+ * Fusion.Widget.ScalebarDual
+ *
+ * $Id$
+ *
+ * Copyright (c) 2007, DM Solutions Group Inc.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+ /********************************************************************
+ * Class: Fusion.Widget.ScalebarDual
+ *
+ * A dynamically generated cartographic scalebar that looks like the Google scalebar
+ *
+ * **********************************************************************/
+
+Fusion.Widget.ScalebarDual = Class.create();
+Fusion.Widget.ScalebarDual.prototype = {
+    nominalSize: 100,
+    initialize : function(widgetTag) {
+        //console.log('Scalebar.initialize');
+        Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+
+        var json = widgetTag.extension;
+
+        this.content = $(this.getName());
+
+        var scaleDiv = document.createElement('div');
+        Element.addClassName(scaleDiv, 'scaleDiv');
+        Element.addClassName(scaleDiv, 'scaleMetric');
+        this.content.appendChild(scaleDiv);
+
+        this.metricDiv = document.createElement('div');
+        Element.addClassName(this.metricDiv, 'scaleLabel');
+        scaleDiv.appendChild(this.metricDiv);
+
+        scaleDiv = document.createElement('div');
+        Element.addClassName(scaleDiv, 'scaleDiv');
+        Element.addClassName(scaleDiv, 'scaleImperial');
+        this.content.appendChild(scaleDiv);
+
+        this.imperialDiv = document.createElement('div');
+        Element.addClassName(this.imperialDiv, 'scaleLabel');
+        scaleDiv.appendChild(this.imperialDiv);
+
+        Element.addClassName(this.domObj, 'dualScalebar');
+
+        this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.extentsChangedCB.bind(this));
+        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.extentsChangedCB.bind(this));
+
+        Fusion.addWidgetStyleSheet(widgetTag.location + '/ScalebarDual/ScalebarDual.css');
+
+    },
+
+    extentsChangedCB : function() {
+      var maxWidth = this.content.getWidth();
+
+      //TODO: support projected data
+      var map = this.getMap();
+      var oExtent = map.getCurrentExtents();
+      var res = map.getResolution();
+
+      var kmPerPixel;
+      var units = map.getUnits()
+      if (units == 'degrees' || units == 'dd' ) {   //TODO: add case for units='ft'
+        var cp = oExtent.getCenterLonLat();
+        if (Math.abs(cp.lat) > 89.9) return;
+
+        var ddPerPixel = res;
+        var metersPerDD = 110570;
+        //adjust for latitude
+        var kmPerDD = 110.570 * Math.cos(cp.lat*Math.PI/180);
+        kmPerPixel = kmPerDD * ddPerPixel;
+      } else {
+        kmPerPixel = res/1000.0;
+      }
+      var miPerPixel = kmPerPixel * 0.621371192;
+      var ftPerPixel = kmPerPixel * 3280.8399;
+      var kmBarLength = 0; //pixels
+      var miBarLength = 0;
+      var km = 0;
+      var mi = 0;
+      var ft = 0;
+      var kmDone = miDone = false;
+      while(!kmDone && !miDone) {
+          if (kmBarLength < this.nominalSize) {
+              if (km < 1)
+                  km = (km * 10  + 1)/10 ;
+              else if (km < 10)
+                  km = km + 1;
+              else if (km < 100)
+                  km = km + 10;
+              else if (km < 1000)
+                  km = km + 100;
+              else
+                  km = km + 1000;
+          } else {
+            kmDone = true;
+          }
+          if (miBarLength < this.nominalSize) {
+              if (mi < 1)
+                  mi = (mi * 10  + 1)/10 ;
+              else if (mi < 10)
+                  mi = mi + 1;
+              else if (mi < 100)
+                  mi = mi + 10;
+              else if (mi < 1000)
+                  mi = mi + 100;
+              else
+                  mi = mi + 1000;
+          } else {
+            miDone = true;
+          }
+
+          kmBarLength = km / kmPerPixel;
+          miBarLength = mi / miPerPixel;
+      }
+      //for small values, convert to feet and round
+      if (mi < 0.4) {
+          ft = (Math.floor(mi * 52.8) * 100);
+          miBarLength = ft / ftPerPixel;
+      }
+
+      var sbMax = Math.max(kmBarLength, miBarLength) + 2;
+      this.content.style.width = Math.round(sbMax) + 'px';
+      //(document.getElementById(this.id)).style.width = sbMax + 'px';
+      this.metricDiv.parentNode.style.width = Math.round(kmBarLength - 0) + "px";  //0 was 24 why?
+      //for small values, convert units
+      if (km <= 0.5) {
+          this.metricDiv.innerHTML = km * 1000 + " m";
+      }else{
+          this.metricDiv.innerHTML = km + " km";
+      }
+      this.imperialDiv.style.width = Math.round(miBarLength - 0) + "px";  //0 was 24 why?
+      if (mi < 0.4) {
+          this.imperialDiv.innerHTML = ft + " ft";
+      }else{
+          this.imperialDiv.innerHTML = mi + " mi";
+      }
+  }
+};

Modified: sandbox/aboudreault/widgets/Search/ErrorPage.templ
===================================================================
--- sandbox/aboudreault/widgets/Search/ErrorPage.templ	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Search/ErrorPage.templ	2008-03-31 14:35:37 UTC (rev 1353)
@@ -31,15 +31,18 @@
 
 function InitDocument()
 {
-    GetParent().Refresh();
+    var map = GetParent().Fusion.getMapByName(mapName);
+    map.reloadMap();
 }
 
 function Back()
 {
-    if(popup)
-        self.close();
-    else
-        GetParent().GotoHomePage();
+    if (popup) {
+        history.back();
+    } else {
+        var TaskPaneId=this.frameElement.taskPaneId;
+        GetParent().Fusion.getWidgetById(TaskPaneId).goHome();  
+    }
 }
 
 function GetParent()


Property changes on: sandbox/aboudreault/widgets/Search/ErrorPage.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Search/Search.php
===================================================================
--- sandbox/aboudreault/widgets/Search/Search.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Search/Search.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * Search
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/Search/Search.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Search/Search.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Search/SearchPrompt.php
===================================================================
--- sandbox/aboudreault/widgets/Search/SearchPrompt.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Search/SearchPrompt.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * SearchPrompt
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/Search/SearchPrompt.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Search/SearchPrompt.templ
===================================================================
--- sandbox/aboudreault/widgets/Search/SearchPrompt.templ	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Search/SearchPrompt.templ	2008-03-31 14:35:37 UTC (rev 1353)
@@ -49,7 +49,7 @@
     var widget = GetParent().Fusion.getWidgetById(widgetId);
     resultColumns = widget.resultColumns;
 
-    document.getElementById('title').innerHTML = widget.sName;  //TODO use a better property than this
+    document.getElementById('title').innerHTML = widget.title;  //TODO use a better property than this
     document.getElementById('prompt').innerHTML = widget.prompt;  //TODO use a better property than this
     document.getElementById('target').value = widget.sTarget;  //TODO use a better property than this
     document.getElementById('filter').value = widget.filter;  //TODO use a better property than this


Property changes on: sandbox/aboudreault/widgets/Search/SearchPrompt.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/Search/Viewer.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Search.js
===================================================================
--- sandbox/aboudreault/widgets/Search.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Search.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.Search
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -50,7 +50,7 @@
         this.filter = json.Filter ? json.Filter[0] : "";
         this.limit = json.MatchLimit ? json.MatchLimit[0] : 100;
         this.resultColumns = json.ResultColumns ? json.ResultColumns[0].Column : [];
-
+        this.title = json.Title ? json.Title[0] : widgetTag.label;
     },
 
     execute : function() {


Property changes on: sandbox/aboudreault/widgets/Search.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Select.js
===================================================================
--- sandbox/aboudreault/widgets/Select.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Select.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -36,7 +36,6 @@
     nTolerance : 3,     //default pixel tolernace for a point click
     bActiveOnly: false, //only select feature(s) on the active layer?
     maxFeatures: 0,     //deafult of 0 selects all features (i.e. no maximum)
-    keyModifiers: 0,    //set during event handling to indicate modifier key states
     
     initialize : function(widgetTag) {
         //console.log('Select.initialize');
@@ -68,9 +67,9 @@
         }
         
         this.map = this.getMap().oMapOL;
-        this.handler = new OpenLayers.Handler.Box(this,{done: this.execute});
-        this.handler.dragHandler.up = this.setModifiers.bind(this);
-        this.handler.dragHandler.down = this.clearModifiers.bind(this);
+        this.handler = new OpenLayers.Handler.Box(this,{done: this.execute},{keyMask:0});
+        this.shiftHandler = new OpenLayers.Handler.Box(this,{done: this.extend},
+                                        {keyMask:OpenLayers.Handler.MOD_SHIFT});
     },
     
     enable: function() {
@@ -100,6 +99,7 @@
        */
     activate : function() {
         this.handler.activate();
+        this.shiftHandler.activate();
         this.getMap().setCursor(this.asCursor);
         /*icon button*/
         this._oButton.activateTool();
@@ -112,6 +112,7 @@
        **/
     deactivate : function() {
         this.handler.deactivate();
+        this.shiftHandler.deactivate();
         this.getMap().setCursor('auto');
         /*icon button*/
         this._oButton.deactivateTool();
@@ -125,10 +126,10 @@
         *   position will be either an instance of OpenLayers.Bounds when the mouse has
         *   moved, or an OpenLayers.Pixel for click without dragging on the map
         **/
-    execute : function(position) {
+    execute : function(position, extend) {
         //ctrl click is used to launch a URL defined on the feature. See ClickCTRL widget
         if (this.keyModifiers & OpenLayers.Handler.MOD_CTRL) {
-          return;
+          //return;
         }
         
         var nRight, nTop;
@@ -169,7 +170,7 @@
             }
         }
         
-        if (this.keyModifiers & OpenLayers.Handler.MOD_SHIFT) {
+        if (extend) {
             options.extendSelection = true;
         }
         
@@ -177,6 +178,16 @@
     },
 
     /**
+        * handler for extending the selection when the shift key is pressed
+        *
+        * Parameters:
+        * evt - the OpenLayers.Event object that is being responded to
+        */
+    extend: function(position) {
+        this.execute(position, true);
+    },
+    
+    /**
         * calculate the keyboard modifier mask for this event 
         *
         * Parameters:

Modified: sandbox/aboudreault/widgets/SelectRadius.js
===================================================================
--- sandbox/aboudreault/widgets/SelectRadius.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectRadius.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -104,8 +104,9 @@
         this._oButton.activateTool();
         if (!this.circle) {
             this.circle = new Fusion.Tool.Canvas.Circle(this.getMap());
-            this.circle.setCenter(0);
         }
+        /*map units for tool tip*/
+        this.units = this.getMap().getAllMaps()[0].units;
     },
 
     /**
@@ -131,10 +132,12 @@
         //console.log('SelectRadius.mouseDown');
         if (Event.isLeftClick(e)) {
             var p = this.getMap().getEventPosition(e);
-
+            var point = this.getMap().pixToGeo(p.x, p.y);
+            var radius = this.getMap().pixToGeoMeasure(this.defaultRadius);
+            
             if (!this.isDigitizing) {
-                this.circle.setCenter(p.x, p.y);
-                this.circle.setRadius(this.defaultRadius);
+                this.circle.setCenter(point.x, point.y);
+                this.circle.setRadius(radius);
                 this.clearContext();
                 this.circle.draw(this.context);     
                 this.isDigitizing = true;
@@ -146,7 +149,10 @@
             this.radiusTip.style.top = (p.y - size.height*2) + 'px';
             this.radiusTip.style.left = p.x + 'px';
             var r = this.getMap().pixToGeoMeasure(this.circle.radius);
-            this.radiusTip.innerHTML = r;
+            if (this.units == 'm' || this.units == 'ft') {
+                r = Math.round(r * 100)/100;
+            }
+            this.radiusTip.innerHTML = r + this.units;
         }
     },
 
@@ -163,11 +169,13 @@
             return;
         }
     
-        var p = this.getMap().getEventPosition(e);
+        var map = this.getMap();
+        var p = map.getEventPosition(e);
+        var point = map.pixToGeo(p.x, p.y);
         var center = this.circle.center;
         
-        var radius = Math.sqrt(Math.pow(center.x-p.x,2) + Math.pow(center.y-p.y,2));
-        if (radius > this.nTolerance) {
+        var radius = Math.sqrt(Math.pow(center.x-point.x,2) + Math.pow(center.y-point.y,2));
+        if (map.geoToPixMeasure(radius) > this.nTolerance) {
             this.circle.setRadius(radius);
         }
         this.clearContext();
@@ -178,8 +186,11 @@
             var size = Element.getDimensions(this.radiusTip);
             this.radiusTip.style.top = (p.y - size.height*2) + 'px';
             this.radiusTip.style.left = p.x + 'px';
-            var r = this.getMap().pixToGeoMeasure(this.circle.radius);
-            this.radiusTip.innerHTML = r;
+            var r = map.pixToGeoMeasure(this.circle.radius);
+            if (this.units == 'm' || this.units == 'ft') {
+                r = Math.round(r * 100)/100;
+            }
+            this.radiusTip.innerHTML = r + this.units;
         }
         
     },
@@ -190,8 +201,8 @@
             //this.circle.draw(this.context);
             this.clearContext();
             this.isDigitizing = false;
-            var center = this.getMap().pixToGeo(this.circle.center.x, this.circle.center.y);
-            var radius = this.getMap().pixToGeoMeasure(this.circle.radius);
+            var center = this.circle.center;
+            var radius = this.circle.radius;
             this.execute(center, radius);
         }
         
@@ -228,7 +239,7 @@
         
         var options = {};
         options.geometry = wkt;
-        options.selectionType = "inside";
+        options.selectionType = this.selectionType;
 
         if (this.bActiveOnly) {
             var layer = this.getMap().getActiveLayer();

Modified: sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * SelectWithin
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -26,6 +26,8 @@
 
   $fusionMGpath = '../../MapGuide/php/';
   include $fusionMGpath . 'Common.php';
+  include $fusionMGpath . 'Utilities.php';
+  include('../../common/php/Utilities.php');
 
   $mapName = "";
   $sessionId = "";
@@ -41,14 +43,23 @@
     //load the map runtime state
     $map = new MgMap();
     $map->Open($resourceService, $mapName);
+    
+    //object to hold response
+    $result = NULL;
+    $result->hasSelection = false;
 
+    /*holds selection array*/
+    $properties = NULL;
+    $properties->layers = array();
+
     $layers = explode(",", $layers);
     if (count($layers) > 0) {
 
       $layerNames = new MgStringCollection();
-      for ($i = 0; $i < count($layers); $i++)
+      for ($i = 0; $i < count($layers); $i++) {
         $layerNames->Add($layers[$i]);
-
+      }
+      
       // create a multi-polygon or a multi-geometry containing the input selected features
       $inputGeom = MultiGeometryFromSelection($featureSrvc, $resourceService, $map, $mapName);
       if ($inputGeom) {
@@ -57,13 +68,64 @@
         if ($fi) {
           $resultSel = $fi->GetSelection();
           if( $resultSel) {
-            //return XML
-            header("Content-type: text/xml");
-            echo $resultSel->ToXml();
+            $resultSel->Save($resourceService, $mapName);
+            
+            //this needs to be re-opened for some reason
+            $resultSel = new MgSelection($map);
+            $resultSel->Open($resourceService, $mapName);
+	  
+            $layers = $resultSel->GetLayers();
+            if ($layers && $layers->GetCount() >= 0) {
+              $result->hasSelection = true;
+              
+              //set the extents for the selection object
+              $oExtents = $resultSel->GetExtents($featureSrvc);
+              if ($oExtents) {
+                $oMin = $oExtents->GetLowerLeftCoordinate();
+                $oMax = $oExtents->GetUpperRightCoordinate();
+                $result->extents = NULL;
+                $result->extents->minx = $oMin->GetX();
+                $result->extents->miny = $oMin->GetY();
+                $result->extents->maxx = $oMax->GetX();
+                $result->extents->maxy = $oMax->GetY();
+
+                /*keep the full extents of the selection when saving the selection in the session*/
+                $properties->extents = NULL;
+                $properties->extents->minx = $oMin->GetX();
+                $properties->extents->miny = $oMin->GetY();
+                $properties->extents->maxx = $oMax->GetX();
+                $properties->extents->maxy = $oMax->GetY();
+              }
+              
+              //get properties for individual features
+              $result->layers = array();
+              for ($i=0; $i<$layers->GetCount(); $i++) {
+                $layer = $layers->GetItem($i);
+                $layerName = $layer->GetName();
+                $layerClassName = $layer->GetFeatureClassName();
+                $options = new MgFeatureQueryOptions();
+                $options->SetFilter($resultSel->GenerateFilter($layer, $layerClassName));
+                $resourceId = new MgResourceIdentifier($layer->GetFeatureSourceId());
+                $featureReader = $featureSrvc->SelectFeatures($resourceId, $layerClassName, $options);
+                $properties = BuildSelectionArray($featureReader, $layerName, $properties, false, NULL, false, $layer);
+                
+                array_push($result->layers, $layerName);
+                array_push($properties->layers, $layerName);
+                $count = $resultSel->GetSelectedFeaturesCount($layer, $layerClassName);
+                $result->$layerName->featureCount = $count;
+              }
+
+              /*save selection in the session*/
+              $_SESSION['selection_array'] = $properties; 
+            }
           }
         }
       }
     }
+    
+    header('Content-type: text/x-json');
+    header('X-JSON: true');
+    echo var2json($result);
   } catch(MgException $e) {
     echo "\nException: " . $e->GetDetails();
     return;


Property changes on: sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.php
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.php	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.php	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,7 +2,7 @@
 /**
  * SelectWithinPanel
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.php
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ	2008-03-31 14:35:37 UTC (rev 1353)
@@ -43,8 +43,9 @@
 
 function InitDocument()
 {
-    if(!popup)
+    if(!popup) {
         document.onmousedown = OnMouseDown;
+    }
     var w = msie? document.body.clientWidth: window.innerWidth - 20;
     document.getElementById("layers").style.width = (w > 200? 200: w) + "px";
     FillLayerList();
@@ -59,7 +60,7 @@
 function ExecuteCommand()
 {
     //build the destination layer set
-    layerSet = "";
+    var layerSet = "";
     var list = document.getElementById("layers");
     var layerNames = document.getElementById("layerNames");
     var count = list.options.length;
@@ -69,32 +70,24 @@
         var opt = list.options[i];
         if(opt.selected)
         {
-            if(selIndex > 0)
-                layerSet = "," + layerSet;
+            if(selIndex > 0) {
+                layerSet += ",";
+            }
             layerSet += layerNames.options[i].text;
             selIndex ++;
         }
     }
-    if(layerSet == "")
+    if(layerSet == "") {
         return;
+    }
 
+    var mapWidget = GetParent().Fusion.getMapByName(mapName);
+    var map = mapWidget.aMaps[0];
     var params = "mapname=" + encodeURIComponent(mapName) + "&session=" + sessionId + "&layers=" + encodeURIComponent(layerSet);
-    var options = {onSuccess: selected, onFailure: selectedError, parameters:params};
+    var options = {onSuccess: map.processQueryResults.bind(map), onFailure: selectedError, parameters:params};
     GetParent().Fusion.ajaxRequest(webAgent, options);
 }
 
-function selected(r) {
-    var map = GetParent().Fusion.getMapByName(mapName);
-    map.setSelection(r.responseText, true, false);
-
-    if (popup) {
-      window.close();
-    } else {
-      var TaskPaneId=this.frameElement.taskPaneId;
-      GetParent().Fusion.getWidgetById(TaskPaneId).goHome();  
-    }
-}
-
 function selectedError(r) {
     alert(r.responseText);
 }
@@ -139,10 +132,11 @@
 
 function GetParent()
 {
-    if(popup)
+    if(popup) {
         return opener;
-    else
+    } else {
         return parent.parent;
+    }
 }
 
 </script>


Property changes on: sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/SelectWithin/Viewer.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SelectWithin.js
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectWithin.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.SelectWithin
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -36,7 +36,7 @@
 
     initialize : function(widgetTag) {
         //console.log('SelectWithin.initialize');
-        Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+        Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
         Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
 
         var json = widgetTag.extension;


Property changes on: sandbox/aboudreault/widgets/SelectWithin.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SelectionInfo.js
===================================================================
--- sandbox/aboudreault/widgets/SelectionInfo.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectionInfo.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.SelectionInfo
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -45,7 +45,7 @@
 
 Fusion.Widget.SelectionInfo = Class.create();
 Fusion.Widget.SelectionInfo.prototype = {
-    defaultTemplate: '{features} features selected on {layers} layers',
+    defaultTemplate: 'selectionInfo',
     domSpan: null,
     
     initialize : function(widgetTag) {
@@ -56,11 +56,11 @@
         var json = widgetTag.extension;
         
         this.emptyText = json.EmptyText ? json.EmptyText[0] : this.domObj.innerHTML;
-        this.template = json.Template ? json.Template[0] : this.defaultTemplate;
+        this.template = json.Template ? json.Template[0] : null;
         
         this.domSpan = document.createElement('span');
         this.domSpan.className = 'spanSelectionInfo';
-        this.domSpan.innerHTML = this.emptyText;
+        this.domSpan.innerHTML = OpenLayers.String.translate(this.emptyText);
         this.domObj.innerHTML = '';
         this.domObj.appendChild(this.domSpan);
 
@@ -76,9 +76,13 @@
             var layers = map.getSelectedLayers();
             var nLayers = layers.length;
             var nFeatures = map.getSelectedFeatureCount();
-            this.domSpan.innerHTML = this.template.replace('{layers}',nLayers).replace('{features}',nFeatures);
+            if (this.template) {
+              this.domSpan.innerHTML = this.template.replace('{0}',nFeatures).replace('{1}',nLayers);
+            } else {
+              this.domSpan.innerHTML = OpenLayers.String.translate(this.defaultTemplate,nFeatures,nLayers);
+            }
         } else {
-            this.domSpan.innerHTML = this.emptyText;
+            this.domSpan.innerHTML = OpenLayers.String.translate(this.emptyText);
         }
     }
 };


Property changes on: sandbox/aboudreault/widgets/SelectionInfo.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/SelectionPanel/SelectionPanel.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/SelectionPanel.js
===================================================================
--- sandbox/aboudreault/widgets/SelectionPanel.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/SelectionPanel.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.SelectionPanel
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -77,7 +77,7 @@
         this.featureList.options.length = 0;
         this.oSelection = null;
         Element.addClassName(this.featureDiv, 'noSelection');
-        this.featureDiv.innerHTML = 'No Selection';
+        this.featureDiv.innerHTML = OpenLayers.String.translate('noSelection');
     },
     
     updateSelection: function() {
@@ -147,10 +147,10 @@
         var thead = document.createElement('thead');
         var tr = document.createElement('tr');
         var th = document.createElement('th');
-        th.innerHTML = 'Attribute';
+        th.innerHTML = OpenLayers.String.translate('attribute');
         tr.appendChild(th);
         var th = document.createElement('th');
-        th.innerHTML = 'Value';
+        th.innerHTML = OpenLayers.String.translate('value');
         tr.appendChild(th);
         thead.appendChild(tr);
         table.appendChild(thead);


Property changes on: sandbox/aboudreault/widgets/SelectionPanel.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/TaskPane/TaskPane.css
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/TaskPane/TaskPane.html
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/TaskPane.js
===================================================================
--- sandbox/aboudreault/widgets/TaskPane.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/TaskPane.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.TaskPane
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -45,10 +45,10 @@
         Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
         
         this.aExecutedTasks = [];
-        this.defHomeIcon = 'images/icon_home.gif';
-        this.defPrevTaskIcon = 'images/icon_back.gif';
-        this.defNextTaskIcon = 'images/icon_forward.gif';
-        this.defTaskListIcon = 'images/icon_tasks.gif';
+        this.defHomeIcon = 'images/icon_home.png';
+        this.defPrevTaskIcon = 'images/icon_back.png';
+        this.defNextTaskIcon = 'images/icon_forward.png';
+        this.defTaskListIcon = 'images/icon_tasks.png';
         this.defInitialTask = widgetTag.location + 'TaskPane/TaskPane.html';
               
         var json = widgetTag.extension;
@@ -73,7 +73,7 @@
         this.toolbar.add(new Jx.Button(this.homeAction, 
             {
             image: this.defHomeIcon, 
-            tooltip: 'return to the task pane home'
+            tooltip: OpenLayers.String.translate('taskHome')
             }
         ));
 
@@ -81,7 +81,7 @@
         this.toolbar.add(new Jx.Button(this.prevAction, 
             {
             image: this.defPrevTaskIcon, 
-            tooltip: 'go to previous task executed'
+            tooltip: OpenLayers.String.translate('prevTask')
             }
         ));
 
@@ -89,11 +89,13 @@
         this.toolbar.add(new Jx.Button(this.nextAction, 
             {
             image: this.defNextTaskIcon, 
-            tooltip: 'go to next task executed'
+            tooltip: OpenLayers.String.translate('nextTask')
             }
         ));
 
-        this.taskMenu = new Jx.Menu({image: this.defTaskListIcon, label: 'Task List', right:0});
+        this.taskMenu = new Jx.Menu({image: this.defTaskListIcon, 
+                    label: OpenLayers.String.translate('taskList'), 
+                    right:0});
         Element.addClassName(this.taskMenu.domObj, 'taskMenu');
         Element.addClassName(this.taskMenu.button.domObj, 'jxButtonContentLeft');
         this.toolbar.add(this.taskMenu);
@@ -106,7 +108,7 @@
         this.iframe.setAttribute('frameborder', 0);
         this.iframe.style.border = '0px solid #fff';
         this.oTaskPane = new Jx.Panel({toolbar: tmpDiv, 
-                      label: 'Task Pane', 
+                      label: OpenLayers.String.translate('taskPane'), 
                       content: this.iframe
         });
         Element.addClassName(this.domObj, 'taskPanePanel');
@@ -116,9 +118,9 @@
         //we need to trigger an initial resize after the panel
         //is added to the DOM
         this.oTaskPane.domObj.resize();
-        this.setContent(this.initialTask);
         
         Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, this.setTaskMenu.bind(this));
+        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setContent.bind(this,this.initialTask));
     },
     
     updateButtons: function() {
@@ -149,6 +151,20 @@
         if (this.nCurrentTask < this.aExecutedTasks.length) {
             this.aExecutedTasks.splice(this.nCurrentTask, this.aExecutedTasks.length - this.nCurrentTask);
         }
+        
+        //add in default Fusion parameters to the URL
+        var map = this.getMap();
+        var params = [];
+        params.push('LOCALE='+Fusion.locale);
+        params.push('SESSION='+map.getSessionID());
+        params.push('MAPNAME='+map.getMapName());
+        if (url.indexOf('?') < 0) {
+            url += '?';
+        } else if (url.slice(-1) != '&') {
+            url += '&';
+        }
+        url += params.join('&');
+        
         this.aExecutedTasks.push(url);
         ++this.nCurrentTask;
         this.iframe.src = url;


Property changes on: sandbox/aboudreault/widgets/TaskPane.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/ViewOptions.js
===================================================================
--- sandbox/aboudreault/widgets/ViewOptions.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/ViewOptions.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.ViewOptions
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,9 +34,9 @@
 {
     displayUnits: false,
     options : {
-        'Imperial': 'Miles', 
-        'Metric': 'Meters',
-        'Degrees': 'Degrees'
+        'imperial': 'Miles', 
+        'metric': 'Meters',
+        'deg': 'Degrees'
     },
 
     initialize : function(widgetTag) {
@@ -51,14 +51,12 @@
         
         for (var key in this.options) {
           var action = new Jx.Action(this.setViewOptions.bind(this, this.options[key]));
-          var menuItem = new Jx.MenuItem(action, {label: key} );
+          var menuItem = new Jx.MenuItem(action, {label: OpenLayers.String.translate(key)} );
           this.oMenu.add(menuItem);
         }
 
         this.displayUnits = json.DisplayUnits ? json.DisplayUnits[0] : false;
-        if (!this.displayUnits) {
-            this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setMapUnits.bind(this));
-        }
+        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setMapUnits.bind(this));
     },
     
     //action to perform when the button is clicked
@@ -67,7 +65,8 @@
     },
 
     setMapUnits: function() {
-      this.setViewOptions(this.getMap().getUnits());
+      var units = this.displayUnits ? this.displayUnits : this.getMap().getUnits();
+      this.setViewOptions(units);
     },
     
     setViewOptions: function(data) {
@@ -83,4 +82,4 @@
         }
       }
     }
-};
\ No newline at end of file
+};


Property changes on: sandbox/aboudreault/widgets/ViewOptions.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/ViewSize.js
===================================================================
--- sandbox/aboudreault/widgets/ViewSize.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/ViewSize.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 /**
  * Fusion.Widget.ViewSize
  *
- * $Id: $
+ * $Id$
  *
  * Copyright (c) 2007, DM Solutions Group Inc.
  * Permission is hereby granted, free of charge, to any person obtaining a


Property changes on: sandbox/aboudreault/widgets/ViewSize.js
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/Zoom.js
===================================================================
--- sandbox/aboudreault/widgets/Zoom.js	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/Zoom.js	2008-03-31 14:35:37 UTC (rev 1353)
@@ -36,7 +36,6 @@
     nTolerance : 5,
     nFactor : 2,
     zoomIn: true,
-    keyModifiers: 0,    //set during event handling to indicate modifier key states
     
     initialize : function(widgetTag)
     {
@@ -55,9 +54,9 @@
         this.keypressWatcher = this.keypressHandler.bind(this);
         
         this.map = this.getMap().oMapOL;
-        this.handler = new OpenLayers.Handler.Box(this, {done: this.execute});
-        this.handler.dragHandler.up = this.setModifiers.bind(this);
-        this.handler.dragHandler.down = this.clearModifiers.bind(this);
+        this.handler = new OpenLayers.Handler.Box(this, {done: this.execute}, {keyMask:0});
+        this.shiftHandler = new OpenLayers.Handler.Box(this, {done: this.altZoom}, 
+                                        {keyMask:OpenLayers.Handler.MOD_SHIFT});
     },
 
    /**
@@ -80,6 +79,7 @@
     {
         //console.log('Zoom.activate');
         this.handler.activate();
+        this.shiftHandler.activate();
         /*cursor*/
         if (this.zoomIn) {
             this.getMap().setCursor(this.zoomInCursor);
@@ -99,6 +99,7 @@
     {
         //console.log('Zoom.deactivate');
         this.handler.deactivate();
+        this.shiftHandler.deactivate();
         this.getMap().setCursor('auto');
         /*icon button*/
         this._oButton.deactivateTool();
@@ -112,11 +113,11 @@
      * Parameters:
      * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
      */
-    execute: function (position) {
+    execute: function (position, altZoom) {
         /* if the last event had a shift modifier, swap the sense of this
                 tool - zoom in becomes out and zoom out becomes in */
         var zoomIn = this.zoomIn;
-        if (this.keyModifiers & OpenLayers.Handler.MOD_SHIFT) {
+        if (altZoom) {
             zoomIn = !zoomIn;
         }
         if (position instanceof OpenLayers.Bounds) {
@@ -151,29 +152,16 @@
     },
 
     /**
-        * calculate the keyboard modifier mask for this event 
+        * handler for zooming when the shift key is pressed.  This changes it from in to out or vice versa
         *
         * Parameters:
-        * evt - the OpenLayers.Event object that is being responded to
+        * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
         */
-    setModifiers: function(evt) {
-        this.keyModifiers =
-            (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
-            (evt.ctrlKey  ? OpenLayers.Handler.MOD_CTRL  : 0) |
-            (evt.altKey   ? OpenLayers.Handler.MOD_ALT   : 0);
+    altZoom: function(position) {
+        this.execute(position, true);
     },
     
     /**
-        * clears the keyboard modifier mask for this event 
-        *
-        * Parameters:
-        * evt - the OpenLayers.Event object that is being responded to
-        */
-    clearModifiers: function(evt) {
-      this.keyModifiers = 0;
-    },
-
-    /**
         * allows run-time setting of widget parameters 
         *
         * Parameters:


Property changes on: sandbox/aboudreault/widgets/scalebar/fancy-bar-alt.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision


Property changes on: sandbox/aboudreault/widgets/scalebar/fancy-bar.gif
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/WidgetInfoTemplate.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/WidgetInfoTemplate.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/WidgetInfoTemplate.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -3,6 +3,7 @@
 <ApplicationDefinitionWidgetInfoSet xsi:noNamespaceSchemaLocation="ApplicationDefinitionInfo-1.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <WidgetInfo>
   <Type>String</Type>
+  <LocalizedType>String</LocalizedType>
   <Description>String</Description>
   <Location>String</Location>
   <Label>String</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/WidgetInfoTemplate.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/about.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/about.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/about.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,13 +1,12 @@
 <WidgetInfo>
   <Type>About</Type>
-  <Description>This widget displays information about the application including 
-    the license and copyright information retrieved from a URL set as a parameter.
-  </Description>
+  <LocalizedType>About</LocalizedType>
+  <Description>This widget displays information about the application including the license and copyright information retrieved from a URL set as a parameter</Description>
   <Location></Location>
   <Label>About</Label>
   <Tooltip>Click to show information about this application</Tooltip>
   <StatusText></StatusText>
-  <ImageUrl></ImageUrl>
+  <ImageUrl>images/icons/about.png</ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/about.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/activityindicator.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/activityindicator.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/activityindicator.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,10 +1,7 @@
 <WidgetInfo>
   <Type>ActivityIndicator</Type>
-  <Description>AcitivityIndicator is a widget that shows or hides its DOM element
-    based on whether the map widget is busy or not.  The map widget
-    becomes busy when loading maps, reloading maps or redrawing
-    layers.
-  </Description>
+  <LocalizedType>Activity Indicator</LocalizedType>
+  <Description>AcitivityIndicator is a widget that shows or hides its DOM element based on whether the map widget is busy or not. The map widget becomes busy when loading maps, reloading maps or redrawing layers.</Description>
   <Location></Location>
   <Label>Activity Indicator</Label>
   <Tooltip>The application is busy</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/activityindicator.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/buffer.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/buffer.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/buffer.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -2,10 +2,8 @@
 wil be merged in the future -->
 <WidgetInfo>
     <Type>Buffer</Type>
-    <Description>This widget will perform a buffering operation on selected 
-      features in the Map.  Either a popup window or the task pane will be used
-      to gather user input, depending on the setting of the Target parameter.
-    </Description>
+    <LocalizedType>Buffer</LocalizedType>
+    <Description>This widget will perform a buffering operation on selected features in the Map.  Either a popup window or the task pane will be used to gather user input, depending on the setting of the Target parameter</Description>
     <Label>Create a buffer</Label>
     <Tooltip>Click to create a buffer</Tooltip>
     <ImageUrl>images/icons/buffer.png</ImageUrl>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/buffer.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/bufferpanel.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/bufferpanel.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/bufferpanel.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,9 +1,7 @@
 <WidgetInfo>
     <Type>BufferPanel</Type>
-    <Description>This widget will perform a buffering operation on selected 
-      features in the Map.  Either a popup window or the task pane will be used
-      to gather user input, depending on the setting of the Target parameter.
-    </Description>
+    <LocalizedType>Buffer Panel</LocalizedType>
+    <Description>This widget will perform a buffering operation on selected features in the Map.  Either a popup window or the task pane will be used to gather user input, depending on the setting of the Target parameter</Description>
     <Label>Buffer</Label>
     <Tooltip>Click to create a buffer</Tooltip>
     <ImageUrl>images/icons/buffer.png</ImageUrl>
@@ -11,13 +9,9 @@
     <ContainableBy>Any</ContainableBy>
     <Parameter>
         <Name>Target</Name>
-        <Label>The name of a task pane widget or a popup window</Label>
+        <Label>Target</Label>
         <Type>target</Type>
-        <Description>If this is a TaskPane widget, this widget will set a URL
-        in the TaskPane to gather user input, otherwise it looks for an HTML
-        element with this name, otherwise it will open a popup window to gather 
-        user input.
-        </Description>
+        <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
         <IsMandatory>true</IsMandatory>
         <DefaultValue>TaskPane</DefaultValue>
     </Parameter>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/bufferpanel.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/centerselection.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/centerselection.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/centerselection.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>CenterSelection</Type>
-  <Description>Center the current selection, if any, but maintain the current 
-  scale if possible.  Zoom out if not.
-  </Description>
+  <LocalizedType>Center Selection</LocalizedType>
+  <Description>Center the current selection, if any, but maintain the current scale if possible. Zoom out if not</Description>
   <Location></Location>
   <Label>Center selection</Label>
   <Tooltip>Click to center the map on the current selection</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/centerselection.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/clearselection.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/clearselection.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/clearselection.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>ClearSelection</Type>
+  <LocalizedType>Clear Selection</LocalizedType>
   <Description>Clears the current selection</Description>
   <Label>Clear Selection</Label>
   <Tooltip>Click to clear the current selection</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/clearselection.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/colorpicker.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/colorpicker.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/colorpicker.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>ColorPicker</Type>
+  <LocalizedType>Color Picker</LocalizedType>
   <Description>The user can pick from a palette of web-safe colors or enter a hex value</Description>
   <Location></Location>
   <Label>Color picker</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/colorpicker.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/ctrlclick.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/ctrlclick.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/ctrlclick.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,6 +1,7 @@
 <WidgetInfo>
   <Type>CTRLClick</Type>
-  <Description>Launch a window with a CTRL click  if a URL expression is set on the layer</Description>
+  <LocalizedType>CTRL Click</LocalizedType>
+  <Description>Launch a window with a CTRL click if a URL expression is set on the layer</Description>
   <Location></Location>
   <Label>CTRLClick</Label>
   <Tooltip></Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/ctrlclick.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/cursorposition.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/cursorposition.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/cursorposition.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,10 +1,11 @@
 <WidgetInfo>
   <Type>CursorPosition</Type>
+  <LocalizedType>Cursor Position</LocalizedType>
   <Description>Provides dynamic cursor tracking as it moves over the map</Description>
   <Label>CursorPosition</Label>
   <Tooltip>this will display the cursor position</Tooltip>
   <StandardUi>false</StandardUi>
-  <ContainableBy>Toolbar</ContainableBy>
+  <ContainableBy>Splitterbar</ContainableBy>
   <Parameter>
     <Name>Template</Name>
     <Type>string</Type>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/cursorposition.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/editablescale.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/editablescale.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/editablescale.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,18 +1,17 @@
 <WidgetInfo>
   <Type>EditableScale</Type>
-  <Description>This widget displays the map scale as well as provide for a way 
-  for the user to enter a scale value to display the map at.
-  </Description>
+  <LocalizedType>Editable Scale</LocalizedType>
+  <Description>This widget displays the map scale and provides a way for the user to enter a scale value at which to display the map</Description>
   <Label>Editable Scale</Label>
   <Tooltip>Allows display and entry of map scale</Tooltip>
   <ImageUrl></ImageUrl>
   <StandardUi>false</StandardUi>
-  <ContainableBy>Toolbar</ContainableBy>
+  <ContainableBy>Splitterbar</ContainableBy>
   <Parameter>
     <Name>Precision</Name>
     <Type>integer</Type>
     <Label>Precision</Label>
-    <Description>The precision to display the scale at</Description>
+    <Description>The precision at which to display the scale</Description>
     <DefaultValue>4</DefaultValue>
     <Min>0</Min>
     <Max>15</Max>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/editablescale.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/extenthistory.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/extenthistory.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/extenthistory.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>ExtentHistory</Type>
-  <Description>A widget to navigate forward or backward in the map view 
-  extent history.
-  </Description>
+  <LocalizedType>Extent History</LocalizedType>
+  <Description>A widget to navigate forward or backward in the map view extent history</Description>
   <Label>Go To Extent</Label>
   <ImageUrl>images/icons/view-back.png</ImageUrl>
   <Tooltip>Navigate to the previous extents</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/extenthistory.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/help.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/help.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/help.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Help</Type>
+  <LocalizedType>Help</LocalizedType>
   <Description>Outputs a user help page</Description>
   <Location></Location>
   <Label>Help</Label>
@@ -11,11 +12,7 @@
   <ContainableBy>Any</ContainableBy>
   <Parameter>
     <Name>Target</Name>
-    <Description>location to display the help page.  If the Target is a Task 
-    Pane widget name, help will be displayed there, otherwise if it is a page
-    DOM element, it will display in that element, otherwise it will open a popup
-    window with the target name.
-    </Description>
+    <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
     <Type>String</Type>
     <Label>Target</Label>
     <DefaultValue>HelpWindow</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/help.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/initialmapview.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/initialmapview.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/initialmapview.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>InitialMapView</Type>
+  <LocalizedType>Initial Map View</LocalizedType>
   <Description>A widget that will zoom the map to the full extents</Description>
   <Location></Location>
   <Label>Zoom Extents</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/initialmapview.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/invokescript.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/invokescript.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/invokescript.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,11 +1,12 @@
 <WidgetInfo>
   <Type>InvokeScript</Type>
+  <LocalizedType>Invoke Script</LocalizedType>
   <Description>A widget to execute arbitrary javascript</Description>
   <Location></Location>
   <Label>Invoke script</Label>
   <Tooltip>Click to invoke a javascript method</Tooltip>
   <StatusText></StatusText>
-  <ImageUrl></ImageUrl>
+  <ImageUrl>images/icons/invoke-script.png</ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/invokescript.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/invokeurl.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/invokeurl.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/invokeurl.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,24 +1,18 @@
 <WidgetInfo>
   <Type>InvokeURL</Type>
-  <Description>A widget to call up a URL into the TaskPane, a new window or 
-  HTML element.  The MapName and Session ID are automatically added to the URL,
-  as well as any additional parameters specifed.
-  </Description>
+  <LocalizedType>Invoke URL</LocalizedType>
+  <Description>A widget to call up a URL into the TaskPane, a new window or HTML element. The map name and Session ID are automatically added to the URL, as well as any additional parameters specifed</Description>
   <Location></Location>
   <Label>Invoke URL</Label>
   <Tooltip>Click to execute the URL</Tooltip>
   <StatusText></StatusText>
-  <ImageUrl></ImageUrl>
+  <ImageUrl>images/icons/invoke-url.png</ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>
   <Parameter>
     <Name>Target</Name>
-    <Description>If this is a TaskPane widget, this widget will set a URL
-    in the TaskPane to gather user input, otherwise it looks for an HTML
-    element with this name, otherwise it will open a popup window to gather 
-    user input.
-    </Description>
+    <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
     <Type>String</Type>
     <Label>Target</Label>
     <DefaultValue>InvokeUrlWindow</DefaultValue>
@@ -33,8 +27,7 @@
   </Parameter>
   <Parameter>
     <Name>DisableIfSelectionEmpty</Name>
-    <Description>A flag to indicate if this widget should only be enabled if 
-    there is a selection available on the map</Description>
+    <Description>A flag to indicate if this widget should only be enabled if there is a selection available on the map</Description>
     <Type>boolean</Type>
     <Label>DisableIfSelectionEmpty</Label>
     <DefaultValue>false</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/invokeurl.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/legend.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/legend.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/legend.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>Legend</Type>
-  <Description>A widget that displays a listing of all layers that make up the 
-  map as a tree structure
-  </Description>
+  <LocalizedType>Legend</LocalizedType>
+  <Description>A widget that displays a listing of all layers that make up the map as a tree structure</Description>
   <Location></Location>
   <Label>Legend</Label>
   <Tooltip>Map Legend</Tooltip>
@@ -28,16 +27,32 @@
     <IsMandatory>false</IsMandatory>
   </Parameter>
   <Parameter>
+    <Name>ShowMapFolder</Name>
+    <Description>flag to indicate if the map folder is shown</Description>
+    <Type>boolean</Type>
+    <Label>Show the map folder</Label>
+    <DefaultValue>false</DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
+  <Parameter>
     <Name>LayerRasterIcon</Name>
-    <Description>icon to use for raster layers</Description>
+    <Description>Icon to use for raster layers</Description>
     <Type>String</Type>
     <Label>Raster layer icon</Label>
     <DefaultValue>images/icons/legend-raster.png</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
   <Parameter>
+    <Name>LayerDWFIcon</Name>
+    <Description>Icon to use for DWF layers</Description>
+    <Type>String</Type>
+    <Label>DWF layer icon</Label>
+    <DefaultValue>images/icons/legend-DWF.png</DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
+  <Parameter>
     <Name>LayerThemeIcon</Name>
-    <Description>icon to use for theme layers</Description>
+    <Description>Icon to use for theme layers</Description>
     <Type>String</Type>
     <Label>Theme layer icon</Label>
     <DefaultValue>images/icons/legend-theme.png</DefaultValue>
@@ -45,7 +60,7 @@
   </Parameter>
   <Parameter>
     <Name>DisabledLayerIcon</Name>
-    <Description>icon to use for disabled layers</Description>
+    <Description>Icon to use for disabled layers</Description>
     <Type>String</Type>
     <Label>Disabled layer icon</Label>
     <DefaultValue>images/icons/legend-layer.png</DefaultValue>
@@ -53,7 +68,7 @@
   </Parameter>
   <Parameter>
     <Name>LayerInfoIcon</Name>
-    <Description>icon to use layer information</Description>
+    <Description>Icon to use for layer information</Description>
     <Type>String</Type>
     <Label>Layer information icon</Label>
     <DefaultValue>images/icons/tree_layer_info.png</DefaultValue>
@@ -61,7 +76,7 @@
   </Parameter>
   <Parameter>
     <Name>GroupInfoIcon</Name>
-    <Description>icon to use for layer groups</Description>
+    <Description>Icon to use for layer groups</Description>
     <Type>String</Type>
     <Label>Group information icon</Label>
     <DefaultValue>images/icons/tree_group_info.png</DefaultValue>
@@ -69,7 +84,7 @@
   </Parameter>
   <Parameter>
     <Name>RootFolderIcon</Name>
-    <Description>icon to use for the root folder</Description>
+    <Description>Icon to use for the root folder</Description>
     <Type>String</Type>
     <Label>Map root folder icon</Label>
     <DefaultValue>images/icons/legend-map.png</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/legend.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/linktoview.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/linktoview.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/linktoview.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <WidgetInfo>
   <Type>LinkToView</Type>
-  <Description>A widget displays a hyperlink to the current view of the 
-  application</Description>
+  <LocalizedType>Link to View</LocalizedType>
+  <Description>Displays a hyperlink to the current view of the application</Description>
   <Location></Location>
   <Label>Link to view</Label>
   <Tooltip>A link to the current map view</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/linktoview.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/mapmenu.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/mapmenu.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/mapmenu.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>MapMenu</Type>
-  <Description>A widget that displays a list of maps that can be loaded into 
-  the application
-  </Description>
+  <LocalizedType>Map Menu</LocalizedType>
+  <Description>A widget that displays a list of maps that can be loaded into the application</Description>
   <Location></Location>
   <Label>Maps</Label>
   <Tooltip>Choose a map theme</Tooltip>
@@ -11,4 +10,12 @@
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>
+  <Parameter>
+    <Name>Folder</Name>
+    <Label>MapDefinition root folder</Label>
+    <Type>string</Type>
+    <Description>The hierarchy below this folder will be searched for MapDefinitions to display</Description>
+    <DefaultValue>Library://</DefaultValue>
+    <IsMandatory>0</IsMandatory>
+  </Parameter>
 </WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/mapmenu.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/maptip.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/maptip.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/maptip.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>Maptip</Type>
-  <Description>A widget to display information about features under the mouse 
-  as it hovers over the map
-  </Description>
+  <LocalizedType>Map Tip</LocalizedType>
+  <Description>A widget to display information about features under the mouse as it hovers over the map</Description>
   <Location></Location>
   <Label>Map tip</Label>
   <Tooltip></Tooltip>
@@ -23,11 +22,35 @@
   </Parameter>
   <Parameter>
     <Name>Layer</Name>
-    <Description>The layers to display information about.  Repeat this 
-    parameter as often as required
-    </Description>
+    <Description>The layers to display information about</Description>
     <Type>String</Type>
-    <Label>layers</Label>
+    <Label>Layers</Label>
     <IsMandatory>false</IsMandatory>
   </Parameter>
+  <Parameter>
+    <Name>Tolerance</Name>
+    <Description>The number of screen pixels around the cursor to query</Description>
+    <Type>integer</Type>
+    <Label>Tolerance</Label>
+    <Min>0</Min>
+    <Max>10</Max>
+    <DefaultValue>2</DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
+  <Parameter>
+    <Name>Target</Name>
+    <Label>Target</Label>
+    <Type>String</Type>
+    <Description>The frame, window, or TaskPane in which to open hyperlinks. If empty, a new window is used</Description>
+    <IsMandatory>false</IsMandatory>
+    <DefaultValue>MaptipWindow</DefaultValue>
+  </Parameter>
+  <Parameter>
+    <Name>WinFeatures</Name>
+    <Label>Window Features</Label>
+    <Type>String</Type>
+    <Description>Options for opening hyperlinks new window, if used</Description>
+    <IsMandatory>false</IsMandatory>
+    <DefaultValue>menubar=no,location=no,resizable=no,status=no</DefaultValue>
+  </Parameter>
 </WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/maptip.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/measure.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/measure.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/measure.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Measure</Type>
+  <LocalizedType>Measure</LocalizedType>
   <Description>A widget that allows measurements to be made on the map</Description>
   <Location></Location>
   <Label>Measure</Label>
@@ -34,9 +35,9 @@
     <Description>Precision of the distance displayed</Description>
     <Type>integer</Type>
     <Label>DistancePrecision</Label>
-    <Min>0</Min>
-    <Max>6</Max>
-    <DefaultValue>2</DefaultValue>
+    <Min>1</Min>
+    <Max>8</Max>
+    <DefaultValue>4</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
   <Parameter>
@@ -44,9 +45,9 @@
     <Description>Precision of the area displayed</Description>
     <Type>integer</Type>
     <Label>Area Precision</Label>
-    <Min>0</Min>
-    <Max>6</Max>
-    <DefaultValue>2</DefaultValue>
+    <Min>1</Min>
+    <Max>8</Max>
+    <DefaultValue>4</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
   <Parameter>
@@ -139,11 +140,7 @@
       <Name>Target</Name>
       <Label>Target</Label>
       <Type>target</Type>
-      <Description>If this is a TaskPane widget, this widget will set a URL
-      in the TaskPane to gather user input, otherwise it looks for an HTML
-      element with this name, otherwise it will open a popup window to gather 
-      user input.
-      </Description>
+      <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
       <IsMandatory>true</IsMandatory>
       <DefaultValue>TaskPane</DefaultValue>
   </Parameter>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/measure.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/navigator.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/navigator.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/navigator.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Navigator</Type>
+  <LocalizedType>Navigator</LocalizedType>
   <Description>In-map navigator widget</Description>
   <Location></Location>
   <Label>Navigator</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/navigator.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/overviewmap.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/overviewmap.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/overviewmap.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>OverviewMap</Type>
+  <LocalizedType>Overview Map</LocalizedType>
   <Description>A key map to locate the vewing area of the primary map</Description>
   <Location></Location>
   <Label>Overview map</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/overviewmap.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/pan.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/pan.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/pan.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Pan</Type>
+  <LocalizedType>Pan</LocalizedType>
   <Description>Pans the map</Description>
   <Location></Location>
   <Label>Pan</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/pan.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/panonclick.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/panonclick.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/panonclick.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>PanOnClick</Type>
+  <LocalizedType>Pan on Click</LocalizedType>
   <Description>Pans the map in the specified diretion on a click</Description>
   <Location></Location>
   <Label>Pan on click</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/panonclick.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/panquery.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/panquery.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/panquery.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,13 +1,12 @@
 <WidgetInfo>
   <Type>PanQuery</Type>
-  <Description>A widget that combines pan and query actions.  If the mouse did
-  not move, a query is issued, otherwise a pan is performed.
-  </Description>
+  <LocalizedType>Pan Query</LocalizedType>
+  <Description>A widget that combines pan and query actions.  If the mouse did not move, a query is issued, otherwise a pan is performed</Description>
   <Location></Location>
   <Label>Pan query</Label>
   <Tooltip>Drag the mouse to pan, click to query</Tooltip>
   <StatusText></StatusText>
-  <ImageUrl>String</ImageUrl>
+  <ImageUrl>images/icons/pan.png</ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/panquery.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/print.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/print.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/print.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Print</Type>
+  <LocalizedType>Print</LocalizedType>
   <Description>Produces a printable version of the page</Description>
   <Label>Print</Label>
   <Tooltip>Print the current map view</Tooltip>
@@ -46,4 +47,12 @@
     <DefaultValue>false</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
+  <Parameter>
+    <Name>ImageBaseUrl</Name>
+    <Description>relative URL to the images directory for dialog</Description>
+    <Type>string</Type>
+    <Label>Image Base URL</Label>
+    <DefaultValue></DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
 </WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/print.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/refreshmap.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/refreshmap.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/refreshmap.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>RefreshMap</Type>
+  <LocalizedType>Refresh Map</LocalizedType>
   <Description>A widget that redraws the map</Description>
   <Location></Location>
   <Label>Refresh</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/refreshmap.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/savemap.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/savemap.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/savemap.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,37 +1,50 @@
-<WidgetInfo>
-  <Type>SaveMap</Type>
-  <Description>A widget to save the map as an image</Description>
-  <Label>Save map</Label>
-  <Tooltip>Click to save the map as an image</Tooltip>
-  <ImageUrl>images/icons/file-save.png</ImageUrl>
-  <StandardUi>true</StandardUi>
-  <ContainableBy>Any</ContainableBy>
-  <Parameter>
-    <Name>Format</Name>
-    <Description>The image format to use</Description>
-    <Type>String</Type>
-    <Label>Format</Label>
-    <AllowedValue>
-      <Name>png</Name>
-      <Label>png</Label>
-    </AllowedValue>
-    <AllowedValue>
-      <Name>jpg</Name>
-      <Label>jpg</Label>
-    </AllowedValue>
-    <AllowedValue>
-      <Name>gif</Name>
-      <Label>gif</Label>
-    </AllowedValue>
-    <DefaultValue>png</DefaultValue>
-    <IsMandatory>false</IsMandatory>
-  </Parameter>
-  <Parameter>
-    <Name>Scale</Name>
-    <Description>The scale denominator at which the map is to be saved</Description>
-    <Type>integer</Type>
-    <Label>Scale</Label>
-    <DefaultValue></DefaultValue>
-    <IsMandatory>false</IsMandatory>
-  </Parameter>
-</WidgetInfo>
+<WidgetInfo>
+  <Type>SaveMap</Type>
+  <LocalizedType>Save Map</LocalizedType>
+  <Description>A widget to save the map as an image</Description>
+  <Label>Save map</Label>
+  <Tooltip>Click to save the map as an image</Tooltip>
+  <ImageUrl>images/icons/file-save.png</ImageUrl>
+  <StandardUi>true</StandardUi>
+  <ContainableBy>Any</ContainableBy>
+  <Parameter>
+    <Name>Format</Name>
+    <Description>The image format to use</Description>
+    <Type>String</Type>
+    <Label>Format</Label>
+    <AllowedValue>
+      <Name>dwf</Name>
+      <Label>DWF</Label>
+    </AllowedValue>    
+    <AllowedValue>
+      <Name>png</Name>
+      <Label>PNG</Label>
+    </AllowedValue>
+    <AllowedValue>
+      <Name>jpg</Name>
+      <Label>JPEG</Label>
+    </AllowedValue>
+    <AllowedValue>
+      <Name>gif</Name>
+      <Label>GIF</Label>
+    </AllowedValue>
+    <DefaultValue>png</DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
+  <Parameter>
+    <Name>Scale</Name>
+    <Description>The scale at which the map is to be saved, or 0 to use the current map scale</Description>
+    <Type>integer</Type>
+    <Label>Scale</Label>
+    <DefaultValue></DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
+  <Parameter>
+      <Name>ResourceId</Name>
+      <Description>The print layout to be used for DWF creation.  This is mandatory if the format is set to DWF.</Description>
+      <Type>PrintLayout</Type>
+      <Label>Print Layout (DWF Only)</Label>
+      <DefaultValue></DefaultValue>
+      <IsMandatory>false</IsMandatory>
+  </Parameter>
+</WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/savemap.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/scalebar.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/scalebar.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/scalebar.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Scalebar</Type>
+  <LocalizedType>Scale Bar</LocalizedType>
   <Description>Outputs a cartographic scalebar</Description>
   <Location></Location>
   <Label>Scalebar</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/scalebar.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/search.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/search.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/search.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Search</Type>
+  <LocalizedType>Search</LocalizedType>
   <Description>A widget which will perform an attribute based search</Description>
   <Location></Location>
   <Label>Search</Label>
@@ -11,13 +12,9 @@
   <ContainableBy>Any</ContainableBy>
   <Parameter>
     <Name>Target</Name>
-    <Label>The name of a task pane widget or a popup window</Label>
-    <Type>string</Type>
-    <Description>If this is a TaskPane widget, this widget will set a URL
-    in the TaskPane to gather user input, otherwise it looks for an HTML
-    element with this name, otherwise it will open a popup window to gather 
-    user input.
-    </Description>
+    <Label>Target</Label>
+    <Type>target</Type>
+    <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
     <IsMandatory>true</IsMandatory>
   </Parameter>
   <Parameter>
@@ -55,12 +52,18 @@
   </Parameter>
   <Parameter>
     <Name>ResultColumns</Name>
-    <Description>An XML structure describing the columns to be returned as part 
-    of the search and their labels
-    </Description>
+    <Description>An XML structure describing the columns to be returned as part of the search and their labels</Description>
     <Type>XML</Type>
     <Label>ResultColumns</Label>
     <DefaultValue></DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
+  <Parameter>
+    <Name>Title</Name>
+    <Description>The title to use for the search form</Description>
+    <Type>String</Type>
+    <Label>Title</Label>
+    <DefaultValue></DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
 </WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/search.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/select.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/select.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/select.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Select</Type>
+  <LocalizedType>Select</LocalizedType>
   <Description>A widget that allows selection of features on a map</Description>
   <Location></Location>
   <Label>Select</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/select.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectioninfo.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectioninfo.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectioninfo.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <WidgetInfo>
   <Type>SelectionInfo</Type>
-  <Description>Displays the number of features and number of layers in the 
-  current selection.</Description>
+  <LocalizedType>Selection Info</LocalizedType>
+  <Description>Displays the number of features and number of layers in the current selection.</Description>
   <Location></Location>
   <Label>Selection info</Label>
   <Tooltip></Tooltip>
@@ -9,13 +9,21 @@
   <ImageUrl></ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>false</StandardUi>
-  <ContainableBy></ContainableBy>
+  <ContainableBy>Splitterbar</ContainableBy>
   <Parameter>
     <Name>Template</Name>
     <Description>The format of the output string.</Description>
     <Type>String</Type>
     <Label>Template</Label>
-    <DefaultValue>{features} features selected on {layers} layers</DefaultValue>
+    <DefaultValue>{0} features selected on {1} layers</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
+  <Parameter>
+    <Name>EmptyText</Name>
+    <Description>The string to display when nothing is selected</Description>
+    <Type>String</Type>
+    <Label>Empty selection string</Label>
+    <DefaultValue>No features selected</DefaultValue>
+    <IsMandatory>false</IsMandatory>
+  </Parameter>
 </WidgetInfo>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectioninfo.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectionpanel.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectionpanel.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectionpanel.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>SelectionPanel</Type>
-  <Description>The SelectionPanel widget displays attributes for the features 
-  that are selected on the map.
-  </Description>
+  <LocalizedType>Selection Panel</LocalizedType>
+  <Description>The SelectionPanel widget displays attributes for the features that are selected on the map.</Description>
   <Location></Location>
   <Label>Selection Panel</Label>
   <Tooltip></Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectionpanel.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectpolygon.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectpolygon.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectpolygon.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>SelectPolygon</Type>
+  <LocalizedType>Select Polygon</LocalizedType>
   <Description>Perform a selection using a polygon</Description>
   <Location></Location>
   <Label>Select Polygon</Label>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectpolygon.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectradius.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectradius.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectradius.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>SelectRadius</Type>
+  <LocalizedType>Select Radius</LocalizedType>
   <Description>Perform a selection within a certain radius of a click</Description>
   <Label>Select Radius</Label>
   <Tooltip>Click to select within a radius</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectradius.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectradiusvalue.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectradiusvalue.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectradiusvalue.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,8 +1,7 @@
 <WidgetInfo>
   <Type>SelectRadiusValue</Type>
-  <Description>A widget to allow the user can manually enter a radius for 
-  the SelectRadius widget
-  </Description>
+  <LocalizedType>Select Radius Value</LocalizedType>
+  <Description>A widget to allow the user can manually enter a radius for the SelectRadius widget</Description>
   <Location></Location>
   <Label>Select radius value</Label>
   <Tooltip>enter the radius for the Select by Radius tool</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectradiusvalue.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/selectwithin.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/selectwithin.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/selectwithin.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <WidgetInfo>
   <Type>SelectWithin</Type>
-  <Description>A widget to perform a selection within a currently selected set 
-  of features</Description>
+  <LocalizedType>Select Within</LocalizedType>
+  <Description>A widget to perform a selection within a currently selected set of features</Description>
   <Location></Location>
   <Label>Select within</Label>
   <Tooltip>Click to select features within this selection</Tooltip>
@@ -14,18 +14,13 @@
     <Name>Target</Name>
     <Label>Target</Label>
     <Type>target</Type>
-    <Description>If this is a TaskPane widget, this widget will set a URL
-    in the TaskPane to gather user input, otherwise it looks for an HTML
-    element with this name, otherwise it will open a popup window to gather 
-    user input.
-    </Description>
+    <Description>The frame, window, or TaskPane in which to display any UI for the widget. If empty, a new window is used</Description>
     <DefaultValue>TaskPane</DefaultValue>
     <IsMandatory>false</IsMandatory>
   </Parameter>
   <Parameter>
     <Name>DisableIfSelectionEmpty</Name>
-    <Description>A flag to indicate if this widget should only be enabled if 
-    there is a selection available on the map</Description>
+    <Description>A flag to indicate if this widget should only be enabled if there is a selection available on the map</Description>
     <Type>boolean</Type>
     <Label>Disable If Selection Empty</Label>
     <DefaultValue>true</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/selectwithin.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/taskpane.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/taskpane.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/taskpane.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <WidgetInfo>
   <Type>TaskPane</Type>
-  <Description>A widget that acts as a workspace for widgets that require user 
-  input/output, e.g. InvokeURL, Buffer, Search, etc. widgets</Description>
+  <LocalizedType>Task Pane</LocalizedType>
+  <Description>A widget that acts as a workspace for widgets that require user input/output, e.g. InvokeURL, Buffer, Search, etc. widgets</Description>
   <Location></Location>
   <Label>TaskPane</Label>
   <Tooltip></Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/taskpane.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/viewoptions.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/viewoptions.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/viewoptions.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,11 +1,12 @@
 <WidgetInfo>
   <Type>ViewOptions</Type>
+  <LocalizedType>View Options</LocalizedType>
   <Description>A widget to allow selection of the display units for various widgets</Description>
   <Location></Location>
   <Label>Options</Label>
   <Tooltip>Click to change the units displayed</Tooltip>
   <StatusText></StatusText>
-  <ImageUrl></ImageUrl>
+  <ImageUrl>images/icons/options.png</ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>true</StandardUi>
   <ContainableBy>Any</ContainableBy>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/viewoptions.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/viewsize.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/viewsize.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/viewsize.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,6 +1,7 @@
 <!-- this widget doesn't work the same was as the scale entry in the existing AJAX viewer, so we may make a new one -->
 <WidgetInfo>
   <Type>ViewSize</Type>
+  <LocalizedType>View Size</LocalizedType>
   <Description>Display the size of the current view in user-definable units</Description>
   <Location></Location>
   <Label>ViewSize</Label>
@@ -9,7 +10,7 @@
   <ImageUrl></ImageUrl>
   <ImageClass></ImageClass>
   <StandardUi>false</StandardUi>
-  <ContainableBy>Toolbar</ContainableBy>
+  <ContainableBy>Splitterbar</ContainableBy>
   <Parameter>
     <Name>Units</Name>
     <Description>the units to display the size in</Description>
@@ -58,9 +59,7 @@
   </Parameter>
   <Parameter>
     <Name>Template</Name>
-    <Description>A template string to display the size.  Values in {} will be 
-    replaced by actual values
-    </Description>
+    <Description>A template string to display the size. Values in {} will be replaced by actual values</Description>
     <Type>String</Type>
     <Label>Template</Label>
     <DefaultValue>{w} x {h} {units}</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/viewsize.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/zoom.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/zoom.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/zoom.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>Zoom</Type>
+  <LocalizedType>Zoom</LocalizedType>
   <Description>Zooms in on the map</Description>
   <Label>Zoom Rectangle</Label>
   <Tooltip>Click or click and drag on the map to zoom in</Tooltip>
@@ -10,7 +11,7 @@
   <ContainableBy>Any</ContainableBy>
   <Parameter>
     <Name>Tolerance</Name>
-    <Description>not sure</Description>
+    <Description>Zoom tolerance</Description>
     <Type>integer</Type>
     <Label>Tolerance</Label>
     <Min></Min>
@@ -29,7 +30,7 @@
   </Parameter>
   <Parameter>
     <Name>Direction</Name>
-    <Description>indicates if the map should zoom in or out</Description>
+    <Description>Indicates if the map should zoom in or out</Description>
     <Type>String</Type>
     <Label>Direction</Label>
     <AllowedValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/zoom.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/zoomonclick.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/zoomonclick.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/zoomonclick.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,5 +1,6 @@
 <WidgetInfo>
   <Type>ZoomOnClick</Type>
+  <LocalizedType>Zoom on Click</LocalizedType>
   <Description>Zoom the map by a fixed amount when a button is clicked</Description>
   <Location></Location>
   <Label>ZoomOnClick</Label>
@@ -11,7 +12,7 @@
   <ContainableBy>Any</ContainableBy>
   <Parameter>
     <Name>Factor</Name>
-    <Description>The factor to zoom by.  Values less than 0 zoom out.</Description>
+    <Description>The factor to zoom by. Values less than 0 zoom out.</Description>
     <Type>double</Type>
     <Label>Factor</Label>
     <DefaultValue>2</DefaultValue>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/zoomonclick.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision

Modified: sandbox/aboudreault/widgets/widgetinfo/zoomtoselection.xml
===================================================================
--- sandbox/aboudreault/widgets/widgetinfo/zoomtoselection.xml	2008-03-28 20:33:50 UTC (rev 1352)
+++ sandbox/aboudreault/widgets/widgetinfo/zoomtoselection.xml	2008-03-31 14:35:37 UTC (rev 1353)
@@ -1,7 +1,7 @@
 <WidgetInfo>
   <Type>ZoomToSelection</Type>
-  <Description>A widget that will zoom the map to the currently selected features
-  </Description>
+  <LocalizedType>Zoom to Selection</LocalizedType>
+  <Description>A widget that will zoom the map to the currently selected features</Description>
   <Location></Location>
   <Label>Zoom Selection</Label>
   <Tooltip>Click to zoom to the selection</Tooltip>


Property changes on: sandbox/aboudreault/widgets/widgetinfo/zoomtoselection.xml
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision



More information about the fusion-commits mailing list