[fusion-commits] r1482 - in sandbox/jx2: jx jx/images jx/images/delicious jx/lib lib templates/mapguide/standard templates/mapserver/standard widgets

svn_fusion at osgeo.org svn_fusion at osgeo.org
Thu Aug 28 08:29:20 EDT 2008


Author: pagameba
Date: 2008-08-28 08:29:20 -0400 (Thu, 28 Aug 2008)
New Revision: 1482

Added:
   sandbox/jx2/jx/images/delicious/
   sandbox/jx2/jx/images/delicious/button_bg.png
   sandbox/jx2/jx/images/delicious/dialog_chrome.png
   sandbox/jx2/jx/images/delicious/dialog_resize.png
   sandbox/jx2/jx/images/delicious/emblems.png
   sandbox/jx2/jx/images/delicious/flyout_chrome.png
   sandbox/jx2/jx/images/delicious/tree.png
   sandbox/jx2/jx/images/panel_controls.png
   sandbox/jx2/jx/lib/jxlib.js
   sandbox/jx2/jx/lib/jxlib.uncompressed.js
   sandbox/jx2/jx/lib/jxskin_border.css
   sandbox/jx2/jx/lib/jxskin_delicious.css
Removed:
   sandbox/jx2/jx/css/
   sandbox/jx2/jx/lib/jx_combined.css
   sandbox/jx2/jx/lib/jx_combined.js
   sandbox/jx2/jx/lib/jx_compressed.js
Modified:
   sandbox/jx2/jx/images/close.png
   sandbox/jx2/jx/images/disclose.png
   sandbox/jx2/jx/images/help.png
   sandbox/jx2/jx/images/maximize.png
   sandbox/jx2/jx/images/minimize.png
   sandbox/jx2/jx/images/tree_folder.png
   sandbox/jx2/jx/images/tree_folder_open.png
   sandbox/jx2/jx/images/tree_last_node.png
   sandbox/jx2/jx/images/tree_minus.png
   sandbox/jx2/jx/images/tree_node.png
   sandbox/jx2/jx/images/tree_none.png
   sandbox/jx2/jx/images/tree_page.png
   sandbox/jx2/jx/images/tree_plus.png
   sandbox/jx2/lib/ApplicationDefinition.js
   sandbox/jx2/lib/ButtonTool.js
   sandbox/jx2/lib/Map.js
   sandbox/jx2/lib/MenuBase.js
   sandbox/jx2/lib/fusion.js
   sandbox/jx2/templates/mapguide/standard/index.html
   sandbox/jx2/templates/mapserver/standard/ApplicationDefinition.xml
   sandbox/jx2/templates/mapserver/standard/index.html
   sandbox/jx2/widgets/ColorPicker.js
   sandbox/jx2/widgets/EditableScale.js
   sandbox/jx2/widgets/LayerManager.js
   sandbox/jx2/widgets/Legend.js
   sandbox/jx2/widgets/MapMenu.js
   sandbox/jx2/widgets/Measure.js
   sandbox/jx2/widgets/Navigator.js
   sandbox/jx2/widgets/Print.js
   sandbox/jx2/widgets/SaveMap.js
   sandbox/jx2/widgets/SelectionPanel.js
   sandbox/jx2/widgets/TaskPane.js
   sandbox/jx2/widgets/ViewOptions.js
Log:
first cut, things more or less working

Modified: sandbox/jx2/jx/images/close.png
===================================================================
(Binary files differ)

Added: sandbox/jx2/jx/images/delicious/button_bg.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/button_bg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/jx2/jx/images/delicious/dialog_chrome.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/dialog_chrome.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/jx2/jx/images/delicious/dialog_resize.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/dialog_resize.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/jx2/jx/images/delicious/emblems.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/emblems.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/jx2/jx/images/delicious/flyout_chrome.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/flyout_chrome.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/jx2/jx/images/delicious/tree.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/delicious/tree.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: sandbox/jx2/jx/images/disclose.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/help.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/maximize.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/minimize.png
===================================================================
(Binary files differ)

Added: sandbox/jx2/jx/images/panel_controls.png
===================================================================
(Binary files differ)


Property changes on: sandbox/jx2/jx/images/panel_controls.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: sandbox/jx2/jx/images/tree_folder.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_folder_open.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_last_node.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_minus.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_node.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_none.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_page.png
===================================================================
(Binary files differ)

Modified: sandbox/jx2/jx/images/tree_plus.png
===================================================================
(Binary files differ)

Deleted: sandbox/jx2/jx/lib/jx_combined.css
===================================================================
--- sandbox/jx2/jx/lib/jx_combined.css	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/jx/lib/jx_combined.css	2008-08-28 12:29:20 UTC (rev 1482)
@@ -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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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: jx_combined.css 776 2008-08-22 18:46:25Z madair $
- * @author          Fred Warnock (fwarnock at dmsolutions.ca)
- * @copyright       © 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/jx2/jx/lib/jx_combined.js
===================================================================
--- sandbox/jx2/jx/lib/jx_combined.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/jx/lib/jx_combined.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1,14064 +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 © 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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 */
-Event.observe(window, 'load', function() {
-    if (!("console" in window) || !("firebug" in window.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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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);            
-                var temp = new Jx.Layout(this.blanket);
-                temp.resize();
-            }        
-        }
-
-        /* 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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 || {};
-        if (!options.label) {
-            options.label = name;
-        }
-        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, options);
-        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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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: jx_combined.js 776 2008-08-22 18:46:25Z madair $
- *
- * 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/jx2/jx/lib/jx_compressed.js
===================================================================
--- sandbox/jx2/jx/lib/jx_compressed.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/jx/lib/jx_compressed.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -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;}};Event.observe(window,'load',function(){if(!("console"in window)||!("firebug"in window.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),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);var temp=new Jx.Layout(this.blanket);temp.resize();}}
-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||{};if(!options.label){options.label=name;}
-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,options);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

Added: sandbox/jx2/jx/lib/jxlib.js
===================================================================
--- sandbox/jx2/jx/lib/jxlib.js	                        (rev 0)
+++ sandbox/jx2/jx/lib/jxlib.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -0,0 +1 @@
+var MooTools={version:"1.2dev",build:""};var Native=function(J){J=J||{};var F=J.afterImplement||function(){};var G=J.generics;G=(G!==false);var H=J.legacy;var E=J.initialize;var B=J.protect;var A=J.name;var C=E||H;C.constructor=Native;C.$family={name:"native"};if(H&&E){C.prototype=H.prototype}C.prototype.constructor=C;if(A){var D=A.toLowerCase();C.prototype.$family={name:D};Native.typize(C,D)}var I=function(M,K,N,L){if(!B||L||!M.prototype[K]){M.prototype[K]=N}if(G){Native.genericize(M,K,B)}F.call(M,K,N);return M};C.implement=function(L,K,N){if(typeof L=="string"){return I(this,L,K,N)}for(var M in L){I(this,M,L[M],K)}return this};C.alias=function(M,K,N){if(typeof M=="string"){M=this.prototype[M];if(M){I(this,K,M,N)}}else{for(var L in M){this.alias(L,M[L],K)}}return this};return C};Native.implement=function(D,C){for(var B=0,A=D.length;B<A;B++){D[B].implement(C)}};Native.genericize=function(B,C,A){if((!A||!B[C])&&typeof B.prototype[C]=="function"){B[C]=function(){var D=Array.prototype.slice.call(arguments);return B.prototype[C].apply(D.shift(),D)}}};Native.typize=function(A,B){if(!A.type){A.type=function(C){return($type(C)===B)}}};Native.alias=function(E,B,A,F){for(var D=0,C=E.length;D<C;D++){E[D].alias(B,A,F)}};(function(B){for(var A in B){Native.typize(B[A],A)}})({"boolean":Boolean,"native":Native,object:Object});(function(B){for(var A in B){new Native({name:A,initialize:B[A],protect:true})}})({String:String,Function:Function,Number:Number,Array:Array,RegExp:RegExp,Date:Date});(function(B,A){for(var C=A.length;C--;C){Native.genericize(B,A[C],true)}return arguments.callee})(Array,["pop","push","reverse","shift","sort","splice","unshift","concat","join","slice","toString","valueOf","indexOf","lastIndexOf"])(String,["charAt","charCodeAt","concat","indexOf","lastIndexOf","match","replace","search","slice","split","substr","substring","toLowerCase","toUpperCase","valueOf"]);function $chk(A){return !!(A||A===0)}function $clear(A){clearTimeout(A);clearInterval(A);return null}function $defined(A){return(A!=undefined)}function $empty(){}function $arguments(A){return function(){return arguments[A]}}function $lambda(A){return(typeof A=="function")?A:function(){return A}}function $extend(C,A){for(var B in (A||{})){C[B]=A[B]}return C}function $unlink(C){var B;switch($type(C)){case"object":B={};for(var E in C){B[E]=$unlink(C[E])}break;case"hash":B=$unlink(C.getClean());break;case"array":B=[];for(var D=0,A=C.length;D<A;D++){B[D]=$unlink(C[D])}break;default:return C}return B}function $merge(){var E={};for(var D=0,A=arguments.length;D<A;D++){var B=arguments[D];if($type(B)!="object"){continue}for(var C in B){var G=B[C],F=E[C];E[C]=(F&&$type(G)=="object"&&$type(F)=="object")?$merge(F,G):$unlink(G)}}return E}function $pick(){for(var B=0,A=arguments.length;B<A;B++){if(arguments[B]!=undefined){return arguments[B]}}return null}function $random(B,A){return Math.floor(Math.random()*(A-B+1)+B)}function $splat(B){var A=$type(B);return(A)?((A!="array"&&A!="arguments")?[B]:B):[]}var $time=Date.now||function(){return new Date().getTime()};function $try(){for(var B=0,A=arguments.length;B<A;B++){try{return arguments[B]()}catch(C){}}return null}function $type(A){if(A==undefined){return false}if(A.$family){return(A.$family.name=="number"&&!isFinite(A))?false:A.$family.name}if(A.nodeName){switch(A.nodeType){case 1:return"element";case 3:return(/\S/).test(A.nodeValue)?"textnode":"whitespace"}}else{if(typeof A.length=="number"){if(A.callee){return"arguments"}else{if(A.item){return"collection"}}}}return typeof A}var Hash=new Native({name:"Hash",initialize:function(A){if($type(A)=="hash"){A=$unlink(A.getClean())}for(var B in A){this[B]=A[B]}return this}});Hash.implement({getLength:function(){var B=0;for(var A in this){if(this.hasOwnProperty(A)){B++}}return B},forEach:function(B,C){for(var A in this){if(this.hasOwnProperty(A)){B.call(C,this[A],A,this)}}},getClean:function(){var B={};for(var A in this){if(this.hasOwnProperty(A)){B[A]=this[A]}}return B}});Hash.alias("forEach","each");function $H(A){return new Hash(A)}Array.implement({forEach:function(C,D){for(var B=0,A=this.length;B<A;B++){C.call(D,this[B],B,this)}}});Array.alias("forEach","each");function $A(C){if(C.item){var D=[];for(var B=0,A=C.length;B<A;B++){D[B]=C[B]}return D}return Array.prototype.slice.call(C)}function $each(C,B,D){var A=$type(C);((A=="arguments"||A=="collection"||A=="array")?Array:Hash).each(C,B,D)}var Browser=new Hash({Engine:{name:"unknown",version:""},Platform:{name:(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime)},Plugins:{}});if(window.opera){Browser.Engine={name:"presto",version:(document.getElementsByClassName)?950:925}}else{if(window.ActiveXObject){Browser.Engine={name:"trident",version:(window.XMLHttpRequest)?5:4}}else{if(!navigator.taintEnabled){Browser.Engine={name:"webkit",version:(Browser.Features.xpath)?420:419}}else{if(document.getBoxObjectFor!=null){Browser.Engine={name:"gecko",version:(document.getElementsByClassName)?19:18}}}}}Browser.Engine[Browser.Engine.name]=Browser.Engine[Browser.Engine.name+Browser.Engine.version]=true;if(window.orientation!=undefined){Browser.Platform.name="ipod"}Browser.Platform[Browser.Platform.name]=true;Browser.Request=function(){return $try(function(){return new XMLHttpRequest()},function(){return new ActiveXObject("MSXML2.XMLHTTP")})};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var A=($try(function(){return navigator.plugins["Shockwave Flash"].description},function(){return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")})||"0 r0").match(/\d+/g);return{version:parseInt(A[0]||0+"."+A[1]||0),build:parseInt(A[2]||0)}})();function $exec(B){if(!B){return B}if(window.execScript){window.execScript(B)}else{var A=document.createElement("script");A.setAttribute("type","text/javascript");A.text=B;document.head.appendChild(A);document.head.removeChild(A)}return B}Native.UID=1;var $uid=(Browser.Engine.trident)?function(A){return(A.uid||(A.uid=[Native.UID++]))[0]}:function(A){return A.uid||(A.uid=Native.UID++)};var Window=new Native({name:"Window",legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(A){$uid(A);if(!A.Element){A.Element=$empty;if(Browser.Engine.webkit){A.document.createElement("iframe")}A.Element.prototype=(Browser.Engine.webkit)?window["[[DOMElement.prototype]]"]:{}}return $extend(A,Window.Prototype)},afterImplement:function(B,A){window[B]=Window.Prototype[B]=A}});Window.Prototype={$family:{name:"window"}};new Window(window);var Document=new Native({name:"Document",legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(A){$uid(A);A.head=A.getElementsByTagName("head")[0];A.html=A.getElementsByTagName("html")[0];A.window=A.defaultView||A.parentWindow;if(Browser.Engine.trident4){$try(function(){A.execCommand("BackgroundImageCache",false,true)})}return $extend(A,Document.Prototype)},afterImplement:function(B,A){document[B]=Document.Prototype[B]=A}});Document.Prototype={$family:{name:"document"}};new Document(document);Array.implement({every:function(C,D){for(var B=0,A=this.length;B<A;B++){if(!C.call(D,this[B],B,this)){return false}}return true},filter:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B])}}return C},clean:function(){return this.filter($defined)},indexOf:function(C,D){var A=this.length;for(var B=(D<0)?Math.max(0,A+D):D||0;B<A;B++){if(this[B]===C){return B}}return -1},map:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){C[B]=D.call(E,this[B],B,this)}return C},some:function(C,D){for(var B=0,A=this.length;B<A;B++){if(C.call(D,this[B],B,this)){return true}}return false},associate:function(C){var D={},B=Math.min(this.length,C.length);for(var A=0;A<B;A++){D[C[A]]=this[A]}return D},link:function(C){var A={};for(var E=0,B=this.length;E<B;E++){for(var D in C){if(C[D](this[E])){A[D]=this[E];delete C[D];break}}}return A},contains:function(A,B){return this.indexOf(A,B)!=-1},extend:function(C){for(var B=0,A=C.length;B<A;B++){this.push(C[B])}return this},getLast:function(){return(this.length)?this[this.length-1]:null},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null},include:function(A){if(!this.contains(A)){this.push(A)}return this},combine:function(C){for(var B=0,A=C.length;B<A;B++){this.include(C[B])}return this},erase:function(B){for(var A=this.length;A--;A){if(this[A]===B){this.splice(A,1)}}return this},empty:function(){this.length=0;return this},flatten:function(){var D=[];for(var B=0,A=this.length;B<A;B++){var C=$type(this[B]);if(!C){continue}D=D.concat((C=="array"||C=="collection"||C=="arguments")?Array.flatten(this[B]):this[B])}return D},hexToRgb:function(B){if(this.length!=3){return null}var A=this.map(function(C){if(C.length==1){C+=C}return C.toInt(16)});return(B)?A:"rgb("+A+")"},rgbToHex:function(D){if(this.length<3){return null}if(this.length==4&&this[3]==0&&!D){return"transparent"}var B=[];for(var A=0;A<3;A++){var C=(this[A]-0).toString(16);B.push((C.length==1)?"0"+C:C)}return(D)?B:"#"+B.join("")}});Function.implement({extend:function(A){for(var B in A){this[B]=A[B]}return this},create:function(B){var A=this;B=B||{};return function(D){var C=B.arguments;C=(C!=undefined)?$splat(C):Array.slice(arguments,(B.event)?1:0);if(B.event){C=[D||window.event].extend(C)}var E=function(){return A.apply(B.bind||null,C)};if(B.delay){return setTimeout(E,B.delay)}if(B.periodical){return setInterval(E,B.periodical)}if(B.attempt){return $try(E)}return E()}},pass:function(A,B){return this.create({arguments:A,bind:B})},attempt:function(A,B){return this.create({arguments:A,bind:B,attempt:true})()},bind:function(B,A){return this.create({bind:B,arguments:A})},bindWithEvent:function(B,A){return this.create({bind:B,event:true,arguments:A})},delay:function(B,C,A){return this.create({delay:B,bind:C,arguments:A})()},periodical:function(A,C,B){return this.create({periodical:A,bind:C,arguments:B})()},run:function(A,B){return this.apply(B,$splat(A))}});Number.implement({limit:function(B,A){return Math.min(A,Math.max(B,this))},round:function(A){A=Math.pow(10,A||0);return Math.round(this*A)/A},times:function(B,C){for(var A=0;A<this;A++){B.call(C,A,this)}},toFloat:function(){return parseFloat(this)},toInt:function(A){return parseInt(this,A||10)}});Number.alias("times","each");(function(B){var A={};B.each(function(C){if(!Number[C]){A[C]=function(){return Math[C].apply(null,[this].concat($A(arguments)))}}});Number.implement(A)})(["abs","acos","asin","atan","atan2","ceil","cos","exp","floor","log","max","min","pow","sin","sqrt","tan"]);String.implement({test:function(A,B){return((typeof A=="string")?new RegExp(A,B):A).test(this)},contains:function(A,B){return(B)?(B+this+B).indexOf(B+A+B)>-1:this.indexOf(A)>-1},trim:function(){return this.replace(/^\s+|\s+$/g,"")},clean:function(){return this.replace(/\s+/g," ").trim()},camelCase:function(){return this.replace(/-\D/g,function(A){return A.charAt(1).toUpperCase()})},hyphenate:function(){return this.replace(/[A-Z]/g,function(A){return("-"+A.charAt(0).toLowerCase())})},capitalize:function(){return this.replace(/\b[a-z]/g,function(A){return A.toUpperCase()})},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1")},toInt:function(A){return parseInt(this,A||10)},toFloat:function(){return parseFloat(this)},hexToRgb:function(B){var A=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(A)?A.slice(1).hexToRgb(B):null},rgbToHex:function(B){var A=this.match(/\d{1,3}/g);return(A)?A.rgbToHex(B):null},stripScripts:function(B){var A="";var C=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi,function(){A+=arguments[1]+"\n";return""});if(B===true){$exec(A)}else{if($type(B)=="function"){B(A,C)}}return C},substitute:function(A,B){return this.replace(B||(/\\?\{([^}]+)\}/g),function(D,C){if(D.charAt(0)=="\\"){return D.slice(1)}return(A[C]!=undefined)?A[C]:""})}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(B){for(var A in this){if(this.hasOwnProperty(A)&&this[A]===B){return A}}return null},hasValue:function(A){return(Hash.keyOf(this,A)!==null)},extend:function(A){Hash.each(A,function(C,B){Hash.set(this,B,C)},this);return this},combine:function(A){Hash.each(A,function(C,B){Hash.include(this,B,C)},this);return this},erase:function(A){if(this.hasOwnProperty(A)){delete this[A]}return this},get:function(A){return(this.hasOwnProperty(A))?this[A]:null},set:function(A,B){if(!this[A]||this.hasOwnProperty(A)){this[A]=B}return this},empty:function(){Hash.each(this,function(B,A){delete this[A]},this);return this},include:function(B,C){var A=this[B];if(A==undefined){this[B]=C}return this},map:function(B,C){var A=new Hash;Hash.each(this,function(E,D){A.set(D,B.call(C,E,D,this))},this);return A},filter:function(B,C){var A=new Hash;Hash.each(this,function(E,D){if(B.call(C,E,D,this)){A.set(D,E)}},this);return A},every:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&!B.call(C,this[A],A)){return false}}return true},some:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&B.call(C,this[A],A)){return true}}return false},getKeys:function(){var A=[];Hash.each(this,function(C,B){A.push(B)});return A},getValues:function(){var A=[];Hash.each(this,function(B){A.push(B)});return A},toQueryString:function(A){var B=[];Hash.each(this,function(F,E){if(A){E=A+"["+E+"]"}var D;switch($type(F)){case"object":D=Hash.toQueryString(F,E);break;case"array":var C={};F.each(function(H,G){C[G]=H});D=Hash.toQueryString(C,E);break;default:D=E+"="+encodeURIComponent(F)}if(F!=undefined){B.push(D)}});return B.join("&")}});Hash.alias({keyOf:"indexOf",hasValue:"contains"});var Event=new Native({name:"Event",initialize:function(A,F){F=F||window;var K=F.document;A=A||F.event;if(A.$extended){return A}this.$extended=true;var J=A.type;var G=A.target||A.srcElement;while(G&&G.nodeType==3){G=G.parentNode}if(J.test(/key/)){var B=A.which||A.keyCode;var M=Event.Keys.keyOf(B);if(J=="keydown"){var D=B-111;if(D>0&&D<13){M="f"+D}}M=M||String.fromCharCode(B).toLowerCase()}else{if(J.match(/(click|mouse|menu)/i)){K=(!K.compatMode||K.compatMode=="CSS1Compat")?K.html:K.body;var I={x:A.pageX||A.clientX+K.scrollLeft,y:A.pageY||A.clientY+K.scrollTop};var C={x:(A.pageX)?A.pageX-F.pageXOffset:A.clientX,y:(A.pageY)?A.pageY-F.pageYOffset:A.clientY};if(J.match(/DOMMouseScroll|mousewheel/)){var H=(A.wheelDelta)?A.wheelDelta/120:-(A.detail||0)/3}var E=(A.which==3)||(A.button==2);var L=null;if(J.match(/over|out/)){switch(J){case"mouseover":L=A.relatedTarget||A.fromElement;break;case"mouseout":L=A.relatedTarget||A.toElement}if(!(function(){while(L&&L.nodeType==3){L=L.parentNode}return true}).create({attempt:Browser.Engine.gecko})()){L=false}}}}return $extend(this,{event:A,type:J,page:I,client:C,rightClick:E,wheel:H,relatedTarget:L,target:G,code:B,key:M,shift:A.shiftKey,control:A.ctrlKey,alt:A.altKey,meta:A.metaKey})}});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Event.implement({stop:function(){return this.stopPropagation().preventDefault()},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation()}else{this.event.cancelBubble=true}return this},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault()}else{this.event.returnValue=false}return this}});var Class=new Native({name:"Class",initialize:function(B){B=B||{};var A=function(E){for(var D in this){this[D]=$unlink(this[D])}for(var F in Class.Mutators){if(!this[F]){continue}Class.Mutators[F](this,this[F]);delete this[F]}this.constructor=A;if(E===$empty){return this}var C=(this.initialize)?this.initialize.apply(this,arguments):this;if(this.options&&this.options.initialize){this.options.initialize.call(this)}return C};$extend(A,this);A.constructor=Class;A.prototype=B;return A}});Class.implement({implement:function(){Class.Mutators.Implements(this.prototype,Array.slice(arguments));return this}});Class.Mutators={Implements:function(A,B){$splat(B).each(function(C){$extend(A,($type(C)=="class")?new C($empty):C)})},Extends:function(self,klass){var instance=new klass($empty);delete instance.parent;delete instance.parentOf;for(var key in instance){var current=self[key],previous=instance[key];if(current==undefined){self[key]=previous;continue}var ctype=$type(current),ptype=$type(previous);if(ctype!=ptype){continue}switch(ctype){case"function":if(!arguments.callee.caller){self[key]=eval("("+String(current).replace(/\bthis\.parent\(\s*(\))?/g,function(full,close){return"arguments.callee._parent_.call(this"+(close||", ")})+")")}self[key]._parent_=previous;break;case"object":self[key]=$merge(previous,current)}}self.parent=function(){return arguments.callee.caller._parent_.apply(this,arguments)};self.parentOf=function(descendant){return descendant._parent_.apply(this,Array.slice(arguments,1))}}};var Chain=new Class({chain:function(){this.$chain=(this.$chain||[]).extend(arguments);return this},callChain:function(){return(this.$chain&&this.$chain.length)?this.$chain.shift().apply(this,arguments):false},clearChain:function(){if(this.$chain){this.$chain.empty()}return this}});var Events=new Class({addEvent:function(C,B,A){C=Events.removeOn(C);if(B!=$empty){this.$events=this.$events||{};this.$events[C]=this.$events[C]||[];this.$events[C].include(B);if(A){B.internal=true}}return this},addEvents:function(A){for(var B in A){this.addEvent(B,A[B])}return this},fireEvent:function(C,B,A){C=Events.removeOn(C);if(!this.$events||!this.$events[C]){return this}this.$events[C].each(function(D){D.create({bind:this,delay:A,"arguments":B})()},this);return this},removeEvent:function(B,A){B=Events.removeOn(B);if(!this.$events||!this.$events[B]){return this}if(!A.internal){this.$events[B].erase(A)}return this},removeEvents:function(C){for(var D in this.$events){if(C&&C!=D){continue}var B=this.$events[D];for(var A=B.length;A--;A){this.removeEvent(D,B[A])}}return this}});Events.removeOn=function(A){return A.replace(/^on([A-Z])/,function(B,C){return C.toLowerCase()})};var Options=new Class({setOptions:function(){this.options=$merge.run([this.options].extend(arguments));if(!this.addEvent){return this}for(var A in this.options){if($type(this.options[A])!="function"||!(/^on[A-Z]/).test(A)){continue}this.addEvent(A,this.options[A]);delete this.options[A]}return this}});Document.implement({newElement:function(A,B){if(Browser.Engine.trident&&B){["name","type","checked"].each(function(C){if(!B[C]){return }A+=" "+C+'="'+B[C]+'"';if(C!="checked"){delete B[C]}});A="<"+A+">"}return $.element(this.createElement(A)).set(B)},newTextNode:function(A){return this.createTextNode(A)},getDocument:function(){return this},getWindow:function(){return this.defaultView||this.parentWindow},purge:function(){var C=this.getElementsByTagName("*");for(var B=0,A=C.length;B<A;B++){Browser.freeMem(C[B])}}});var Element=new Native({name:"Element",legacy:window.Element,initialize:function(A,B){var C=Element.Constructors.get(A);if(C){return C(B)}if(typeof A=="string"){return document.newElement(A,B)}return $(A).set(B)},afterImplement:function(A,B){if(!Array[A]){Elements.implement(A,Elements.multi(A))}Element.Prototype[A]=B}});Element.Prototype={$family:{name:"element"}};Element.Constructors=new Hash;var IFrame=new Native({name:"IFrame",generics:false,initialize:function(){var E=Array.link(arguments,{properties:Object.type,iframe:$defined});var C=E.properties||{};var B=$(E.iframe)||false;var D=C.onload||$empty;delete C.onload;C.id=C.name=$pick(C.id,C.name,B.id,B.name,"IFrame_"+$time());B=new Element(B||"iframe",C);var A=function(){var F=$try(function(){return B.contentWindow.location.host});if(F&&F==window.location.host){var H=new Window(B.contentWindow);var G=new Document(B.contentWindow.document);$extend(H.Element.prototype,Element.Prototype)}D.call(B.contentWindow,B.contentWindow.document)};(!window.frames[C.id])?B.addListener("load",A):A();return B}});var Elements=new Native({initialize:function(F,B){B=$extend({ddup:true,cash:true},B);F=F||[];if(B.ddup||B.cash){var G={},E=[];for(var C=0,A=F.length;C<A;C++){var D=$.element(F[C],!B.cash);if(B.ddup){if(G[D.uid]){continue}G[D.uid]=true}E.push(D)}F=E}return(B.cash)?$extend(F,this):F}});Elements.implement({filter:function(A,B){if(!A){return this}return new Elements(Array.filter(this,(typeof A=="string")?function(C){return C.match(A)}:A,B))}});Elements.multi=function(A){return function(){var B=[];var F=true;for(var D=0,C=this.length;D<C;D++){var E=this[D][A].apply(this[D],arguments);B.push(E);if(F){F=($type(E)=="element")}}return(F)?new Elements(B):B}};Window.implement({$:function(B,C){if(B&&B.$family&&B.uid){return B}var A=$type(B);return($[A])?$[A](B,C,this.document):null},$$:function(A){if(arguments.length==1&&typeof A=="string"){return this.document.getElements(A)}var F=[];var C=Array.flatten(arguments);for(var D=0,B=C.length;D<B;D++){var E=C[D];switch($type(E)){case"element":E=[E];break;case"string":E=this.document.getElements(E,true);break;default:E=false}if(E){F.extend(E)}}return new Elements(F)},getDocument:function(){return this.document},getWindow:function(){return this}});$.string=function(C,B,A){C=A.getElementById(C);return(C)?$.element(C,B):null};$.element=function(A,D){$uid(A);if(!D&&!A.$family&&!(/^object|embed$/i).test(A.tagName)){var B=Element.Prototype;for(var C in B){A[C]=B[C]}}return A};$.object=function(B,C,A){if(B.toElement){return $.element(B.toElement(A),C)}return null};$.textnode=$.whitespace=$.window=$.document=$arguments(0);Native.implement([Element,Document],{getElement:function(A,B){return $(this.getElements(A,true)[0]||null,B)},getElements:function(A,D){A=A.split(",");var C=[];var B=(A.length>1);A.each(function(E){var F=this.getElementsByTagName(E.trim());(B)?C.extend(F):C=F},this);return new Elements(C,{ddup:B,cash:!D})}});Element.Storage={get:function(A){return(this[A]||(this[A]={}))}};Element.Inserters=new Hash({before:function(B,A){if(A.parentNode){A.parentNode.insertBefore(B,A)}},after:function(B,A){if(!A.parentNode){return }var C=A.nextSibling;(C)?A.parentNode.insertBefore(B,C):A.parentNode.appendChild(B)},bottom:function(B,A){A.appendChild(B)},top:function(B,A){var C=A.firstChild;(C)?A.insertBefore(B,C):A.appendChild(B)}});Element.Inserters.inside=Element.Inserters.bottom;Element.Inserters.each(function(C,B){var A=B.capitalize();Element.implement("inject"+A,function(D){C(this,$(D,true));return this});Element.implement("grab"+A,function(D){C($(D,true),this);return this})});Element.implement({getDocument:function(){return this.ownerDocument},getWindow:function(){return this.ownerDocument.getWindow()},getElementById:function(D,C){var B=this.ownerDocument.getElementById(D);if(!B){return null}for(var A=B.parentNode;A!=this;A=A.parentNode){if(!A){return null}}return $.element(B,C)},set:function(D,B){switch($type(D)){case"object":for(var C in D){this.set(C,D[C])}break;case"string":var A=Element.Properties.get(D);(A&&A.set)?A.set.apply(this,Array.slice(arguments,1)):this.setProperty(D,B)}return this},get:function(B){var A=Element.Properties.get(B);return(A&&A.get)?A.get.apply(this,Array.slice(arguments,1)):this.getProperty(B)},erase:function(B){var A=Element.Properties.get(B);(A&&A.erase)?A.erase.apply(this,Array.slice(arguments,1)):this.removeProperty(B);return this},match:function(A){return(!A||Element.get(this,"tag")==A)},inject:function(B,A){Element.Inserters.get(A||"bottom")(this,$(B,true));return this},wraps:function(B,A){B=$(B,true);return this.replaces(B).grab(B,A)},grab:function(B,A){Element.Inserters.get(A||"bottom")($(B,true),this);return this},appendText:function(B,A){return this.grab(this.getDocument().newTextNode(B),A)},adopt:function(){Array.flatten(arguments).each(function(A){A=$(A,true);if(A){this.appendChild(A)}},this);return this},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this},clone:function(D,C){switch($type(this)){case"element":var H={};for(var G=0,E=this.attributes.length;G<E;G++){var B=this.attributes[G],L=B.nodeName.toLowerCase();if(Browser.Engine.trident&&(/input/i).test(this.tagName)&&(/width|height/).test(L)){continue}var K=(L=="style"&&this.style)?this.style.cssText:B.nodeValue;if(!$chk(K)||L=="uid"||(L=="id"&&!C)){continue}if(K!="inherit"&&["string","number"].contains($type(K))){H[L]=K}}var J=new Element(this.nodeName.toLowerCase(),H);if(D!==false){for(var I=0,F=this.childNodes.length;I<F;I++){var A=Element.clone(this.childNodes[I],true,C);if(A){J.grab(A)}}}return J;case"textnode":return document.newTextNode(this.nodeValue)}return null},replaces:function(A){A=$(A,true);A.parentNode.replaceChild(this,A);return this},hasClass:function(A){return this.className.contains(A," ")},addClass:function(A){if(!this.hasClass(A)){this.className=(this.className+" "+A).clean()}return this},removeClass:function(A){this.className=this.className.replace(new RegExp("(^|\\s)"+A+"(?:\\s|$)"),"$1").clean();return this},toggleClass:function(A){return this.hasClass(A)?this.removeClass(A):this.addClass(A)},getComputedStyle:function(B){if(this.currentStyle){return this.currentStyle[B.camelCase()]}var A=this.getWindow().getComputedStyle(this,null);return(A)?A.getPropertyValue([B.hyphenate()]):null},empty:function(){$A(this.childNodes).each(function(A){Browser.freeMem(A);Element.empty(A);Element.dispose(A)},this);return this},destroy:function(){Browser.freeMem(this.empty().dispose());return null},getSelected:function(){return new Elements($A(this.options).filter(function(A){return A.selected}))},toQueryString:function(){var A=[];this.getElements("input, select, textarea").each(function(B){if(!B.name||B.disabled){return }var C=(B.tagName.toLowerCase()=="select")?Element.getSelected(B).map(function(D){return D.value}):((B.type=="radio"||B.type=="checkbox")&&!B.checked)?null:B.value;$splat(C).each(function(D){if(D){A.push(B.name+"="+encodeURIComponent(D))}})});return A.join("&")},getProperty:function(C){var B=Element.Attributes,A=B.Props[C];var D=(A)?this[A]:this.getAttribute(C,2);return(B.Bools[C])?!!D:(A)?D:D||null},getProperties:function(){var A=$A(arguments);return A.map(function(B){return this.getProperty(B)},this).associate(A)},setProperty:function(D,E){var C=Element.Attributes,B=C.Props[D],A=$defined(E);if(B&&C.Bools[D]){E=(E||!A)?true:false}else{if(!A){return this.removeProperty(D)}}(B)?this[B]=E:this.setAttribute(D,E);return this},setProperties:function(A){for(var B in A){this.setProperty(B,A[B])}return this},removeProperty:function(D){var C=Element.Attributes,B=C.Props[D],A=(B&&C.Bools[D]);(B)?this[B]=(A)?false:"":this.removeAttribute(D);return this},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this}});(function(){var A=function(D,B,I,C,F,H){var E=D[I||B];var G=[];while(E){if(E.nodeType==1&&(!C||Element.match(E,C))){G.push(E);if(!F){break}}E=E[B]}return(F)?new Elements(G,{ddup:false,cash:!H}):$(G[0],H)};Element.implement({getPrevious:function(B,C){return A(this,"previousSibling",null,B,false,C)},getAllPrevious:function(B,C){return A(this,"previousSibling",null,B,true,C)},getNext:function(B,C){return A(this,"nextSibling",null,B,false,C)},getAllNext:function(B,C){return A(this,"nextSibling",null,B,true,C)},getFirst:function(B,C){return A(this,"nextSibling","firstChild",B,false,C)},getLast:function(B,C){return A(this,"previousSibling","lastChild",B,false,C)},getParent:function(B,C){return A(this,"parentNode",null,B,false,C)},getParents:function(B,C){return A(this,"parentNode",null,B,true,C)},getChildren:function(B,C){return A(this,"nextSibling","firstChild",B,true,C)},hasChild:function(B){B=$(B,true);return(!!B&&$A(this.getElementsByTagName(B.tagName)).contains(B))}})})();Element.Properties=new Hash;Element.Properties.style={set:function(A){this.style.cssText=A},get:function(){return this.style.cssText},erase:function(){this.style.cssText=""}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase()}};Element.Properties.href={get:function(){return(!this.href)?null:this.href.replace(new RegExp("^"+document.location.protocol+"//"+document.location.host),"")}};Element.Properties.html={set:function(){return this.innerHTML=Array.flatten(arguments).join("")}};Native.implement([Element,Window,Document],{addListener:function(B,A){if(this.addEventListener){this.addEventListener(B,A,false)}else{this.attachEvent("on"+B,A)}return this},removeListener:function(B,A){if(this.removeEventListener){this.removeEventListener(B,A,false)}else{this.detachEvent("on"+B,A)}return this},retrieve:function(B,A){var D=Element.Storage.get(this.uid);var C=D[B];if($defined(A)&&!$defined(C)){C=D[B]=A}return $pick(C)},store:function(B,A){var C=Element.Storage.get(this.uid);C[B]=A;return this},eliminate:function(A){var B=Element.Storage.get(this.uid);delete B[A];return this}});Element.Attributes=new Hash({Props:{html:"innerHTML","class":"className","for":"htmlFor",text:(Browser.Engine.trident)?"innerText":"textContent"},Bools:["compact","nowrap","ismap","declare","noshade","checked","disabled","readonly","multiple","selected","noresize","defer"],Camels:["value","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"]});Browser.freeMem=function(A){if(!A){return }if(Browser.Engine.trident&&(/object/i).test(A.tagName)){for(var B in A){if(typeof A[B]=="function"){A[B]=$empty}}Element.dispose(A)}if(A.uid&&A.removeEvents){A.removeEvents()}};(function(B){var C=B.Bools,A=B.Camels;B.Bools=C=C.associate(C);Hash.extend(Hash.combine(B.Props,C),A.associate(A.map(function(D){return D.toLowerCase()})));B.erase("Camels")})(Element.Attributes);window.addListener("unload",function(){window.removeListener("unload",arguments.callee);document.purge();if(Browser.Engine.trident){CollectGarbage()}});Element.Properties.events={set:function(A){this.addEvents(A)}};Native.implement([Element,Window,Document],{addEvent:function(E,G){var H=this.retrieve("events",{});H[E]=H[E]||{keys:[],values:[]};if(H[E].keys.contains(G)){return this}H[E].keys.push(G);var F=E,A=Element.Events.get(E),C=G,I=this;if(A){if(A.onAdd){A.onAdd.call(this,G)}if(A.condition){C=function(J){if(A.condition.call(this,J)){return G.call(this,J)}return false}}F=A.base||F}var D=function(){return G.call(I)};var B=Element.NativeEvents[F]||0;if(B){if(B==2){D=function(J){J=new Event(J,I.getWindow());if(C.call(I,J)===false){J.stop()}}}this.addListener(F,D)}H[E].values.push(D);return this},removeEvent:function(D,C){var B=this.retrieve("events");if(!B||!B[D]){return this}var G=B[D].keys.indexOf(C);if(G==-1){return this}var A=B[D].keys.splice(G,1)[0];var F=B[D].values.splice(G,1)[0];var E=Element.Events.get(D);if(E){if(E.onRemove){E.onRemove.call(this,C)}D=E.base||D}return(Element.NativeEvents[D])?this.removeListener(D,F):this},addEvents:function(A){for(var B in A){this.addEvent(B,A[B])}return this},removeEvents:function(B){var A=this.retrieve("events");if(!A){return this}if(!B){for(var C in A){this.removeEvents(C)}A=null}else{if(A[B]){while(A[B].keys[0]){this.removeEvent(B,A[B].keys[0])}A[B]=null}}return this},fireEvent:function(D,B,A){var C=this.retrieve("events");if(!C||!C[D]){return this}C[D].keys.each(function(E){E.create({bind:this,delay:A,"arguments":B})()},this);return this},cloneEvents:function(D,A){D=$(D);var C=D.retrieve("events");if(!C){return this}if(!A){for(var B in C){this.cloneEvents(D,B)}}else{if(C[A]){C[A].keys.each(function(E){this.addEvent(A,E)},this)}}return this}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};(function(){var A=function(B){var C=B.relatedTarget;if(C==undefined){return true}if(C===false){return false}return($type(this)!="document"&&C!=this&&C.prefix!="xul"&&!this.hasChild(C))};Element.Events=new Hash({mouseenter:{base:"mouseover",condition:A},mouseleave:{base:"mouseout",condition:A},mousewheel:{base:(Browser.Engine.gecko)?"DOMMouseScroll":"mousewheel"}})})();Element.Properties.styles={set:function(A){this.setStyles(A)}};Element.Properties.opacity={set:function(A,B){if(!B){if(A==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden"}}else{if(this.style.visibility!="visible"){this.style.visibility="visible"}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1}if(Browser.Engine.trident){this.style.filter=(A==1)?"":"alpha(opacity="+A*100+")"}this.style.opacity=A;this.store("opacity",A)},get:function(){return this.retrieve("opacity",1)}};Element.implement({setOpacity:function(A){return this.set("opacity",A,true)},getOpacity:function(){return this.get("opacity")},setStyle:function(B,A){switch(B){case"opacity":return this.set("opacity",parseFloat(A));case"float":B=(Browser.Engine.trident)?"styleFloat":"cssFloat"}B=B.camelCase();if($type(A)!="string"){var C=(Element.Styles.get(B)||"@").split(" ");A=$splat(A).map(function(E,D){if(!C[D]){return""}return($type(E)=="number")?C[D].replace("@",Math.round(E)):E}).join(" ")}else{if(A==String(Number(A))){A=Math.round(A)}}this.style[B]=A;return this},getStyle:function(G){switch(G){case"opacity":return this.get("opacity");case"float":G=(Browser.Engine.trident)?"styleFloat":"cssFloat"}G=G.camelCase();var A=this.style[G];if(!$chk(A)){A=[];for(var F in Element.ShortStyles){if(G!=F){continue}for(var E in Element.ShortStyles[F]){A.push(this.getStyle(E))}return A.join(" ")}A=this.getComputedStyle(G)}if(A){A=String(A);var C=A.match(/rgba?\([\d\s,]+\)/);if(C){A=A.replace(C[0],C[0].rgbToHex())}}if(Browser.Engine.presto||(Browser.Engine.trident&&!$chk(parseInt(A)))){if(G.test(/^(height|width)$/)){var B=(G=="width")?["left","right"]:["top","bottom"],D=0;B.each(function(H){D+=this.getStyle("border-"+H+"-width").toInt()+this.getStyle("padding-"+H).toInt()},this);return this["offset"+G.capitalize()]-D+"px"}if(Browser.Engine.presto&&String(A).test("px")){return A}if(G.test(/(border(.+)Width|margin|padding)/)){return"0px"}}return A},setStyles:function(B){for(var A in B){this.setStyle(A,B[A])}return this},getStyles:function(){var A={};Array.each(arguments,function(B){A[B]=this.getStyle(B)},this);return A}});Element.Styles=new Hash({left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"});Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(G){var F=Element.ShortStyles;var B=Element.Styles;["margin","padding"].each(function(H){var I=H+G;F[H][I]=B[I]="@px"});var E="border"+G;F.border[E]=B[E]="@px @ rgb(@, @, @)";var D=E+"Width",A=E+"Style",C=E+"Color";F[E]={};F.borderWidth[D]=F[E][D]=B[D]="@px";F.borderStyle[A]=F[E][A]=B[A]="@";F.borderColor[C]=F[E][C]=B[C]="rgb(@, @, @)"});(function(){Element.implement({scrollTo:function(H,I){if(B(this)){this.getWindow().scrollTo(H,I)}else{this.scrollLeft=H;this.scrollTop=I}return this},getSize:function(){if(B(this)){return this.getWindow().getSize()}return{x:this.offsetWidth,y:this.offsetHeight}},getScrollSize:function(){if(B(this)){return this.getWindow().getScrollSize()}return{x:this.scrollWidth,y:this.scrollHeight}},getScroll:function(){if(B(this)){return this.getWindow().getScroll()}return{x:this.scrollLeft,y:this.scrollTop}},getScrolls:function(){var I=this,H={x:0,y:0};while(I&&!B(I)){H.x+=I.scrollLeft;H.y+=I.scrollTop;I=I.parentNode}return H},getOffsetParent:function(){var H=this;if(B(H)){return null}if(!Browser.Engine.trident){return H.offsetParent}while((H=H.parentNode)&&!B(H)){if(D(H,"position")!="static"){return H}}return null},getOffsets:function(){var I=this,H={x:0,y:0};if(B(this)){return H}while(I&&!B(I)){H.x+=I.offsetLeft;H.y+=I.offsetTop;if(Browser.Engine.gecko){if(!F(I)){H.x+=C(I);H.y+=G(I)}var J=I.parentNode;if(J&&D(J,"overflow")!="visible"){H.x+=C(J);H.y+=G(J)}}else{if(I!=this&&(Browser.Engine.trident||Browser.Engine.webkit)){H.x+=C(I);H.y+=G(I)}}I=I.offsetParent;if(Browser.Engine.trident){while(I&&!I.currentStyle.hasLayout){I=I.offsetParent}}}if(Browser.Engine.gecko&&!F(this)){H.x-=C(this);H.y-=G(this)}return H},getPosition:function(K){if(B(this)){return{x:0,y:0}}var L=this.getOffsets(),I=this.getScrolls();var H={x:L.x-I.x,y:L.y-I.y};var J=(K&&(K=$(K)))?K.getPosition():{x:0,y:0};return{x:H.x-J.x,y:H.y-J.y}},getCoordinates:function(J){if(B(this)){return this.getWindow().getCoordinates()}var H=this.getPosition(J),I=this.getSize();var K={left:H.x,top:H.y,width:I.x,height:I.y};K.right=K.left+K.width;K.bottom=K.top+K.height;return K},computePosition:function(H){return{left:H.x-E(this,"margin-left"),top:H.y-E(this,"margin-top")}},position:function(H){return this.setStyles(this.computePosition(H))}});Native.implement([Document,Window],{getSize:function(){var I=this.getWindow();if(Browser.Engine.presto||Browser.Engine.webkit){return{x:I.innerWidth,y:I.innerHeight}}var H=A(this);return{x:H.clientWidth,y:H.clientHeight}},getScroll:function(){var I=this.getWindow();var H=A(this);return{x:I.pageXOffset||H.scrollLeft,y:I.pageYOffset||H.scrollTop}},getScrollSize:function(){var I=A(this);var H=this.getSize();return{x:Math.max(I.scrollWidth,H.x),y:Math.max(I.scrollHeight,H.y)}},getPosition:function(){return{x:0,y:0}},getCoordinates:function(){var H=this.getSize();return{top:0,left:0,bottom:H.y,right:H.x,height:H.y,width:H.x}}});var D=Element.getComputedStyle;function E(H,I){return D(H,I).toInt()||0}function F(H){return D(H,"-moz-box-sizing")=="border-box"}function G(H){return E(H,"border-top-width")}function C(H){return E(H,"border-left-width")}function B(H){return(/^(?:body|html)$/i).test(H.tagName)}function A(H){var I=H.getDocument();return(!I.compatMode||I.compatMode=="CSS1Compat")?I.html:I.body}})();Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y},getWidth:function(){return this.getSize().x},getScrollTop:function(){return this.getScroll().y},getScrollLeft:function(){return this.getScroll().x},getScrollHeight:function(){return this.getScrollSize().y},getScrollWidth:function(){return this.getScrollSize().x},getTop:function(){return this.getPosition().y},getLeft:function(){return this.getPosition().x}});Native.implement([Document,Element],{getElements:function(H,G){H=H.split(",");var C,E={};for(var D=0,B=H.length;D<B;D++){var A=H[D],F=Selectors.Utils.search(this,A,E);if(D!=0&&F.item){F=$A(F)}C=(D==0)?F:(C.item)?$A(C).concat(F):C.concat(F)}return new Elements(C,{ddup:(H.length>1),cash:!G})}});Element.implement({match:function(B){if(!B){return true}var D=Selectors.Utils.parseTagAndID(B);var A=D[0],E=D[1];if(!Selectors.Filters.byID(this,E)||!Selectors.Filters.byTag(this,A)){return false}var C=Selectors.Utils.parseSelector(B);return(C)?Selectors.Utils.filter(this,C,{}):true}});var Selectors={Cache:{nth:{},parsed:{}}};Selectors.RegExps={id:(/#([\w-]+)/),tag:(/^(\w+|\*)/),quick:(/^(\w+|\*)$/),splitter:(/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),combined:(/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)};Selectors.Utils={chk:function(B,C){if(!C){return true}var A=$uid(B);if(!C[A]){return C[A]=true}return false},parseNthArgument:function(F){if(Selectors.Cache.nth[F]){return Selectors.Cache.nth[F]}var C=F.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);if(!C){return false}var E=parseInt(C[1]);var B=(E||E===0)?E:1;var D=C[2]||false;var A=parseInt(C[3])||0;if(B!=0){A--;while(A<1){A+=B}while(A>=B){A-=B}}else{B=A;D="index"}switch(D){case"n":C={a:B,b:A,special:"n"};break;case"odd":C={a:2,b:0,special:"n"};break;case"even":C={a:2,b:1,special:"n"};break;case"first":C={a:0,special:"index"};break;case"last":C={special:"last-child"};break;case"only":C={special:"only-child"};break;default:C={a:(B-1),special:"index"}}return Selectors.Cache.nth[F]=C},parseSelector:function(E){if(Selectors.Cache.parsed[E]){return Selectors.Cache.parsed[E]}var D,H={classes:[],pseudos:[],attributes:[]};while((D=Selectors.RegExps.combined.exec(E))){var I=D[1],G=D[2],F=D[3],B=D[4],C=D[5],J=D[6];if(I){H.classes.push(I)}else{if(C){var A=Selectors.Pseudo.get(C);if(A){H.pseudos.push({parser:A,argument:J})}else{H.attributes.push({name:C,operator:"=",value:J})}}else{if(G){H.attributes.push({name:G,operator:F,value:B})}}}}if(!H.classes.length){delete H.classes}if(!H.attributes.length){delete H.attributes}if(!H.pseudos.length){delete H.pseudos}if(!H.classes&&!H.attributes&&!H.pseudos){H=null}return Selectors.Cache.parsed[E]=H},parseTagAndID:function(B){var A=B.match(Selectors.RegExps.tag);var C=B.match(Selectors.RegExps.id);return[(A)?A[1]:"*",(C)?C[1]:false]},filter:function(F,C,E){var D;if(C.classes){for(D=C.classes.length;D--;D){var G=C.classes[D];if(!Selectors.Filters.byClass(F,G)){return false}}}if(C.attributes){for(D=C.attributes.length;D--;D){var B=C.attributes[D];if(!Selectors.Filters.byAttribute(F,B.name,B.operator,B.value)){return false}}}if(C.pseudos){for(D=C.pseudos.length;D--;D){var A=C.pseudos[D];if(!Selectors.Filters.byPseudo(F,A.parser,A.argument,E)){return false}}}return true},getByTagAndID:function(B,A,D){if(D){var C=(B.getElementById)?B.getElementById(D,true):Element.getElementById(B,D,true);return(C&&Selectors.Filters.byTag(C,A))?[C]:[]}else{return B.getElementsByTagName(A)}},search:function(J,I,O){var B=[];var C=I.trim().replace(Selectors.RegExps.splitter,function(Z,Y,X){B.push(Y);return":)"+X}).split(":)");var K,F,E,V;for(var U=0,Q=C.length;U<Q;U++){var T=C[U];if(U==0&&Selectors.RegExps.quick.test(T)){K=J.getElementsByTagName(T);continue}var A=B[U-1];var L=Selectors.Utils.parseTagAndID(T);var W=L[0],M=L[1];if(U==0){K=Selectors.Utils.getByTagAndID(J,W,M)}else{var D={},H=[];for(var S=0,R=K.length;S<R;S++){H=Selectors.Getters[A](H,K[S],W,M,D)}K=H}var G=Selectors.Utils.parseSelector(T);if(G){E=[];for(var P=0,N=K.length;P<N;P++){V=K[P];if(Selectors.Utils.filter(V,G,O)){E.push(V)}}K=E}}return K}};Selectors.Getters={" ":function(H,G,I,A,E){var D=Selectors.Utils.getByTagAndID(G,I,A);for(var C=0,B=D.length;C<B;C++){var F=D[C];if(Selectors.Utils.chk(F,E)){H.push(F)}}return H},">":function(H,G,I,A,F){var C=Selectors.Utils.getByTagAndID(G,I,A);for(var E=0,D=C.length;E<D;E++){var B=C[E];if(B.parentNode==G&&Selectors.Utils.chk(B,F)){H.push(B)}}return H},"+":function(C,B,A,E,D){while((B=B.nextSibling)){if(B.nodeType==1){if(Selectors.Utils.chk(B,D)&&Selectors.Filters.byTag(B,A)&&Selectors.Filters.byID(B,E)){C.push(B)}break}}return C},"~":function(C,B,A,E,D){while((B=B.nextSibling)){if(B.nodeType==1){if(!Selectors.Utils.chk(B,D)){break}if(Selectors.Filters.byTag(B,A)&&Selectors.Filters.byID(B,E)){C.push(B)}}}return C}};Selectors.Filters={byTag:function(B,A){return(A=="*"||(B.tagName&&B.tagName.toLowerCase()==A))},byID:function(A,B){return(!B||(A.id&&A.id==B))},byClass:function(B,A){return(B.className&&B.className.contains(A," "))},byPseudo:function(A,D,C,B){return D.call(A,C,B)},byAttribute:function(C,D,B,E){var A=Element.prototype.getProperty.call(C,D);if(!A){return false}if(!B||E==undefined){return true}switch(B){case"=":return(A==E);case"*=":return(A.contains(E));case"^=":return(A.substr(0,E.length)==E);case"$=":return(A.substr(A.length-E.length)==E);case"!=":return(A!=E);case"~=":return A.contains(E," ");case"|=":return A.contains(E,"-")}return false}};Selectors.Pseudo=new Hash({empty:function(){return !(this.innerText||this.textContent||"").length},not:function(A){return !Element.match(this,A)},contains:function(A){return(this.innerText||this.textContent||"").contains(A)},"first-child":function(){return Selectors.Pseudo.index.call(this,0)},"last-child":function(){var A=this;while((A=A.nextSibling)){if(A.nodeType==1){return false}}return true},"only-child":function(){var B=this;while((B=B.previousSibling)){if(B.nodeType==1){return false}}var A=this;while((A=A.nextSibling)){if(A.nodeType==1){return false}}return true},"nth-child":function(G,E){G=(G==undefined)?"n":G;var C=Selectors.Utils.parseNthArgument(G);if(C.special!="n"){return Selectors.Pseudo[C.special].call(this,C.a,E)}var F=0;E.positions=E.positions||{};var D=$uid(this);if(!E.positions[D]){var B=this;while((B=B.previousSibling)){if(B.nodeType!=1){continue}F++;var A=E.positions[$uid(B)];if(A!=undefined){F=A+F;break}}E.positions[D]=F}return(E.positions[D]%C.a==C.b)},index:function(A){var B=this,C=0;while((B=B.previousSibling)){if(B.nodeType==1&&++C>A){return false}}return(C==A)},even:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n+1",A)},odd:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n",A)}});Element.Events.domready={onAdd:function(A){if(Browser.loaded){A.call(this)}}};(function(){var B=function(){if(Browser.loaded){return }Browser.loaded=true;window.fireEvent("domready");document.fireEvent("domready")};switch(Browser.Engine.name){case"webkit":(function(){(["loaded","complete"].contains(document.readyState))?B():arguments.callee.delay(50)})();break;case"trident":var A=document.createElement("div");(function(){($try(function(){A.doScroll("left");return $(A).inject(document.body).set("html","temp").dispose()}))?B():arguments.callee.delay(50)})();break;default:window.addEvent("load",B);document.addEvent("DOMContentLoaded",B)}})();var JSON=new Hash({encode:function(B){switch($type(B)){case"string":return'"'+B.replace(/[\x00-\x1f\\"]/g,JSON.$replaceChars)+'"';case"array":return"["+String(B.map(JSON.encode).filter($defined))+"]";case"object":case"hash":var A=[];Hash.each(B,function(E,D){var C=JSON.encode(E);if(C){A.push(JSON.encode(D)+":"+C)}});return"{"+A+"}";case"number":case"boolean":return String(B);case false:return"null"}return null},$specialChars:{"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},$replaceChars:function(A){return JSON.$specialChars[A]||"\\u00"+Math.floor(A.charCodeAt()/16).toString(16)+(A.charCodeAt()%16).toString(16)},decode:function(string,secure){if($type(string)!="string"||!string.length){return null}if(secure&&!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g,"@").replace(/"[^"\\\n\r]*"/g,""))){return null}return eval("("+string+")")}});Native.implement([Hash,Array,String,Number],{toJSON:function(){return JSON.encode(this)}});var Cookie=new Class({Implements:Options,options:{path:false,domain:false,duration:false,secure:false,document:document},initialize:function(B,A){this.key=B;this.setOptions(A)},write:function(B){B=encodeURIComponent(B);if(this.options.domain){B+="; domain="+this.options.domain}if(this.options.path){B+="; path="+this.options.path}if(this.options.duration){var A=new Date();A.setTime(A.getTime()+this.options.duration*24*60*60*1000);B+="; expires="+A.toGMTString()}if(this.options.secure){B+="; secure"}this.options.document.cookie=this.key+"="+B;return this},read:function(){var A=this.options.document.cookie.match("(?:^|;)\\s*"+this.key.escapeRegExp()+"=([^;]*)");return(A)?decodeURIComponent(A[1]):null},dispose:function(){new Cookie(this.key,$merge(this.options,{duration:-1})).write("");return this}});Cookie.write=function(B,C,A){return new Cookie(B,A).write(C)};Cookie.read=function(A){return new Cookie(A).read()};Cookie.dispose=function(B,A){return new Cookie(B,A).dispose()};var Swiff=new Class({Implements:[Options],options:{id:null,height:1,width:1,container:null,properties:{},params:{quality:"high",allowScriptAccess:"always",wMode:"transparent",swLiveConnect:true},callBacks:{},vars:{}},toElement:function(){return this.object},initialize:function(L,M){this.instance="Swiff_"+$time();this.setOptions(M);M=this.options;var B=this.id=M.id||this.instance;var A=$(M.container);Swiff.CallBacks[this.instance]={};var E=M.params,G=M.vars,F=M.callBacks;var H=$extend({height:M.height,width:M.width},M.properties);var K=this;for(var D in F){Swiff.CallBacks[this.instance][D]=(function(N){return function(){return N.apply(K.object,arguments)}})(F[D]);G[D]="Swiff.CallBacks."+this.instance+"."+D}E.flashVars=Hash.toQueryString(G);if(Browser.Engine.trident){H.classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";E.movie=L}else{H.type="application/x-shockwave-flash";H.data=L}var J='<object id="'+B+'"';for(var I in H){J+=" "+I+'="'+H[I]+'"'}J+=">";for(var C in E){if(E[C]){J+='<param name="'+C+'" value="'+E[C]+'" />'}}J+="</object>";this.object=((A)?A.empty():new Element("div")).set("html",J).firstChild},replaces:function(A){A=$(A,true);A.parentNode.replaceChild(this.toElement(),A);return this},inject:function(A){$(A,true).appendChild(this.toElement());return this},remote:function(){return Swiff.remote.apply(Swiff,[this.toElement()].extend(arguments))}});Swiff.CallBacks={};Swiff.remote=function(obj,fn){var rs=obj.CallFunction('<invoke name="'+fn+'" returntype="javascript">'+__flash__argumentsToXML(arguments,2)+"</invoke>");return eval(rs)};var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:"ignore",transition:function(A){return -(Math.cos(Math.PI*A)-1)/2}},initialize:function(A){this.subject=this.subject||this;this.setOptions(A);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();var B=this.options.wait;if(B===false){this.options.link="cancel"}},step:function(){var A=$time();if(A<this.time+this.options.duration){var B=this.options.transition((A-this.time)/this.options.duration);this.set(this.compute(this.from,this.to,B))}else{this.set(this.compute(this.from,this.to,1));this.complete()}},set:function(A){return A},compute:function(C,B,A){return Fx.compute(C,B,A)},check:function(A){if(!this.timer){return true}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));return false}return false},start:function(B,A){if(!this.check(arguments.callee,B,A)){return this}this.from=B;this.to=A;this.time=0;this.startTimer();this.onStart();return this},complete:function(){if(this.stopTimer()){this.onComplete()}return this},cancel:function(){if(this.stopTimer()){this.onCancel()}return this},onStart:function(){this.fireEvent("start",this.subject)},onComplete:function(){this.fireEvent("complete",this.subject);if(!this.callChain()){this.fireEvent("chainComplete",this.subject)}},onCancel:function(){this.fireEvent("cancel",this.subject).clearChain()},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=$time()-this.time;this.timer=$clear(this.timer);return true},startTimer:function(){if(this.timer){return false}this.time=$time()-this.time;this.timer=this.step.periodical(Math.round(1000/this.options.fps),this);return true}});Fx.compute=function(C,B,A){return(B-C)*A+C};Fx.Durations={"short":250,normal:500,"long":1000};Fx.CSS=new Class({Extends:Fx,prepare:function(D,E,B){B=$splat(B);var C=B[1];if(!$chk(C)){B[1]=B[0];B[0]=D.getStyle(E)}var A=B.map(this.parse);return{from:A[0],to:A[1]}},parse:function(A){A=$lambda(A)();A=(typeof A=="string")?A.split(" "):$splat(A);return A.map(function(C){C=String(C);var B=false;Fx.CSS.Parsers.each(function(F,E){if(B){return }var D=F.parse(C);if($chk(D)){B={value:D,parser:F}}});B=B||{value:C,parser:Fx.CSS.Parsers.String};return B})},compute:function(D,C,B){var A=[];(Math.min(D.length,C.length)).times(function(E){A.push({value:D[E].parser.compute(D[E].value,C[E].value,B),parser:D[E].parser})});A.$family={name:"fx:css:value"};return A},serve:function(C,B){if($type(C)!="fx:css:value"){C=this.parse(C)}var A=[];C.each(function(D){A=A.concat(D.parser.serve(D.value,B))});return A},render:function(A,D,C,B){A.setStyle(D,this.serve(C,B))},search:function(A){if(Fx.CSS.Cache[A]){return Fx.CSS.Cache[A]}var B={};Array.each(document.styleSheets,function(E,D){var C=E.href;if(C&&C.contains("://")&&!C.contains(document.domain)){return }var F=E.rules||E.cssRules;Array.each(F,function(I,G){if(!I.style){return }var H=(I.selectorText)?I.selectorText.replace(/^\w+/,function(J){return J.toLowerCase()}):null;if(!H||!H.test("^"+A+"$")){return }Element.Styles.each(function(K,J){if(!I.style[J]||Element.ShortStyles[J]){return }K=String(I.style[J]);B[J]=(K.test(/^rgb/))?K.rgbToHex():K})})});return Fx.CSS.Cache[A]=B}});Fx.CSS.Cache={};Fx.CSS.Parsers=new Hash({Color:{parse:function(A){if(A.match(/^#[0-9a-f]{3,6}$/i)){return A.hexToRgb(true)}return((A=A.match(/(\d+),\s*(\d+),\s*(\d+)/)))?[A[1],A[2],A[3]]:false},compute:function(C,B,A){return C.map(function(E,D){return Math.round(Fx.compute(C[D],B[D],A))})},serve:function(A){return A.map(Number)}},Number:{parse:parseFloat,compute:Fx.compute,serve:function(B,A){return(A)?B+A:B}},String:{parse:$lambda(false),compute:$arguments(1),serve:$arguments(0)}});Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A)},set:function(B,A){if(arguments.length==1){A=B;B=this.property||this.options.property}this.render(this.element,B,A,this.options.unit);return this},start:function(C,E,D){if(!this.check(arguments.callee,C,E,D)){return this}var B=Array.flatten(arguments);this.property=this.options.property||B.shift();var A=this.prepare(this.element,this.property,B);return this.parent(A.from,A.to)}});Element.Properties.tween={set:function(A){var B=this.retrieve("tween");if(B){B.cancel()}return this.eliminate("tween").store("tween:options",$extend({link:"cancel"},A))},get:function(A){if(A||!this.retrieve("tween")){if(A||!this.retrieve("tween:options")){this.set("tween",A)}this.store("tween",new Fx.Tween(this,this.retrieve("tween:options")))}return this.retrieve("tween")}};Element.implement({tween:function(A,C,B){this.get("tween").start(arguments);return this},fade:function(C){var E=this.get("tween"),D="opacity",A;C=$pick(C,"toggle");switch(C){case"in":E.start(D,1);break;case"out":E.start(D,0);break;case"show":E.set(D,1);break;case"hide":E.set(D,0);break;case"toggle":var B=this.retrieve("fade:flag",this.get("opacity")==1);E.start(D,(B)?0:1);this.store("fade:flag",!B);A=true;break;default:E.start(D,arguments)}if(!A){this.eliminate("fade:flag")}return this},highlight:function(C,A){if(!A){A=this.retrieve("highlight:original",this.getStyle("background-color"));A=(A=="transparent")?"#fff":A}var B=this.get("tween");B.start("background-color",C||"#ffff88",A).chain(function(){this.setStyle("background-color",this.retrieve("highlight:original"));B.callChain()}.bind(this));return this}});Fx.Morph=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A)},set:function(A){if(typeof A=="string"){A=this.search(A)}for(var B in A){this.render(this.element,B,A[B],this.options.unit)}return this},compute:function(E,D,C){var A={};for(var B in E){A[B]=this.parent(E[B],D[B],C)}return A},start:function(B){if(!this.check(arguments.callee,B)){return this}if(typeof B=="string"){B=this.search(B)}var E={},D={};for(var C in B){var A=this.prepare(this.element,C,B[C]);E[C]=A.from;D[C]=A.to}return this.parent(E,D)}});Element.Properties.morph={set:function(A){var B=this.retrieve("morph");if(B){B.cancel()}return this.eliminate("morph").store("morph:options",$extend({link:"cancel"},A))},get:function(A){if(A||!this.retrieve("morph")){if(A||!this.retrieve("morph:options")){this.set("morph",A)}this.store("morph",new Fx.Morph(this,this.retrieve("morph:options")))}return this.retrieve("morph")}};Element.implement({morph:function(A){this.get("morph").start(A);return this}});(function(){var A=Fx.prototype.initialize;Fx.prototype.initialize=function(B){A.call(this,B);var C=this.options.transition;if(typeof C=="string"&&(C=C.split(":"))){var D=Fx.Transitions;D=D[C[0]]||D[C[0].capitalize()];if(C[1]){D=D["ease"+C[1].capitalize()+(C[2]?C[2].capitalize():"")]}this.options.transition=D}}})();Fx.Transition=function(B,A){A=$splat(A);return $extend(B,{easeIn:function(C){return B(C,A)},easeOut:function(C){return 1-B(1-C,A)},easeInOut:function(C){return(C<=0.5)?B(2*C,A)/2:(2-B(2*(1-C),A))/2}})};Fx.Transitions=new Hash({linear:$arguments(0)});Fx.Transitions.extend=function(A){for(var B in A){Fx.Transitions[B]=new Fx.Transition(A[B])}};Fx.Transitions.extend({Pow:function(B,A){return Math.pow(B,A[0]||6)},Expo:function(A){return Math.pow(2,8*(A-1))},Circ:function(A){return 1-Math.sin(Math.acos(A))},Sine:function(A){return 1-Math.sin((1-A)*Math.PI/2)},Back:function(B,A){A=A[0]||1.618;return Math.pow(B,2)*((A+1)*B-A)},Bounce:function(D){var C;for(var B=0,A=1;1;B+=A,A/=2){if(D>=(7-4*B)/11){C=-Math.pow((11-6*B-11*D)/4,2)+A*A;break}}return C},Elastic:function(B,A){return Math.pow(2,10*--B)*Math.cos(20*B*Math.PI*(A[0]||1)/3)}});["Quad","Cubic","Quart","Quint"].each(function(B,A){Fx.Transitions[B]=new Fx.Transition(function(C){return Math.pow(C,[A+2])})});var Request=new Class({Implements:[Chain,Events,Options],options:{url:"",data:"",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},async:true,format:false,method:"post",link:"ignore",isSuccess:null,emulation:true,urlEncoded:true,encoding:"utf-8",evalScripts:false,evalResponse:false},initialize:function(A){this.xhr=new Browser.Request();this.setOptions(A);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers=new Hash(this.options.headers)},onStateChange:function(){if(this.xhr.readyState!=4||!this.running){return }this.running=false;this.status=0;$try(function(){this.status=this.xhr.status}.bind(this));if(this.options.isSuccess.call(this,this.status)){this.response={text:this.xhr.responseText,xml:this.xhr.responseXML};this.success(this.response.text,this.response.xml)}else{this.response={text:null,xml:null};this.failure()}this.xhr.onreadystatechange=$empty},isSuccess:function(){return((this.status>=200)&&(this.status<300))},processScripts:function(A){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){return $exec(A)}return A.stripScripts(this.options.evalScripts)},success:function(B,A){this.onSuccess(this.processScripts(B),A)},onSuccess:function(){this.fireEvent("complete",arguments).fireEvent("success",arguments).callChain()},failure:function(){this.onFailure()},onFailure:function(){this.fireEvent("complete").fireEvent("failure",this.xhr)},setHeader:function(A,B){this.headers.set(A,B);return this},getHeader:function(A){return $try(function(){return this.xhr.getResponseHeader(A)}.bind(this))},check:function(A){if(!this.running){return true}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));return false}return false},send:function(I){if(!this.check(arguments.callee,I)){return this}this.running=true;var G=$type(I);if(G=="string"||G=="element"){I={data:I}}var D=this.options;I=$extend({data:D.data,url:D.url,method:D.method},I);var E=I.data,B=I.url,A=I.method;switch($type(E)){case"element":E=$(E).toQueryString();break;case"object":case"hash":E=Hash.toQueryString(E)}if(this.options.format){var H="format="+this.options.format;E=(E)?H+"&"+E:H}if(this.options.emulation&&["put","delete"].contains(A)){var F="_method="+A;E=(E)?F+"&"+E:F;A="post"}if(this.options.urlEncoded&&A=="post"){var C=(this.options.encoding)?"; charset="+this.options.encoding:"";this.headers.set("Content-type","application/x-www-form-urlencoded"+C)}if(E&&A=="get"){B=B+(B.contains("?")?"&":"?")+E;E=null}this.xhr.open(A.toUpperCase(),B,this.options.async);this.xhr.onreadystatechange=this.onStateChange.bind(this);this.headers.each(function(K,J){if(!$try(function(){this.xhr.setRequestHeader(J,K);return true}.bind(this))){this.fireEvent("exception",[J,K])}},this);this.fireEvent("request");this.xhr.send(E);if(!this.options.async){this.onStateChange()}return this},cancel:function(){if(!this.running){return this}this.running=false;this.xhr.abort();this.xhr.onreadystatechange=$empty;this.xhr=new Browser.Request();this.fireEvent("cancel");return this}});(function(){var A={};["get","post","put","delete","GET","POST","PUT","DELETE"].each(function(B){A[B]=function(){var C=Array.link(arguments,{url:String.type,data:$defined});return this.send($extend(C,{method:B.toLowerCase()}))}});Request.implement(A)})();Element.Properties.send={set:function(A){var B=this.retrieve("send");if(B){B.cancel()}return this.eliminate("send").store("send:options",$extend({data:this,link:"cancel",method:this.get("method")||"post",url:this.get("action")},A))},get:function(A){if(A||!this.retrieve("send")){if(A||!this.retrieve("send:options")){this.set("send",A)}this.store("send",new Request(this.retrieve("send:options")))}return this.retrieve("send")}};Element.implement({send:function(A){var B=this.get("send");B.send({data:this,url:A||B.options.url});return this}});Request.HTML=new Class({Extends:Request,options:{update:false,evalScripts:true,filter:false},processHTML:function(C){var B=C.match(/<body[^>]*>([\s\S]*?)<\/body>/i);C=(B)?B[1]:C;var A=new Element("div");return $try(function(){var D="<root>"+C+"</root>",G;if(Browser.Engine.trident){G=new ActiveXObject("Microsoft.XMLDOM");G.async=false;G.loadXML(D)}else{G=new DOMParser().parseFromString(D,"text/xml")}D=G.getElementsByTagName("root")[0];for(var F=0,E=D.childNodes.length;F<E;F++){var H=Element.clone(D.childNodes[F],true,true);if(H){A.grab(H)}}return A})||A.set("html",C)},success:function(D){var C=this.options,B=this.response;B.html=D.stripScripts(function(E){B.javascript=E});var A=this.processHTML(B.html);B.tree=A.childNodes;B.elements=A.getElements("*");if(C.filter){B.tree=B.elements.filter(C.filter)}if(C.update){$(C.update).empty().adopt(B.tree)}if(C.evalScripts){$exec(B.javascript)}this.onSuccess(B.tree,B.elements,B.html,B.javascript)}});Element.Properties.load={set:function(A){var B=this.retrieve("load");if(B){send.cancel()}return this.eliminate("load").store("load:options",$extend({data:this,link:"cancel",update:this,method:"get"},A))},get:function(A){if(A||!this.retrieve("load")){if(A||!this.retrieve("load:options")){this.set("load",A)}this.store("load",new Request.HTML(this.retrieve("load:options")))}return this.retrieve("load")}};Element.implement({load:function(){this.get("load").send(Array.link(arguments,{data:Object.type,url:String.type}));return this}});Request.JSON=new Class({Extends:Request,options:{secure:true},initialize:function(A){this.parent(A);this.headers.extend({Accept:"application/json","X-Request":"JSON"})},success:function(A){this.response.json=JSON.decode(A,this.options.secure);this.onSuccess(this.response.json,A)}});Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical"},initialize:function(B,A){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0);if(this.open&&Browser.Engine.webkit419){this.element.dispose().inject(this.wrapper)}},true);this.element=this.subject=$(B);this.parent(A);var C=this.element.retrieve("wrapper");this.wrapper=C||new Element("div",{styles:$extend(this.element.getStyles("margin","position"),{overflow:"hidden"})}).wraps(this.element);this.element.store("wrapper",this.wrapper).setStyle("margin",0);this.now=[];this.open=true},vertical:function(){this.margin="margin-top";this.layout="height";this.offset=this.element.offsetHeight},horizontal:function(){this.margin="margin-left";this.layout="width";this.offset=this.element.offsetWidth},set:function(A){this.element.setStyle(this.margin,A[0]);this.wrapper.setStyle(this.layout,A[1]);return this},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B[F]=Fx.compute(E[F],D[F],C)});return B},start:function(B,E){if(!this.check(arguments.callee,B,E)){return this}this[E||this.options.mode]();var D=this.element.getStyle(this.margin).toInt();var C=this.wrapper.getStyle(this.layout).toInt();var A=[[D,C],[0,this.offset]];var G=[[D,C],[-this.offset,0]];var F;switch(B){case"in":F=A;break;case"out":F=G;break;case"toggle":F=(this.wrapper["offset"+this.layout.capitalize()]==0)?A:G}return this.parent(F[0],F[1])},slideIn:function(A){return this.start("in",A)},slideOut:function(A){return this.start("out",A)},hide:function(A){this[A||this.options.mode]();this.open=false;return this.set([-this.offset,0])},show:function(A){this[A||this.options.mode]();this.open=true;return this.set([0,this.offset])},toggle:function(A){return this.start("toggle",A)}});Element.Properties.slide={set:function(B){var A=this.retrieve("slide");if(A){A.cancel()}return this.eliminate("slide").store("slide:options",$extend({link:"cancel"},B))},get:function(A){if(A||!this.retrieve("slide")){if(A||!this.retrieve("slide:options")){this.set("slide",A)}this.store("slide",new Fx.Slide(this,this.retrieve("slide:options")))}return this.retrieve("slide")}};Element.implement({slide:function(D,E){D=D||"toggle";var B=this.get("slide"),A;switch(D){case"hide":B.hide(E);break;case"show":B.show(E);break;case"toggle":var C=this.retrieve("slide:flag",B.open);B[(C)?"slideOut":"slideIn"](E);this.store("slide:flag",!C);A=true;break;default:B.start(D,E)}if(!A){this.eliminate("slide:flag")}return this}});Fx.Scroll=new Class({Extends:Fx,options:{offset:{x:0,y:0},wheelStops:true},initialize:function(B,A){this.element=this.subject=$(B);this.parent(A);var D=this.cancel.bind(this,false);if($type(this.element)!="element"){this.element=$(this.element.getDocument().body)}var C=this.element;if(this.options.wheelStops){this.addEvent("start",function(){C.addEvent("mousewheel",D)},true);this.addEvent("complete",function(){C.removeEvent("mousewheel",D)},true)}},set:function(){var A=Array.flatten(arguments);this.element.scrollTo(A[0],A[1])},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B.push(Fx.compute(E[F],D[F],C))});return B},start:function(C,H){if(!this.check(arguments.callee,C,H)){return this}var E=this.element.getSize(),F=this.element.getScrollSize();var B=this.element.getScroll(),D={x:C,y:H};for(var G in D){var A=F[G]-E[G];if($chk(D[G])){D[G]=($type(D[G])=="number")?D[G].limit(0,A):A}else{D[G]=B[G]}D[G]+=this.options.offset[G]}return this.parent([B.x,B.y],[D.x,D.y])},toTop:function(){return this.start(false,0)},toLeft:function(){return this.start(0,false)},toRight:function(){return this.start("right",false)},toBottom:function(){return this.start(false,"bottom")},toElement:function(B){var A=$(B).getPosition(this.element);return this.start(A.x,A.y)}});Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(B,A){this.elements=this.subject=$$(B);this.parent(A)},compute:function(G,H,I){var C={};for(var D in G){var A=G[D],E=H[D],F=C[D]={};for(var B in A){F[B]=this.parent(A[B],E[B],I)}}return C},set:function(B){for(var C in B){var A=B[C];for(var D in A){this.render(this.elements[C],D,A[D],this.options.unit)}}return this},start:function(C){if(!this.check(arguments.callee,C)){return this}var H={},I={};for(var D in C){var F=C[D],A=H[D]={},G=I[D]={};for(var B in F){var E=this.prepare(this.elements[D],B,F[B]);A[B]=E.from;G[B]=E.to}}return this.parent(H,I)}});var Drag=new Class({Implements:[Events,Options],options:{snap:6,unit:"px",grid:false,style:true,limit:false,handle:false,invert:false,preventDefault:false,modifiers:{x:"left",y:"top"}},initialize:function(){var B=Array.link(arguments,{options:Object.type,element:$defined});this.element=$(B.element);this.document=this.element.getDocument();this.setOptions(B.options||{});var A=$type(this.options.handle);this.handles=(A=="array"||A=="collection")?$$(this.options.handle):$(this.options.handle)||this.element;this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.selection=(Browser.Engine.trident)?"selectstart":"mousedown";this.bound={start:this.start.bind(this),check:this.check.bind(this),drag:this.drag.bind(this),stop:this.stop.bind(this),cancel:this.cancel.bind(this),eventStop:$lambda(false)};this.attach()},attach:function(){this.handles.addEvent("mousedown",this.bound.start);return this},detach:function(){this.handles.removeEvent("mousedown",this.bound.start);return this},start:function(C){if(this.options.preventDefault){C.preventDefault()}this.fireEvent("beforeStart",this.element);this.mouse.start=C.page;var A=this.options.limit;this.limit={x:[],y:[]};for(var D in this.options.modifiers){if(!this.options.modifiers[D]){continue}if(this.options.style){this.value.now[D]=this.element.getStyle(this.options.modifiers[D]).toInt()}else{this.value.now[D]=this.element[this.options.modifiers[D]]}if(this.options.invert){this.value.now[D]*=-1}this.mouse.pos[D]=C.page[D]-this.value.now[D];if(A&&A[D]){for(var B=2;B--;B){if($chk(A[D][B])){this.limit[D][B]=$lambda(A[D][B])()}}}}if($type(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid}}this.document.addEvents({mousemove:this.bound.check,mouseup:this.bound.cancel});this.document.addEvent(this.selection,this.bound.eventStop)},check:function(A){if(this.options.preventDefault){A.preventDefault()}var B=Math.round(Math.sqrt(Math.pow(A.page.x-this.mouse.start.x,2)+Math.pow(A.page.y-this.mouse.start.y,2)));if(B>this.options.snap){this.cancel();this.document.addEvents({mousemove:this.bound.drag,mouseup:this.bound.stop});this.fireEvent("start",this.element).fireEvent("snap",this.element)}},drag:function(A){if(this.options.preventDefault){A.preventDefault()}this.mouse.now=A.page;for(var B in this.options.modifiers){if(!this.options.modifiers[B]){continue}this.value.now[B]=this.mouse.now[B]-this.mouse.pos[B];if(this.options.invert){this.value.now[B]*=-1}if(this.options.limit&&this.limit[B]){if($chk(this.limit[B][1])&&(this.value.now[B]>this.limit[B][1])){this.value.now[B]=this.limit[B][1]}else{if($chk(this.limit[B][0])&&(this.value.now[B]<this.limit[B][0])){this.value.now[B]=this.limit[B][0]}}}if(this.options.grid[B]){this.value.now[B]-=(this.value.now[B]%this.options.grid[B])}if(this.options.style){this.element.setStyle(this.options.modifiers[B],this.value.now[B]+this.options.unit)}else{this.element[this.options.modifiers[B]]=this.value.now[B]}}this.fireEvent("drag",this.element)},cancel:function(A){this.document.removeEvent("mousemove",this.bound.check);this.document.removeEvent("mouseup",this.bound.cancel);if(A){this.document.removeEvent(this.selection,this.bound.eventStop);this.fireEvent("cancel",this.element)}},stop:function(A){this.document.removeEvent(this.selection,this.bound.eventStop);this.document.removeEvent("mousemove",this.bound.drag);this.document.removeEvent("mouseup",this.bound.stop);if(A){this.fireEvent("complete",this.element)}}});Element.implement({makeResizable:function(A){return new Drag(this,$merge({modifiers:{x:"width",y:"height"}},A))}});Drag.Move=new Class({Extends:Drag,options:{droppables:[],container:false},initialize:function(C,B){this.parent(C,B);this.droppables=$$(this.options.droppables);this.container=$(this.options.container);if(this.container&&$type(this.container)!="element"){this.container=$(this.container.getDocument().body)}C=this.element;var D=C.getStyle("position");var A=(D!="static")?D:"absolute";if(C.getStyle("left")=="auto"||C.getStyle("top")=="auto"){C.position(C.getPosition(C.offsetParent))}C.setStyle("position",A);this.addEvent("start",function(){this.checkDroppables()},true)},start:function(B){if(this.container){var D=this.element,J=this.container,E=J.getCoordinates(D.offsetParent),F={},A={};["top","right","bottom","left"].each(function(K){F[K]=J.getStyle("padding-"+K).toInt();A[K]=D.getStyle("margin-"+K).toInt()},this);var C=D.offsetWidth+A.left+A.right,I=D.offsetHeight+A.top+A.bottom;var H=[E.left+F.left,E.right-F.right-C];var G=[E.top+F.top,E.bottom-F.bottom-I];this.options.limit={x:H,y:G}}this.parent(B)},checkAgainst:function(B){B=B.getCoordinates();var A=this.mouse.now;return(A.x>B.left&&A.x<B.right&&A.y<B.bottom&&A.y>B.top)},checkDroppables:function(){var A=this.droppables.filter(this.checkAgainst,this).getLast();if(this.overed!=A){if(this.overed){this.fireEvent("leave",[this.element,this.overed])}if(A){this.overed=A;this.fireEvent("enter",[this.element,A])}else{this.overed=null}}},drag:function(A){this.parent(A);if(this.droppables.length){this.checkDroppables()}},stop:function(A){this.checkDroppables();this.fireEvent("drop",[this.element,this.overed]);this.overed=null;return this.parent(A)}});Element.implement({makeDraggable:function(A){return new Drag.Move(this,A)}});Hash.Cookie=new Class({Extends:Cookie,options:{autoSave:true},initialize:function(B,A){this.parent(B,A);this.load()},save:function(){var A=JSON.encode(this.hash);if(!A||A.length>4096){return false}if(A=="{}"){this.dispose()}else{this.write(A)}return true},load:function(){this.hash=new Hash(JSON.decode(this.read(),true));return this}});Hash.Cookie.implement((function(){var A={};Hash.each(Hash.prototype,function(C,B){A[B]=function(){var D=C.apply(this.hash,arguments);if(this.options.autoSave){this.save()}return D}});return A})());var Color=new Native({initialize:function(B,C){if(arguments.length>=3){C="rgb";B=Array.slice(arguments,0,3)}else{if(typeof B=="string"){if(B.match(/rgb/)){B=B.rgbToHex().hexToRgb(true)}else{if(B.match(/hsb/)){B=B.hsbToRgb()}else{B=B.hexToRgb(true)}}}}C=C||"rgb";switch(C){case"hsb":var A=B;B=B.hsbToRgb();B.hsb=A;break;case"hex":B=B.hexToRgb(true);break}B.rgb=B.slice(0,3);B.hsb=B.hsb||B.rgbToHsb();B.hex=B.rgbToHex();return $extend(B,this)}});Color.implement({mix:function(){var A=Array.slice(arguments);var C=($type(A.getLast())=="number")?A.pop():50;var B=this.slice();A.each(function(D){D=new Color(D);for(var E=0;E<3;E++){B[E]=Math.round((B[E]/100*(100-C))+(D[E]/100*C))}});return new Color(B,"rgb")},invert:function(){return new Color(this.map(function(A){return 255-A}))},setHue:function(A){return new Color([A,this.hsb[1],this.hsb[2]],"hsb")},setSaturation:function(A){return new Color([this.hsb[0],A,this.hsb[2]],"hsb")},setBrightness:function(A){return new Color([this.hsb[0],this.hsb[1],A],"hsb")}});function $RGB(C,B,A){return new Color([C,B,A],"rgb")}function $HSB(C,B,A){return new Color([C,B,A],"hsb")}function $HEX(A){return new Color(A,"hex")}Array.implement({rgbToHsb:function(){var B=this[0],C=this[1],J=this[2];var G,F,H;var I=Math.max(B,C,J),E=Math.min(B,C,J);var K=I-E;H=I/255;F=(I!=0)?K/I:0;if(F==0){G=0}else{var D=(I-B)/K;var A=(I-C)/K;var L=(I-J)/K;if(B==I){G=L-A}else{if(C==I){G=2+D-L}else{G=4+A-D}}G/=6;if(G<0){G++}}return[Math.round(G*360),Math.round(F*100),Math.round(H*100)]},hsbToRgb:function(){var C=Math.round(this[2]/100*255);if(this[1]==0){return[C,C,C]}else{var A=this[0]%360;var E=A%60;var F=Math.round((this[2]*(100-this[1]))/10000*255);var D=Math.round((this[2]*(6000-this[1]*E))/600000*255);var B=Math.round((this[2]*(6000-this[1]*(60-E)))/600000*255);switch(Math.floor(A/60)){case 0:return[C,B,F];case 1:return[D,C,F];case 2:return[F,C,B];case 3:return[F,D,C];case 4:return[B,F,C];case 5:return[C,F,D]}}return false}});String.implement({rgbToHsb:function(){var A=this.match(/\d{1,3}/g);return(A)?hsb.rgbToHsb():null},hsbToRgb:function(){var A=this.match(/\d{1,3}/g);return(A)?A.hsbToRgb():null}});var Group=new Class({initialize:function(){this.instances=Array.flatten(arguments);this.events={};this.checker={}},addEvent:function(B,A){this.checker[B]=this.checker[B]||{};this.events[B]=this.events[B]||[];if(this.events[B].contains(A)){return false}else{this.events[B].push(A)}this.instances.each(function(C,D){C.addEvent(B,this.check.bind(this,[B,C,D]))},this);return this},check:function(C,A,B){this.checker[C][B]=true;var D=this.instances.every(function(F,E){return this.checker[C][E]||false},this);if(!D){return }this.checker[C]={};this.events[C].each(function(E){E.call(this,this.instances,A)},this)}});var Asset=new Hash({javascript:function(F,D){D=$extend({onload:$empty,document:document,check:$lambda(true)},D);var B=new Element("script",{src:F,type:"text/javascript"});var E=D.onload.bind(B),A=D.check,G=D.document;delete D.onload;delete D.check;delete D.document;B.addEvents({load:E,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){E()}}}).setProperties(D);if(Browser.Engine.webkit419){var C=(function(){if(!$try(A)){return }$clear(C);E()}).periodical(50)}return B.inject(G.head)},css:function(B,A){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:B},A)).inject(document.head)},image:function(C,B){B=$merge({onload:$empty,onabort:$empty,onerror:$empty},B);var D=new Image();var A=$(D)||new Element("img");["load","abort","error"].each(function(E){var F="on"+E;var G=B[F];delete B[F];D[F]=function(){if(!D){return }if(!A.parentNode){A.width=D.width;A.height=D.height}D=D.onload=D.onabort=D.onerror=null;G.delay(1,A,A);A.fireEvent(E,A,1)}});D.src=A.src=C;if(D&&D.complete){D.onload.delay(1)}return A.setProperties(B)},images:function(D,C){C=$merge({onComplete:$empty,onProgress:$empty},C);if(!D.push){D=[D]}var A=[];var B=0;D.each(function(F){var E=new Asset.image(F,{onload:function(){C.onProgress.call(this,B,D.indexOf(F));B++;if(B==D.length){C.onComplete()}}});A.push(E)});return new Elements(A)}});var Sortables=new Class({Implements:[Events,Options],options:{snap:4,opacity:1,clone:false,revert:false,handle:false,constrain:false},initialize:function(A,B){this.setOptions(B);this.elements=[];this.lists=[];this.idle=true;this.addLists($$($(A)||A));if(!this.options.clone){this.options.revert=false}if(this.options.revert){this.effect=new Fx.Morph(null,$merge({duration:250,link:"cancel"},this.options.revert))}},attach:function(){this.addLists(this.lists);return this},detach:function(){this.lists=this.removeLists(this.lists);return this},addItems:function(){Array.flatten(arguments).each(function(A){this.elements.push(A);var B=A.retrieve("sortables:start",this.start.bindWithEvent(this,A));(this.options.handle?A.getElement(this.options.handle)||A:A).addEvent("mousedown",B)},this);return this},addLists:function(){Array.flatten(arguments).each(function(A){this.lists.push(A);this.addItems(A.getChildren())},this);return this},removeItems:function(){var A=[];Array.flatten(arguments).each(function(B){A.push(B);this.elements.erase(B);var C=B.retrieve("sortables:start");(this.options.handle?B.getElement(this.options.handle)||B:B).removeEvent("mousedown",C)},this);return $$(A)},removeLists:function(){var A=[];Array.flatten(arguments).each(function(B){A.push(B);this.lists.erase(B);this.removeItems(B.getChildren())},this);return $$(A)},getClone:function(B,A){if(!this.options.clone){return new Element("div").inject(document.body)}if($type(this.options.clone)=="function"){return this.options.clone.call(this,B,A,this.list)}return A.clone(true).setStyles({margin:"0px",position:"absolute",visibility:"hidden",width:A.getStyle("width")}).inject(this.list).position(A.getPosition(A.getOffsetParent()))},getDroppables:function(){var A=this.list.getChildren();if(!this.options.constrain){A=this.lists.concat(A).erase(this.list)}return A.erase(this.clone).erase(this.element)},insert:function(C,B){var A="inside";if(this.lists.contains(B)){this.list=B;this.drag.droppables=this.getDroppables()}else{A=this.element.getAllPrevious().contains(B)?"before":"after"}this.element.inject(B,A);this.fireEvent("sort",[this.element,this.clone])},start:function(B,A){if(!this.idle){return }this.idle=false;this.element=A;this.opacity=A.get("opacity");this.list=A.getParent();this.clone=this.getClone(B,A);this.drag=new Drag.Move(this.clone,{snap:this.options.snap,container:this.options.constrain&&this.element.getParent(),droppables:this.getDroppables(),onSnap:function(){B.stop();this.clone.setStyle("visibility","visible");this.element.set("opacity",this.options.opacity||0);this.fireEvent("start",[this.element,this.clone])}.bind(this),onEnter:this.insert.bind(this),onCancel:this.reset.bind(this),onComplete:this.end.bind(this)});this.clone.inject(this.element,"before");this.drag.start(B)},end:function(){this.drag.detach();this.element.set("opacity",this.opacity);if(this.effect){var A=this.element.getStyles("width","height");var B=this.clone.computePosition(this.element.getPosition(this.clone.offsetParent));this.effect.element=this.clone;this.effect.start({top:B.top,left:B.left,width:A.width,height:A.height,opacity:0.25}).chain(this.reset.bind(this))}else{this.reset()}},reset:function(){this.idle=true;this.clone.destroy();this.fireEvent("complete",this.element)},serialize:function(){var C=Array.link(arguments,{modifier:Function.type,index:$defined});var B=this.lists.map(function(D){return D.getChildren().map(C.modifier||function(E){return E.get("id")},this)},this);var A=C.index;if(this.lists.length==1){A=0}return $chk(A)&&A>=0&&A<this.lists.length?B[A]:B}});var Tips=new Class({Implements:[Events,Options],options:{onShow:function(A){A.setStyle("visibility","visible")},onHide:function(A){A.setStyle("visibility","hidden")},showDelay:100,hideDelay:100,className:null,offsets:{x:16,y:16},fixed:false},initialize:function(){var C=Array.link(arguments,{options:Object.type,elements:$defined});this.setOptions(C.options||null);this.tip=new Element("div").inject(document.body);if(this.options.className){this.tip.addClass(this.options.className)}var B=new Element("div",{"class":"tip-top"}).inject(this.tip);this.container=new Element("div",{"class":"tip"}).inject(this.tip);var A=new Element("div",{"class":"tip-bottom"}).inject(this.tip);this.tip.setStyles({position:"absolute",top:0,left:0,visibility:"hidden"});if(C.elements){this.attach(C.elements)}},attach:function(A){$$(A).each(function(D){var G=D.retrieve("tip:title",D.get("title"));var F=D.retrieve("tip:text",D.get("rel")||D.get("href"));var E=D.retrieve("tip:enter",this.elementEnter.bindWithEvent(this,D));var C=D.retrieve("tip:leave",this.elementLeave.bindWithEvent(this,D));D.addEvents({mouseenter:E,mouseleave:C});if(!this.options.fixed){var B=D.retrieve("tip:move",this.elementMove.bindWithEvent(this,D));D.addEvent("mousemove",B)}D.store("tip:native",D.get("title"));D.erase("title")},this);return this},detach:function(A){$$(A).each(function(C){C.removeEvent("mouseenter",C.retrieve("tip:enter")||$empty);C.removeEvent("mouseleave",C.retrieve("tip:leave")||$empty);C.removeEvent("mousemove",C.retrieve("tip:move")||$empty);C.eliminate("tip:enter").eliminate("tip:leave").eliminate("tip:move");var B=C.retrieve("tip:native");if(B){C.set("title",B)}});return this},elementEnter:function(B,A){$A(this.container.childNodes).each(Element.dispose);var D=A.retrieve("tip:title");if(D){this.titleElement=new Element("div",{"class":"tip-title"}).inject(this.container);this.fill(this.titleElement,D)}var C=A.retrieve("tip:text");if(C){this.textElement=new Element("div",{"class":"tip-text"}).inject(this.container);this.fill(this.textElement,C)}this.timer=$clear(this.timer);this.timer=this.show.delay(this.options.showDelay,this);this.position((!this.options.fixed)?B:{page:A.getPosition()})},elementLeave:function(A){$clear(this.timer);this.timer=this.hide.delay(this.options.hideDelay,this)},elementMove:function(A){this.position(A)},position:function(D){var B=window.getSize(),A=window.getScroll();var E={x:this.tip.offsetWidth,y:this.tip.offsetHeight};var C={x:"left",y:"top"};for(var F in C){var G=D.page[F]+this.options.offsets[F];if((G+E[F]-A[F])>B[F]){G=D.page[F]-this.options.offsets[F]-E[F]}this.tip.setStyle(C[F],G)}},fill:function(A,B){(typeof B=="string")?A.set("html",B):A.adopt(B)},show:function(){this.fireEvent("show",this.tip)},hide:function(){this.fireEvent("hide",this.tip)}});var SmoothScroll=new Class({Extends:Fx.Scroll,initialize:function(B,C){C=C||document;var E=C.getDocument(),D=C.getWindow();this.parent(E,B);this.links=(this.options.links)?$$(this.options.links):$$(E.links);var A=D.location.href.match(/^[^#]*/)[0]+"#";this.links.each(function(G){if(G.href.indexOf(A)!=0){return }var F=G.href.substr(A.length);if(F&&$(F)){this.useLink(G,F)}},this);if(!Browser.Engine.webkit419){this.addEvent("complete",function(){D.location.hash=this.anchor},true)}},useLink:function(B,A){B.addEvent("click",function(C){this.anchor=A;this.toElement(A);C.stop()}.bind(this))}});var Slider=new Class({Implements:[Events,Options],options:{onTick:function(A){if(this.options.snap){A=this.toPosition(this.step)}this.knob.setStyle(this.property,A)},snap:false,offset:0,range:false,wheel:false,steps:100,mode:"horizontal"},initialize:function(E,A,D){this.setOptions(D);this.element=$(E);this.knob=$(A);this.previousChange=this.previousEnd=this.step=-1;this.element.addEvent("mousedown",this.clickedElement.bind(this));if(this.options.wheel){this.element.addEvent("mousewheel",this.scrolledElement.bindWithEvent(this))}var F,B={},C={x:false,y:false};switch(this.options.mode){case"vertical":this.axis="y";this.property="top";F="offsetHeight";break;case"horizontal":this.axis="x";this.property="left";F="offsetWidth"}this.half=this.knob[F]/2;this.full=this.element[F]-this.knob[F]+(this.options.offset*2);this.min=$chk(this.options.range[0])?this.options.range[0]:0;this.max=$chk(this.options.range[1])?this.options.range[1]:this.options.steps;this.range=this.max-this.min;this.steps=this.options.steps||this.full;this.stepSize=Math.abs(this.range)/this.steps;this.stepWidth=this.stepSize*this.full/Math.abs(this.range);this.knob.setStyle("position","relative").setStyle(this.property,-this.options.offset);C[this.axis]=this.property;B[this.axis]=[-this.options.offset,this.full-this.options.offset];this.drag=new Drag(this.knob,{snap:0,limit:B,modifiers:C,onDrag:this.draggedKnob.bind(this),onStart:this.draggedKnob.bind(this),onComplete:function(){this.draggedKnob();this.end()}.bind(this)});if(this.options.snap){this.drag.options.grid=Math.ceil(this.stepWidth);this.drag.options.limit[this.axis][1]=this.full}},set:function(A){if(!((this.range>0)^(A<this.min))){A=this.min}if(!((this.range>0)^(A>this.max))){A=this.max}this.step=Math.round(A);this.checkStep();this.end();this.fireEvent("tick",this.toPosition(this.step));return this},clickedElement:function(C){var B=this.range<0?-1:1;var A=C.page[this.axis]-this.element.getPosition()[this.axis]-this.half;A=A.limit(-this.options.offset,this.full-this.options.offset);this.step=Math.round(this.min+B*this.toStep(A));this.checkStep();this.end();this.fireEvent("tick",A)},scrolledElement:function(A){var B=(this.options.mode=="horizontal")?(A.wheel<0):(A.wheel>0);this.set(B?this.step-this.stepSize:this.step+this.stepSize);A.stop()},draggedKnob:function(){var B=this.range<0?-1:1;var A=this.drag.value.now[this.axis];A=A.limit(-this.options.offset,this.full-this.options.offset);this.step=Math.round(this.min+B*this.toStep(A));this.checkStep()},checkStep:function(){if(this.previousChange!=this.step){this.previousChange=this.step;this.fireEvent("change",this.step)}},end:function(){if(this.previousEnd!==this.step){this.previousEnd=this.step;this.fireEvent("complete",this.step+"")}},toStep:function(A){var B=(A+this.options.offset)*this.stepSize/this.full*this.steps;return this.options.steps?Math.round(B-=B%this.stepSize):B},toPosition:function(A){return(this.full*Math.abs(this.min-A))/(this.steps*this.stepSize)-this.options.offset}});var Scroller=new Class({Implements:[Events,Options],options:{area:20,velocity:1,onChange:function(A,B){this.element.scrollTo(A,B)}},initialize:function(B,A){this.setOptions(A);this.element=$(B);this.listener=($type(this.element)!="element")?$(this.element.getDocument().body):this.element;this.timer=null;this.coord=this.getCoords.bind(this)},start:function(){this.listener.addEvent("mousemove",this.coord)},stop:function(){this.listener.removeEvent("mousemove",this.coord);this.timer=$clear(this.timer)},getCoords:function(A){this.page=(this.listener.get("tag")=="body")?A.client:A.page;if(!this.timer){this.timer=this.scroll.periodical(50,this)}},scroll:function(){var B=this.element.getSize(),A=this.element.getScroll(),E=this.element.getPosition(),D={x:0,y:0};for(var C in this.page){if(this.page[C]<(this.options.area+E[C])&&A[C]!=0){D[C]=(this.page[C]-this.options.area-E[C])*this.options.velocity}else{if(this.page[C]+this.options.area>(B[C]+E[C])&&B[C]+B[C]!=A[C]){D[C]=(this.page[C]-B[C]+this.options.area-E[C])*this.options.velocity}}}if(D.y||D.x){this.fireEvent("change",[A.x+D.x,A.y+D.y])}}});var Accordion=new Class({Extends:Fx.Elements,options:{display:0,show:false,height:true,width:false,opacity:true,fixedHeight:false,fixedWidth:false,wait:false,alwaysHide:false},initialize:function(){var C=Array.link(arguments,{container:Element.type,options:Object.type,togglers:$defined,elements:$defined});this.parent(C.elements,C.options);this.togglers=$$(C.togglers);this.container=$(C.container);this.previous=-1;if(this.options.alwaysHide){this.options.wait=true}if($chk(this.options.show)){this.options.display=false;this.previous=this.options.show}if(this.options.start){this.options.display=false;this.options.show=false}this.effects={};if(this.options.opacity){this.effects.opacity="fullOpacity"}if(this.options.width){this.effects.width=this.options.fixedWidth?"fullWidth":"offsetWidth"}if(this.options.height){this.effects.height=this.options.fixedHeight?"fullHeight":"scrollHeight"}for(var B=0,A=this.togglers.length;B<A;B++){this.addSection(this.togglers[B],this.elements[B])}this.elements.each(function(E,D){if(this.options.show===D){this.fireEvent("active",[this.togglers[D],E])}else{for(var F in this.effects){E.setStyle(F,0)}}},this);if($chk(this.options.display)){this.display(this.options.display)}},addSection:function(E,C,G){E=$(E);C=$(C);var F=this.togglers.contains(E);var B=this.togglers.length;this.togglers.include(E);this.elements.include(C);if(B&&(!F||G)){G=$pick(G,B-1);E.inject(this.togglers[G],"before");C.inject(E,"after")}else{if(this.container&&!F){E.inject(this.container);C.inject(this.container)}}var A=this.togglers.indexOf(E);E.addEvent("click",this.display.bind(this,A));if(this.options.height){C.setStyles({"padding-top":0,"border-top":"none","padding-bottom":0,"border-bottom":"none"})}if(this.options.width){C.setStyles({"padding-left":0,"border-left":"none","padding-right":0,"border-right":"none"})}C.fullOpacity=1;if(this.options.fixedWidth){C.fullWidth=this.options.fixedWidth}if(this.options.fixedHeight){C.fullHeight=this.options.fixedHeight}C.setStyle("overflow","hidden");if(!F){for(var D in this.effects){C.setStyle(D,0)}}return this},display:function(A){A=($type(A)=="element")?this.elements.indexOf(A):A;if((this.timer&&this.options.wait)||(A===this.previous&&!this.options.alwaysHide)){return this}this.previous=A;var B={};this.elements.each(function(E,D){B[D]={};var C=(D!=A)||(this.options.alwaysHide&&(E.offsetHeight>0));this.fireEvent(C?"background":"active",[this.togglers[D],E]);for(var F in this.effects){B[D][F]=C?0:E[this.effects[F]]}},this);return this.start(B)}});window.addEvent("load",function(){if(!("console" in window)||!("firebug" in window.console)){var B=["log","debug","info","warn","error","assert","dir","dirxml","group","groupEnd","time","timeEnd","count","trace","profile","profileEnd"];window.console={};for(var A=0;A<B.length;++A){window.console[B[A]]=function(){}}}});(function(){var A=navigator.userAgent.toLowerCase();var B=A.indexOf("msie")>-1,D=A.indexOf("msie 7")>-1;if(B&&!D){try{document.execCommand("BackgroundImageCache",false,true)}catch(C){}}})();if(typeof Jx=="undefined"){var Jx={};(function(){var C=document.getElementsByTagName("SCRIPT");for(var A=0;A<C.length;A++){var B=C[A].src;var D=/(.*)(js|lib\/)jxlib(.*)/.exec(B);if(D&&D[0]){Jx.aPixel=document.createElement("img");Jx.aPixel.src=D[1]+"/images/a_pixel.png";Jx.baseURL=Jx.aPixel.src.substring(0,Jx.aPixel.src.indexOf("images/a_pixel.png"))}}})()}Jx.applyPNGFilter=function(C){var A=Jx.baseURL+"images/a_pixel.png";if(C.src!=A){var B=C.src;C.src=A;C.runtimeStyle.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+B+"',sizingMethod='scale')"}};Jx.imgQueue=[];Jx.imgLoaded={};Jx.imagesLoading=0;Jx.addToImgQueue=function(A){if(Jx.imgLoaded[A.src]){A.element.src=A.src}else{Jx.imgQueue.push(A);Jx.imgLoaded[A.src]=true}Jx.checkImgQueue()};Jx.checkImgQueue=function(){while(Jx.imagesLoading<2&&Jx.imgQueue.length>0){Jx.loadNextImg()}};Jx.loadNextImg=function(){var A=Jx.imgQueue.shift();if(A){++Jx.imagesLoading;A.element.onload=function(){--Jx.imagesLoading;Jx.checkImgQueue()};A.element.onerror=function(){--Jx.imagesLoading;Jx.checkImgQueue()};A.element.src=A.src}};Jx.createIframeShim=function(){return new Element("iframe",{"class":"jxIframeShim",scrolling:"no",frameborder:0})};Jx.UniqueId=new Class({uniqueIdRefs:null,initUniqueId:function(){this.uniqueIdRefs=[]},deregisterIds:function(){this.uniqueIdRefs=[]},registerIds:function(C,A){if(C.indexOf(A.id)!=-1){this.uniqueIdRefs[A.id]=A}for(var B=0;B<A.childNodes.length;B++){this.registerIds(C,A.childNodes[B])}},getObj:function(A){return this.uniqueIdRefs[A]||null}});Element.implement({getBoxSizing:function(){var B="content-box";if(Browser.Engine.trident||Browser.Engine.presto){var A=document.compatMode;if(A=="BackCompat"||A=="QuirksMode"){B="border-box"}else{B="content-box"}}else{if(arguments.length==0){node=document.documentElement}var C=this.getStyle("-moz-box-sizing");if(!C){C=this.getStyle("box-sizing")}B=(C?C:"content-box")}return B},getContentBoxSize:function(){var A=this.offsetWidth;var C=this.offsetHeight;var D=this.getPaddingSize();var B=this.getBorderSize();A=A-D.left-D.right-B.left-B.right;C=C-D.bottom-D.top-B.bottom-B.top;return{width:A,height:C}},getBorderBoxSize:function(){var A=this.offsetWidth;var B=this.offsetHeight;return{width:A,height:B}},getMarginBoxSize:function(){var C=this.getMarginSize();var A=this.offsetWidth+C.left+C.right;var B=this.offsetHeight+C.top+C.bottom;return{width:A,height:B}},setContentBoxSize:function(C){if(this.getBoxSizing()=="border-box"){var E=this.getPaddingSize();var B=this.getBorderSize();if(typeof C.width!="undefined"){var D=(C.width+E.left+E.right+B.left+B.right);if(D<0){D=0}this.style.width=D+"px"}if(typeof C.height!="undefined"){var A=(C.height+E.top+E.bottom+B.top+B.bottom);if(A<0){A=0}this.style.height=A+"px"}}else{if(typeof C.width!="undefined"){this.style.width=C.width+"px"}if(typeof C.height!="undefined"){this.style.height=C.height+"px"}}},setBorderBoxSize:function(C){if(this.getBoxSizing()=="content-box"){var F=this.getPaddingSize();var B=this.getBorderSize();var E=this.getMarginSize();if(typeof C.width!="undefined"){var D=(C.width-F.left-F.right-B.left-B.right-E.left-E.right);if(D<0){D=0}this.style.width=D+"px"}if(typeof C.height!="undefined"){var A=(C.height-F.top-F.bottom-B.top-B.bottom-E.top-E.bottom);if(A<0){A=0}this.style.height=A+"px"}}else{if(typeof C.width!="undefined"&&C.width>=0){this.style.width=C.width+"px"}if(typeof C.height!="undefined"&&C.height>=0){this.style.height=C.height+"px"}}},getPaddingSize:function(){var B=this.getNumber(this.getStyle("padding-left"));var C=this.getNumber(this.getStyle("padding-top"));var D=this.getNumber(this.getStyle("padding-right"));var A=this.getNumber(this.getStyle("padding-bottom"));return{left:B,top:C,right:D,bottom:A}},getBorderSize:function(){var B=this.getNumber(this.getStyle("border-left-width"));var C=this.getNumber(this.getStyle("border-top-width"));var D=this.getNumber(this.getStyle("border-right-width"));var A=this.getNumber(this.getStyle("border-bottom-width"));return{left:B,top:C,right:D,bottom:A}},getMarginSize:function(){var B=this.getNumber(this.getStyle("margin-left"));var C=this.getNumber(this.getStyle("margin-top"));var D=this.getNumber(this.getStyle("margin-right"));var A=this.getNumber(this.getStyle("margin-bottom"));return{left:B,top:C,right:D,bottom:A}},getNumber:function(B){var A=B==null||isNaN(parseInt(B))?0:parseInt(B);return A},getPageDimensions:function(){return{width:window.getWidth(),height:window.getHeight()}},descendantOf:function(B){var A=$(this.parentNode);if(A==B){return true}else{if(!A||!A.parentNode){return null}else{if(A.parentNode===A){return null}else{return A.descendantOf(B)}}}},findElement:function(B){if(this.tagName==B){return this}var A=$(this.parentNode);if(A){if(A.tagName==B){return A}else{if(!A.parentNode||A.parentNode==A){return null}else{return A.findElement(B)}}}else{return null}}});Jx.ContentLoader=new Class({contentIsLoaded:false,contentLoaded:function(){this.contentIsLoaded=true;this.fireEvent("contentLoaded",this)},contentLoadFailed:function(A){this.contentIsLoaded=true;this.fireEvent("contentLoadFailed",this)},loadContent:function(A){A=$(A);if(this.options.content){var B;if(this.options.content.domObj){B=$(this.options.content.domObj)}else{B=$(this.options.content)}if(B){A.appendChild(B);this.contentIsLoaded=true}else{A.innerHTML=this.options.content;this.contentIsLoaded=true}}else{if(this.options.contentURL){this.contentIsLoaded=false;new Request.HTML({url:this.options.contentURL,method:"get",update:A,onSuccess:this.contentLoaded.bind(this),onFailure:this.contentLoadFailed.bind(this),headers:{"If-Modified-Since":"Sat, 1 Jan 2000 00:00:00 GMT"}}).send()}else{this.contentIsLoaded=true}}if(this.contentIsLoaded){this.fireEvent("contentLoaded",this)}},processContent:function(A){$A(A.childNodes).each(function(B){if(B.tagName=="INPUT"||B.tagName=="SELECT"||B.tagName=="TEXTAREA"){if(B.type=="button"){B.addEvent("click",function(){this.fireEvent("click",this,B)})}else{B.addEvent("change",function(){this.fireEvent("change",B)})}}else{if(B.childNodes){this.processContent(B)}}},this)}});Jx.AutoPosition=new Class({position:function(F,C,N){F=$(F);C=$(C);var B=$splat(N.horizontal||["center center"]);var G=$splat(N.vertical||["center center"]);var E=$merge({top:0,right:0,bottom:0,left:0},N.offsets||{});var I;if(!$(F.parentNode)||F.parentNode==document.body){I=Element.getPageDimensions()}else{I=$(F.parentNode).getContentBoxSize()}var K=C.getCoordinates();var M=F.getMarginBoxSize();var D;var L;var J;var A;if(!B.some(function(O){var P=O.split(" ");if(P.length!=2){return false}if(!isNaN(parseInt(P[0]))){D=parseInt(P[0])}else{switch(P[0]){case"right":D=K.left+K.width;break;case"center":D=K.left+Math.round(K.width/2);break;case"left":default:D=K.left}}switch(P[1]){case"left":D-=E.left;L=D+M.width;break;case"right":D+=E.right;L=D;D=D-M.width;break;case"center":default:D=D-Math.round(M.width/2);L=D+M.width}return(D>=0&&L<=I.width)})){if(L>I.width){D=I.width-M.width}if(D<0){D=0}}F.setStyle("left",D);if(!G.some(function(O){var P=O.split(" ");if(P.length!=2){return false}if(!isNaN(parseInt(P[0]))){J=parseInt(P[0])}else{switch(P[0]){case"bottom":J=K.top+K.height;break;case"center":J=K.top+Math.round(K.height/2);break;case"top":default:J=K.top}}switch(P[1]){case"top":J-=E.top;A=J+M.height;break;case"bottom":J+=E.bottom;A=J;J=J-M.height;break;case"center":default:J=J-Math.round(M.height/2);A=J+M.height}return(J>=0&&A<=I.height)})){if(A>I.height){J=I.height-M.height}if(J<0){J=0}}F.setStyle("top",J);var H=F.retrieve("jxLayout");if(H){H.options.left=D;H.options.top=J}}});Jx.Chrome=new Class({chrome:null,makeChrome:function(A){var C=new Element("div",{"class":"jxChrome"});A.adopt(C);this.chromeOffsets=C.getPaddingSize();C.setStyle("padding",0);var B=C.getStyle("backgroundImage");if(!B.contains("http://")){B=null}else{B=B.slice(4,-1);if(B.charAt(0)=='"'){B=B.slice(1,-1)}C.setStyle("backgroundImage","none");["TL","TR","BL","BR"].each(function(D){C.adopt(new Element("div",{"class":"jxChrome"+D}).adopt(new Element("img",{src:B})))},this)}if(!window.opera){C.adopt(Jx.createIframeShim())}C.dispose();this.chrome=C},showChrome:function(B){B=$(B);var A;if(!this.chromeResizeHandler){this.chromeResizeHandler=this.showChrome.bind(this)}if(!this.chrome){this.makeChrome(B)}if(B&&this.chrome.parentNode!==B){var C=$(this.chrome.parentNode);if(C){A=C.retrieve("jxLayout");if(A){A.removeEvent("sizeChange",this.chromeResizeHandler)}}B.adopt(this.chrome);A=B.retrieve("jxLayout");if(A){A.addEvent("sizeChange",this.chromeResizeHandler)}}this.resizeChrome()},resizeChrome:function(){},hideChrome:function(){if(this.chrome){if(this.chrome.parentNode){var A=this.chrome.parentNode.retrieve("jxLayout");if(A){A.removeEvent("sizeChange",this.chromeResizeHandler)}}this.chrome.dispose()}}});Jx.Button=new Class({Implements:[Options,Events],domObj:null,options:{id:"",type:"Button",image:"",tooltip:"",label:"",enabled:true,toggle:false,halign:"center",valign:"middle",isActive:false,container:"div"},initialize:function(B){this.setOptions(B);var E=new Element(this.options.container,{"class":"jx"+this.options.type+"Container"});if(this.options.toggle){E.addClass("jx"+this.options.type+"Toggle")}var A=new Element("a",{"class":"jx"+this.options.type,href:"javascript:void(0)",title:this.options.tooltip,alt:this.options.tooltip,events:{click:this.clicked.bindWithEvent(this)}});if(this.options.isActive){A.addClass("jx"+this.options.type+"Active")}E.appendChild(A);var D=new Element("span",{"class":"jx"+this.options.type+"Content"});A.appendChild(D);if(this.options.image||!this.options.label){var C=new Element("img",{"class":"jx"+this.options.type+"Icon",src:Jx.aPixel.src});if(this.options.image.indexOf("a_pixel.png")==-1){C.setStyle("backgroundImage","url("+this.options.image+")")}D.appendChild(C)}l=new Element("span",{html:this.options.label});if(this.options.label){l.addClass("jx"+this.options.type+"Label")}D.appendChild(l);if(this.options.id){E.id=this.options.id}if(this.options.halign=="left"){E.addClass("jx"+this.options.type+"ContentLeft")}if(this.options.valign=="top"){E.addClass("jx"+this.options.type+"ContentTop")}this.domA=A;this.domLabel=l;this.domObj=E;this.setEnabled(this.options.enabled)},clicked:function(A){if(this.options.enabled){if(this.options.toggle){this.setActive(!this.options.isActive)}else{this.fireEvent("click",{obj:this,event:A})}}},setEnabled:function(A){this.options.enabled=A;if(this.options.enabled){this.domObj.removeClass("jx"+this.options.type+"Disabled")}else{this.domObj.addClass("jx"+this.options.type+"Disabled")}},isActive:function(){return this.options.isActive},setActive:function(A){if(this.options.isActive==A){return }this.options.isActive=A;if(this.options.isActive){this.domA.addClass("jx"+this.options.type+"Active");this.fireEvent("down",this)}else{this.domA.removeClass("jx"+this.options.type+"Active");this.fireEvent("up",this)}},setImage:function(A){if(this.domImg){this.domImg.set("src",A)}},setLabel:function(A){if(this.domLabel){this.domLabel.set("html",A)}},setTooltip:function(A){if(this.domImg){this.domImg.set({title:A,alt:A})}},addTo:function(B,A){B=$(B);A=A?$(A):null;if(A&&A.parentNode==B){B.insertBefore(this.domObj,A)}else{B.appendChild(this.domObj)}}});Jx.Button.Flyout=new Class({Extends:Jx.Button,Implements:[Jx.ContentLoader,Jx.AutoPosition,Jx.Chrome],content:null,initialize:function(A){if(!Jx.Button.Flyout.Stack){Jx.Button.Flyout.Stack=[]}this.parent(A);this.domA.addClass("jx"+this.options.type+"Flyout");this.contentContainer=new Element("div",{"class":"jxFlyout"});this.content=new Element("div",{"class":"jxFlyoutContent"});this.contentContainer.adopt(this.content);this.content.store("jxFlyout",this);this.loadContent(this.content);this.keypressWatcher=this.keypressHandler.bindWithEvent(this);this.hideWatcher=this.clickHandler.bindWithEvent(this)},clicked:function(C){if(!this.owner){this.owner=document.body;var B=$(this.domObj.parentNode);while(B!=document.body&&this.owner==document.body){var A=B.retrieve("jxFlyout");if(A){this.owner=A;break}else{B=$(B.parentNode)}}}if(Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length-1]==this){this.hide();return }else{if(this.owner!=document.body){if(this.owner.currentFlyout==this){this.hide();return }else{if(this.owner.currentFlyout){this.owner.currentFlyout.hide()}}this.owner.currentFlyout=this}else{while(Jx.Button.Flyout.Stack.length){Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length-1].hide()}}}Jx.Button.Flyout.Stack.push(this);this.options.isActive=true;this.domA.addClass("jx"+this.options.type+"Active");this.contentContainer.setStyle("visibility","hidden");document.body.adopt(this.contentContainer);this.showChrome(this.contentContainer);this.position(this.contentContainer,this.domObj,{horizontal:["left left","right right"],vertical:["bottom top","top bottom"],offsets:this.chromeOffsets});this.contentContainer.setStyle("visibility","");window.addEvent("keypress",this.keypressWatcher);document.addEvent("click",this.hideWatcher);this.fireEvent("open",this)},hide:function(){if(this.owner!=document.body){this.owner.currentFlyout=null}Jx.Button.Flyout.Stack.pop();this.setActive(false);this.contentContainer.dispose();window.removeEvent("keypress",this.keypressWatcher);document.removeEvent("click",this.hideWatcher);this.fireEvent("close",this)},clickHandler:function(B){B=new Event(B);var C=$(B.target);var A=Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length-1];if(!C.descendantOf(A.content)&&!C.descendantOf(A.domObj)){A.hide()}},keypressHandler:function(A){A=new Event(A);if(A.key=="esc"){Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length-1].hide()}}});Jx.Button.Multi=new Class({activeButton:null,buttons:null,initialize:function(){this.buttons=[];var A=new Element("div");this.tb=new Jx.Toolbar({parent:A,position:"right"});this.flyout=new Jx.Button.Flyout({content:A});this.flyout.domObj.firstChild.addClass("jxButtonMulti");this.domObj=new Element("div",{"class":"jxButtonMultiContainer"});this.domObj.grab(this.flyout.domObj)},add:function(){$A(arguments).each(function(B){if(!B instanceof Jx.Button){return }this.buttons.push(B);var A=new Jx.Button($merge(B.options,{onClick:this.setButton.bind(this,B)}));B.multiButton=A;this.tb.add(A);if(!this.activeButton){this.domObj.grab(B.domObj,"top");this.activeButton=B}},this)},remove:function(A){if(!A||!A.multiButton){return }if(this.tb.remove(A.multiButton)){A.multiButton=null;if(this.activeButton==A){if(!this.buttons.some(function(B){if(B!=A){this.setActiveButton(B);return true}else{return false}},this)){this.setActiveButton(null)}}this.flyout.content.style.height="";this.flyout.content.style.width="";this.buttons.erase(A)}},addTo:function(B,A){B=$(B);A=A?$(A):null;if(A&&A.parentNode==B){B.grab(this.domObj,"top")}else{B.adopt(this.domObj)}},setActiveButton:function(A){if(this.activeButton){this.activeButton.domObj.dispose()}if(A&&A.domObj){this.domObj.grab(A.domObj,"top")}this.activeButton=A},setButton:function(A){this.setActiveButton(A);A.clicked();this.flyout.hide()}});Jx.ColorPalette=new Class({Implements:[Options,Events],domObj:null,options:{color:"#000000",alpha:1},hexColors:["00","33","66","99","CC","FF"],initialize:function(C){this.setOptions(C);this.domObj=new Element("div",{id:this.options.id,"class":"jxColorPalette"});var H=new Element("div",{"class":"jxColorBar"});var Q=new Element("div",{"class":"jxColorPreview"});this.selectedSwatch=new Element("div",{"class":"jxColorSelected"});this.previewSwatch=new Element("div",{"class":"jxColorHover"});Q.adopt(this.selectedSwatch);Q.adopt(this.previewSwatch);H.adopt(Q);this.colorInputLabel=new Element("label",{"class":"jxColorLabel",html:"#"});H.adopt(this.colorInputLabel);var K=this.changed.bind(this);this.colorInput=new Element("input",{"class":"jxHexInput",type:"text",maxLength:6,events:{keyup:K,blur:K,change:K}});H.adopt(this.colorInput);this.alphaLabel=new Element("label",{"class":"jxAlphaLabel",html:"alpha (%)"});H.adopt(this.alphaLabel);this.alphaInput=new Element("input",{"class":"jxAlphaInput",type:"text",maxLength:3,events:{keyup:this.alphaChanged.bind(this)}});H.adopt(this.alphaInput);this.domObj.adopt(H);Q=new Element("div",{"class":"jxClearer"});this.domObj.adopt(Q);var I=this.swatchClick.bindWithEvent(this);var G=this.swatchOver.bindWithEvent(this);var P=new Element("table",{"class":"jxColorGrid"});var A=new Element("tbody");P.adopt(A);for(var N=0;N<12;N++){var B=new Element("tr");for(var L=-3;L<18;L++){var F=false;var J,O,R;if(L<0){if(L==-3||L==-1){J=O=R=0;F=true}else{if(N<6){J=O=R=N}else{if(N==6){J=5;O=0;R=0}else{if(N==7){J=0;O=5;R=0}else{if(N==8){J=0;O=0;R=5}else{if(N==9){J=5;O=5;R=0}else{if(N==10){J=0;O=5;R=5}else{if(N==11){J=5;O=0;R=5}}}}}}}}}else{J=parseInt(N/6)*3+parseInt(L/6);O=L%6;R=N%6}var D="#"+this.hexColors[J]+this.hexColors[O]+this.hexColors[R];var E=new Element("td");if(!F){E.setStyle("backgroundColor",D);var S=new Element("a",{"class":"colorSwatch "+(((J>2&&O>2)||(J>2&&R>2)||(O>2&&R>2))?"borderBlack":"borderWhite"),href:"#",title:D,alt:D,events:{mouseover:G,click:I}});S.store("swatchColor",D);E.adopt(S)}else{var M=new Element("span",{"class":"emptyCell"});E.adopt(M)}B.adopt(E)}A.adopt(B)}this.domObj.adopt(P);this.updateSelected()},swatchOver:function(B){var A=B.target;this.previewSwatch.setStyle("backgroundColor",A.retrieve("swatchColor"))},swatchClick:function(B){var A=B.target;this.options.color=A.retrieve("swatchColor");this.updateSelected();this.fireEvent("click",this)},changed:function(){var A=this.colorInput.value;if(A.substring(0,1)=="#"){A=A.substring(1)}if(A.toLowerCase().match(/^[0-9a-f]{6}$/)){this.options.color="#"+A.toUpperCase();this.updateSelected()}},alphaChanged:function(){var A=this.alphaInput.value;if(A.match(/^[0-9]{1,3}$/)){this.options.alpha=parseFloat(A/100);this.updateSelected()}},setColor:function(A){this.colorInput.value=A;this.changed()},setAlpha:function(A){this.alphaInput.value=A;this.alphaChanged()},updateSelected:function(){var A={backgroundColor:this.options.color};this.colorInput.value=this.options.color.substring(1);this.alphaInput.value=parseInt(this.options.alpha*100);if(this.options.alpha<1){A.opacity=this.options.alpha;A.filter="Alpha(opacity="+(this.options.alpha*100)+")"}else{A.opacity="";A.filter=""}this.selectedSwatch.setStyles(A);this.previewSwatch.setStyles(A);this.fireEvent("change",this)}});Jx.Button.Color=new Class({Extends:Jx.Button.Flyout,swatch:null,options:{color:"#000000",alpha:100},initialize:function(A){if(!Jx.Button.Color.ColorPalette){Jx.Button.Color.ColorPalette=new Jx.ColorPalette(this.options)}var B=new Element("span",{"class":"jxButtonSwatch"});this.selectedSwatch=new Element("span");B.appendChild(this.selectedSwatch);this.colorChangeFn=this.changed.bind(this);this.hideFn=this.hide.bind(this);Jx.Button.Flyout.prototype.initialize.apply(this,[A]);$(this.domObj.firstChild).addClass("jxButtonColor");this.domObj.firstChild.firstChild.insertBefore(B,this.domObj.firstChild.firstChild.firstChild);this.updateSwatch()},clicked:function(){if(Jx.Button.Color.ColorPalette.currentButton){Jx.Button.Color.ColorPalette.currentButton.hide()}Jx.Button.Color.ColorPalette.currentButton=this;Jx.Button.Color.ColorPalette.addEvent("change",this.colorChangeFn);Jx.Button.Color.ColorPalette.addEvent("click",this.hideFn);this.content.appendChild(Jx.Button.Color.ColorPalette.domObj);Jx.Button.Color.ColorPalette.domObj.setStyle("display","block");Jx.Button.Flyout.prototype.clicked.apply(this,arguments);Jx.Button.Color.ColorPalette.options.color=this.options.color;Jx.Button.Color.ColorPalette.options.alpha=this.options.alpha/100;Jx.Button.Color.ColorPalette.updateSelected()},hide:function(){this.setActive(false);Jx.Button.Color.ColorPalette.removeEvent("change",this.colorChangeFn);Jx.Button.Color.ColorPalette.removeEvent("click",this.hideFn);Jx.Button.Flyout.prototype.hide.apply(this,arguments);Jx.Button.Color.ColorPalette.currentButton=null},setColor:function(A){this.options.color=A;this.updateSwatch()},setAlpha:function(A){this.options.alpha=A;this.updateSwatch()},changed:function(A){var B=false;if(this.options.color!=A.options.color){this.options.color=A.options.color;B=true}if(this.options.alpha!=A.options.alpha*100){this.options.alpha=A.options.alpha*100;B=true}if(B){this.updateSwatch();this.fireEvent("change",this)}},updateSwatch:function(){var A={backgroundColor:this.options.color};if(this.options.alpha<100){A.filter="Alpha(opacity="+(this.options.alpha)+")";A.opacity=this.options.alpha/100}else{A.opacity="";A.filter=""}this.selectedSwatch.setStyles(A)}});Jx.ButtonSet=new Class({Implements:[Options,Events],buttons:null,initialize:function(A){this.setOptions(A);this.buttons=[];this.buttonChangedHandler=this.buttonChanged.bind(this)},add:function(){$A(arguments).each(function(A){A.domObj.addClass("jx"+A.options.type+"Set");A.addEvent("down",this.buttonChangedHandler);if(!this.activeButton){A.setActive(true)}this.buttons.push(A)},this)},remove:function(A){this.buttons.erase(A);if(this.activeButton==A){if(this.buttons.length){this.buttons[0].setActive(true)}A.removeEvent("down",this.buttonChangedHandler)}},setActiveButton:function(A){if(this.activeButton&&this.activeButton!=A){this.activeButton.setActive(false)}this.activeButton=A},buttonChanged:function(A){this.setActiveButton(A);this.fireEvent("change",this)}});Jx.Grid=new Class({Implements:[Options],domObj:null,model:null,options:{alternateRowColors:false,rowHeaders:false,columnHeaders:false,rowSelection:false,cellSelection:false},initialize:function(B,A){this.setOptions(A);this.domObj=$(B);var C=this.domObj.retrieve("jxLayout");if(C){C.addEvent("sizeChange",this.resize.bind(this))}this.rowColObj=new Element("div",{"class":"jxGridContainer"});this.colObj=new Element("div",{"class":"jxGridContainer"});this.colTable=new Element("table",{"class":"jxGridTable"});this.colTableHead=new Element("thead");this.colTable.appendChild(this.colTableHead);this.colTableBody=new Element("tbody");this.colTable.appendChild(this.colTableBody);this.colObj.appendChild(this.colTable);this.rowObj=new Element("div",{"class":"jxGridContainer"});this.rowTable=new Element("table",{"class":"jxGridTable"});this.rowTableHead=new Element("thead");this.rowTable.appendChild(this.rowTableHead);this.rowObj.appendChild(this.rowTable);this.gridObj=new Element("div",{"class":"jxGridContainer",styles:{overflow:"scroll"}});this.gridTable=new Element("table",{"class":"jxGridTable"});this.gridTableBody=new Element("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.gridObj.addEvent("scroll",this.onScroll.bind(this));this.gridObj.addEvent("click",this.onClickGrid.bindWithEvent(this));this.rowObj.addEvent("click",this.onClickRowHeader.bindWithEvent(this));this.colObj.addEvent("click",this.onClickColumnHeader.bindWithEvent(this));this.gridObj.addEvent("mousemove",this.onMouseMoveGrid.bindWithEvent(this));this.rowObj.addEvent("mousemove",this.onMouseMoveRowHeader.bindWithEvent(this));this.colObj.addEvent("mousemove",this.onMouseMoveColumnHeader.bindWithEvent(this))},onScroll:function(){this.colObj.scrollLeft=this.gridObj.scrollLeft;this.rowObj.scrollTop=this.gridObj.scrollTop},resize:function(){if(!this.model){return }var C=this.options.columnHeaders?this.model.getColumnHeaderHeight():1;var A=this.options.rowHeaders?this.model.getRowHeaderWidth():1;var B=Element.getContentBoxSize(this.domObj);this.rowColObj.setStyles({width:A-1,height:C-1});this.rowObj.setStyles({top:C,left:0,width:A-1,height:B.height-C-1});this.colObj.setStyles({top:0,left:A,width:B.width-A-1,height:C-1});this.gridObj.setStyles({top:C,left:A,width:B.width-A-1,height:B.height-C-1})},setModel:function(A){if(this.model){this.model.removeGridListener(this)}this.model=A;if(this.model){if(this.domObj.resize){this.domObj.resize()}this.model.addGridListener(this);this.createGrid();this.resize()}else{this.destroyGrid()}},destroyGrid:function(){var A=this.colTableHead.cloneNode(false);this.colTable.replaceChild(A,this.colTableHead);this.colTableHead=A;A=this.colTableBody.cloneNode(false);this.colTable.replaceChild(A,this.colTableBody);this.colTableBody=A;A=this.rowTableHead.cloneNode(false);this.rowTable.replaceChild(A,this.rowTableHead);this.rowTableHead=A;A=this.gridTableBody.cloneNode(false);this.gridTable.replaceChild(A,this.gridTableBody);this.gridTableBody=A},createGrid:function(){this.destroyGrid();if(this.model){var L=this.model;var E=L.getColumnCount();var Q=L.getRowCount();if(this.options.columnHeaders){var N=L.getColumnHeaderHeight();var P=new Element("tr");this.colTableHead.appendChild(P);var M=new Element("tr");this.colTableBody.appendChild(M);var C=new Element("th",{styles:{width:0,height:0}});P.appendChild(C);C=C.cloneNode(true);C.setStyle("height",N);M.appendChild(C);for(var K=0;K<E;K++){var J=L.getColumnWidth(K);C=new Element("th",{"class":"jxGridColHeadHide",styles:{width:J}});var B=new Element("p",{styles:{height:0,width:J}});C.appendChild(B);P.appendChild(C);C=new Element("th",{"class":"jxGridColHead",html:L.getColumnHeaderHTML(K)});M.appendChild(C)}var C=new Element("th",{styles:{width:1000,height:0}});P.appendChild(C);C=C.cloneNode(true);C.setStyle("height",N-1);C.className="jxGridColHead";M.appendChild(C)}if(this.options.rowHeaders){var H=L.getRowHeaderWidth();var O=new Element("tr");var G=new Element("td",{styles:{width:0,height:0}});O.appendChild(G);var C=new Element("th",{styles:{width:H,height:0}});O.appendChild(C);this.rowTableHead.appendChild(O);for(var K=0;K<Q;K++){var A=L.getRowHeight(K);var O=new Element("tr");var G=new Element("td",{"class":"jxGridRowHeadHide",styles:{width:0,height:A}});var B=new Element("p",{styles:{width:0,height:A}});G.appendChild(B);O.appendChild(G);var C=new Element("th",{"class":"jxGridRowHead",html:L.getRowHeaderHTML(K)});O.appendChild(C);this.rowTableHead.appendChild(O)}var O=new Element("tr");var G=new Element("td",{styles:{width:0,height:1000}});O.appendChild(G);var C=new Element("th",{"class":"jxGridRowHead",styles:{width:H,height:1000}});O.appendChild(C);this.rowTableHead.appendChild(O)}var N=L.getColumnHeaderHeight();var M=new Element("tr");this.gridTableBody.appendChild(M);var G=new Element("td",{styles:{width:0,height:0}});M.appendChild(G);for(var K=0;K<E;K++){var J=L.getColumnWidth(K);G=new Element("td",{"class":"jxGridColHeadHide",styles:{width:J}});var B=new Element("p",{styles:{width:J,height:0}});G.appendChild(B);M.appendChild(G)}for(var I=0;I<Q;I++){var A=L.getRowHeight(I);var D=A;var O=new Element("tr");this.gridTableBody.appendChild(O);var G=new Element("td",{"class":"jxGridRowHeadHide",styles:{width:0,height:A}});var B=new Element("p",{styles:{height:A}});G.appendChild(B);O.appendChild(G);for(var K=0;K<E;K++){var J=L.getColumnWidth(K);G=new Element("td",{"class":"jxGridCell"});G.innerHTML=L.getValueAt(I,K);O.appendChild(G);var F=G.getSize();if(F.height>D){D=F.height}}if(document.all){D-=1}if(this.options.rowHeaders){this.setRowHeaderHeight(I,D)}if(this.options.alternateRowColors){O.className=(I%2)?"jxGridRowOdd":"jxGridRowEven"}else{O.className="jxGridRowAll"}}}},setRowHeaderHeight:function(B,A){this.rowTableHead.childNodes[B+1].childNodes[0].childNodes[0].style.height=(A)+"px"},gridChanged:function(B,D,A,C){if(this.model==B){this.gridObj.childNodes[D].childNodes[A].innerHTML=C}},prelightRowHeader:function(B){var A=(B>=0&&B<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[B+1].cells[1]:null;if(this.prelitRowHeader!=A){if(this.prelitRowHeader){this.prelitRowHeader.removeClass("jxGridRowHeaderPrelight")}this.prelitRowHeader=A;if(this.prelitRowHeader){this.prelitRowHeader.addClass("jxGridRowHeaderPrelight")}}},prelightColumnHeader:function(B){if(this.colTableBody.rows.length==0){return }var A=(B>=0&&B<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[B+1]:null;if(this.prelitColumnHeader!=A){if(this.prelitColumnHeader){this.prelitColumnHeader.removeClass("jxGridColumnHeaderPrelight")}this.prelitColumnHeader=A;if(this.prelitColumnHeader){this.prelitColumnHeader.addClass("jxGridColumnHeaderPrelight")}}},prelightRow:function(B){var A=(B>=0&&B<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[B+1]:null;if(this.prelitRow!=B){if(this.prelitRow){this.prelitRow.removeClass("jxGridRowPrelight")}this.prelitRow=A;if(this.prelitRow&&!this.prelitRow.hasClass("jxGridRowSelected")){this.prelightRowHeader(B);this.prelitRow.addClass("jxGridRowPrelight")}}},prelightColumn:function(A){this.prelightColumnHeader(A)},prelightCell:function(B,A){var C=(B>=0&&A>=0&&B<this.gridTableBody.rows.length-1&&A<this.gridTableBody.rows[B+1].cells.length-1)?this.gridTableBody.rows[B+1].cells[A+1]:null;if(this.prelitCell!=C){if(this.prelitCell){this.prelitCell.removeClass("jxGridCellPrelight")}this.prelitCell=C;if(this.prelitCell){this.prelitCell.addClass("jxGridCellPrelight");this.prelightRow(B);this.prelightColumn(A)}}},selectCell:function(B,A){var C=(B>=0&&A>=0&&B<this.gridTableBody.rows.length-1&&A<this.gridTableBody.rows[B+1].cells.length-1)?this.gridTableBody.rows[B+1].cells[A+1]:null;if(!C){return }if(this.selectedCell){this.selectedCell.addClass("jxGridCellSelected")}else{this.selectedCell.removeClass("jxGridCellSelected")}},selectRowHeader:function(C,B){var A=(C>=0&&C<this.rowTableHead.rows.length-1)?this.rowTableHead.rows[C+1].cells[1]:null;if(!A){return }if(B){A.addClass("jxGridRowHeaderSelected")}else{A.removeClass("jxGridRowHeaderSelected")}},selectRow:function(C,A){var B=(C>=0&&C<this.gridTableBody.rows.length-1)?this.gridTableBody.rows[C+1]:null;if(B){if(A){B.addClass("jxGridRowSelected")}else{B.removeClass("jxGridRowSelected")}}this.selectRowHeader(C,A)},selectColumnHeader:function(B,C){if(this.colTableBody.rows.length==0){return }var A=(B>=0&&B<this.colTableBody.rows[0].cells.length-1)?this.colTableBody.rows[0].cells[B+1]:null;if(A==null){return }if(C){A.addClass("jxGridColumnHeaderSelected")}else{A.removeClass("jxGridColumnHeaderSelected")}},selectColumn:function(A,C){if(A>=0&&A<this.gridTable.rows[0].cells.length){if(C){for(var B=0;B<this.gridTable.rows.length;B++){this.gridTable.rows[B].cells[this.selectedColumn+1].removeClass("jxGridColumnSelected")}}else{for(var B=0;B<this.gridTable.rows.length;B++){this.gridTable.rows[B].cells[A+1].addClass("jxGridColumnSelected")}}}this.selectColumnHeader(A,C)},onMouseMoveGrid:function(B){var A=this.getRowColumnFromEvent(B);this.prelightCell(A.row,A.column)},onMouseMoveRowHeader:function(B){var A=this.getRowColumnFromEvent(B);this.prelightRow(A.row)},onMouseMoveColumnHeader:function(B){var A=this.getRowColumnFromEvent(B);this.prelightColumn(A.column)},onClickGrid:function(B){var A=this.getRowColumnFromEvent(B);if(this.model.cellSelected){this.model.cellSelected(this,A.row,A.column)}},onClickRowHeader:function(B){var A=this.getRowColumnFromEvent(B);if(this.model.rowSelected){this.model.rowSelected(this,A.row)}},onClickColumnHeader:function(B){var A=this.getRowColumnFromEvent(B);if(this.model.columnSelected){this.model.columnSelected(this,A.column)}},getRowColumnFromEvent:function(D){var F=D.target;if(F.tagName!="TD"&&F.tagName!="TH"){return{row:-1,column:-1}}var C=F.parentNode;var A=F.cellIndex-1;var E=C.rowIndex-1;if(A==-1){for(var B=0;B<C.childNodes.length;B++){if(C.childNodes[B]==F){A=B-1;break}}}return{row:E,column:A}}});Jx.Layout=new Class({Implements:[Options,Events],options:{propagate:true,position:"absolute",left:0,right:0,top:0,bottom:0,width:null,height:null,minWidth:0,minHeight:0,maxWidth:-1,maxHeight:-1},initialize:function(B,A){this.setOptions(A);this.domObj=$(B);this.domObj.resize=this.resize.bind(this);this.domObj.setStyle("position",this.options.position);this.domObj.store("jxLayout",this);if(document.body==this.domObj.parentNode){window.addEvent("resize",this.windowResize.bindWithEvent(this));window.addEvent("load",this.resize.bind(this))}},windowResize:function(){if(this.resizeTimer){$clear(this.resizeTimer);this.resizeTimer=null}this.resizeTimer=this.resize.delay(100,this)},resize:function(K){this.resizeTimer=null;var B=false;if(K){for(var F in K){if(F=="forceResize"){continue}if(this.options[F]!=K[F]){B=true;this.options[F]=K[F]}}if(K.forceResize){B=true}}if(!$(this.domObj.parentNode)){return }var C;if(this.domObj.parentNode.tagName=="BODY"){C=Element.getPageDimensions()}else{C=$(this.domObj.parentNode).getContentBoxSize()}if(this.lastParentSize&&!B){B=(this.lastParentSize.width!=C.width||this.lastParentSize.height!=C.height)}else{B=true}this.lastParentSize=C;if(!B){return }var D,J,I,G;if(this.options.left!=null){D=this.options.left;if(this.options.right==null){if(this.options.width==null){I=C.width-D;if(I<this.options.minWidth){I=this.options.minWidth}if(this.options.maxWidth>=0&&I>this.options.maxWidth){I=this.options.maxWidth}}else{I=this.options.width}}else{if(this.options.width==null){I=C.width-D-this.options.right;if(I<this.options.minWidth){I=this.options.minWidth}if(this.options.maxWidth>=0&&I>this.options.maxWidth){I=this.options.maxWidth}}else{I=this.options.width}}}else{if(this.options.right==null){if(this.options.width==null){D=0;I=C.width;if(this.options.maxWidth>=0&&I>this.options.maxWidth){D=D+parseInt(I-this.options.maxWidth)/2;I=this.options.maxWidth}}else{I=this.options.width;D=parseInt((C.width-I)/2);if(D<0){D=0}}}else{if(this.options.width!=null){I=this.options.width;D=C.width-I-this.options.right;if(D<0){D=0}}else{D=0;I=C.width-this.options.right;if(I<this.options.minWidth){I=this.options.minWidth}if(this.options.maxWidth>=0&&I>this.options.maxWidth){D=I-this.options.maxWidth-this.options.right;I=this.options.maxWidth}}}}if(this.options.top!=null){J=this.options.top;if(this.options.bottom==null){if(this.options.height==null){G=C.height-J;if(G<this.options.minHeight){G=this.options.minHeight}if(this.options.maxHeight>=0&&G>this.options.maxHeight){G=this.options.maxHeight}}else{G=this.options.height;if(this.options.maxHeight>=0&&G>this.options.maxHeight){J=G-this.options.maxHeight;G=this.options.maxHeight}}}else{if(this.options.height==null){G=C.height-J-this.options.bottom;if(G<this.options.minHeight){G=this.options.minHeight}if(this.options.maxHeight>=0&&G>this.options.maxHeight){G=this.options.maxHeight}}else{G=this.options.height}}}else{if(this.options.bottom==null){if(this.options.height==null){J=0;G=C.height;if(G<this.options.minHeight){G=this.options.minHeight}if(this.options.maxHeight>=0&&G>this.options.maxHeight){J=parseInt((C.height-this.options.maxHeight)/2);G=this.options.maxHeight}}else{G=this.options.height;J=parseInt((C.height-G)/2);if(J<0){J=0}}}else{if(this.options.height!=null){G=this.options.height;J=C.height-G-this.options.bottom;if(J<0){J=0}}else{J=0;G=C.height-this.options.bottom;if(G<this.options.minHeight){G=this.options.minHeight}if(this.options.maxHeight>=0&&G>this.options.maxHeight){J=C.height-this.options.maxHeight-this.options.bottom;G=this.options.maxHeight}}}}var E={width:I};if(this.options.position=="absolute"){var H=$(this.domObj.parentNode).getPaddingSize();this.domObj.setStyles({position:this.options.position,left:D+H.left,top:J+H.top});E.height=G}else{if(this.options.height){E.height=this.options.height}}this.domObj.setBorderBoxSize(E);if(this.options.propagate){var A={forceResize:K?K.forceResize:false};$A(this.domObj.childNodes).each(function(L){if(L.resize&&L.getStyle("display")!="none"){L.resize(A)}})}this.fireEvent("sizeChange",this)}});Jx.Menu=new Class({Implements:[Jx.AutoPosition,Jx.Chrome],domObj:null,button:null,subDomObj:null,items:null,initialize:function(A){if(!Jx.Menu.Menus){Jx.Menu.Menus=[]}this.items=[];this.contentContainer=new Element("div",{"class":"jxMenuContainer"});this.subDomObj=new Element("ul",{"class":"jxMenu"});this.contentContainer.adopt(this.subDomObj);if(A){this.domObj=new Element("li",{id:A.id,events:{mouseover:this.onMouseOver.bindWithEvent(this)}});this.button=new Jx.Button($merge(A,{onClick:this.show.bind(this)}));this.button.domA.addClass("jxButtonMenu");this.domObj.adopt(this.button.domObj)}this.hideWatcher=this.hide.bindWithEvent(this);this.keypressWatcher=this.keypressHandler.bindWithEvent(this)},add:function(){$A(arguments).each(function(A){this.items.push(A);A.setOwner(this);this.subDomObj.adopt(A.domObj)},this)},deactivate:function(){this.hide()},actionPerformed:function(){this.hide()},onMouseOver:function(A){if(Jx.Menu.Menus[0]&&Jx.Menu.Menus[0]!=this){this.show({event:A})}},hide:function(A){if(A){if(A.target.descendantOf(this.domObj)||A.target.descendantOf(this.subDomObj)){return }}if(Jx.Menu.Menus[0]&&Jx.Menu.Menus[0]==this){Jx.Menu.Menus[0]=null}if(this.domA){this.domA.removeClass("jx"+this.button.options.type+"Active")}this.contentContainer.dispose();this.items.each(function(B){B.hide(A)});document.removeEvent("mousedown",this.hideWatcher);document.removeEvent("keyup",this.keypressWatcher)},show:function(B){var A=B.event;if(Jx.Menu.Menus[0]&&Jx.Menu.Menus[0]!=this){Jx.Menu.Menus[0].hide(A)}if(this.items.length==0){return }Jx.Menu.Menus[0]=this;this.contentContainer.setStyle("visibility","hidden");document.body.adopt(this.contentContainer);this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());this.showChrome(this.contentContainer);this.position(this.contentContainer,this.button.domObj,{horizontal:["left left"],vertical:["bottom top","top bottom"],offsets:this.chromeOffsets});this.contentContainer.setStyle("visibility","");if(this.domA){this.domA.addClass("jx"+this.button.options.type+"Active")}if(A){A.stop()}document.addEvent("mousedown",this.hideWatcher);document.addEvent("keyup",this.keypressWatcher)},setVisibleItem:function(A){if(this.visibleItem!=A){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide()}this.visibleItem=A;this.visibleItem.show()}},keypressHandler:function(A){A=new Event(A);if(A.key=="esc"){this.hide()}}});Jx.Menu.Item=new Class({Implements:[Options,Events],Extends:Jx.Button,owner:null,button:null,options:{enabled:true,image:Jx.baseURL+"images/a_pixel.png",label:"&nbsp;"},initialize:function(A){this.parent($merge(A,{container:"li",type:"MenuItem"}));this.domObj.addEvent("mouseover",this.onMouseOver.bindWithEvent(this));if(!this.options.enabled){this.domObj.addClass("jxMenuItemDisabled")}},setOwner:function(A){this.owner=A},hide:$empty,show:$empty,clicked:function(A){if(this.options.enabled){if(this.options.toggle){this.setActive(!this.options.isActive)}this.fireEvent("click",this);if(this.owner&&this.owner.deactivate){this.owner.deactivate(A.event)}}},propertyChanged:function(A){this.options.enabled=A.isEnabled();if(this.options.enabled){this.domObj.removeClass("jxMenuItemDisabled")}else{if(!this.domObj.hadClass("jxMenuItemDisabled")){this.domObj.addClass("jxMenuItemDisabled")}}},onMouseOver:function(A){if(this.owner&&this.owner.setVisibleItem){this.owner.setVisibleItem(this)}this.show(A)}});Jx.Menu.Separator=new Class({domObj:null,owner:null,initialize:function(){this.domObj=new Element("li",{"class":"jxMenuItem"});var A=new Element("span",{"class":"jxMenuSeparator",html:"&nbsp;"});this.domObj.appendChild(A)},setOwner:function(A){this.owner=A},hide:$empty,show:$empty});Jx.Menu.SubMenu=new Class({Extends:Jx.Menu.Item,Implements:[Options,Events,Jx.AutoPosition,Jx.Chrome],subDomObj:null,owner:null,visibleItem:null,items:null,initialize:function(A){this.open=false;this.items=[];this.parent(A);this.domA.addClass("jxButtonSubMenu");this.contentContainer=new Element("div",{"class":"jxMenuContainer"});this.subDomObj=new Element("ul",{"class":"jxSubMenu"});this.contentContainer.adopt(this.subDomObj)},setOwner:function(A){this.owner=A},show:function(){if(this.open||this.items.length==0){return }this.contentContainer.setStyle("visibility","hidden");document.body.adopt(this.contentContainer);this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());this.showChrome(this.contentContainer);this.position(this.contentContainer,this.domObj,{horizontal:["right left","left right"],vertical:["top top"],offsets:this.chromeOffsets});this.open=true;this.contentContainer.setStyle("visibility","");this.setActive(true)},hide:function(){if(!this.open){return }this.open=false;this.items.each(function(A){A.hide()});this.contentContainer.dispose();this.visibleItem=null},add:function(){var A=this;$A(arguments).each(function(B){A.items.push(B);B.setOwner(A);A.subDomObj.adopt(B.domObj)})},insertBefore:function(C,D){var B=false;for(var A=0;A<this.items.length;A++){if(this.items[A]==D){this.items.splice(A,0,C);this.subDomObj.insertBefore(C.domObj,D.domObj);B=true;break}}if(!B){this.add(C)}},remove:function(B){for(var A=0;A<this.items.length;A++){if(this.items[A]==B){this.items.splice(A,1);this.subDomObj.removeChild(B.domObj);break}}},processActionEvent:function(A){if(this.open){this.hide()}else{this.show()}if(A&&A.event){A.event.stop()}},deactivate:function(A){if(this.owner){this.owner.deactivate(A)}},isActive:function(){if(this.owner){return this.owner.isActive()}else{return false}},setActive:function(A){if(this.owner&&this.owner.setActive){this.owner.setActive(A)}},setVisibleItem:function(A){if(this.visibleItem!=A){if(this.visibleItem&&this.visibleItem.hide){this.visibleItem.hide()}this.visibleItem=A;this.visibleItem.show()}}});Jx.Menu.Context=new Class({Extends:Jx.Menu,initialize:function(A){this.parent();if($(A)){$(A).addEvent("contextmenu",this.show.bindWithEvent(this))}},show:function(A){if(this.items.length==0){return }this.contentContainer.setStyle("visibility","hidden");document.body.adopt(this.contentContainer);this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());this.position(this.contentContainer,document.body,{horizontal:[A.page.x+" left"],vertical:[A.page.y+" top",A.page.y+" bottom"],offsets:this.chromeOffsets});this.contentContainer.setStyle("visibility","");this.showChrome(this.contentContainer);document.addEvent("mousedown",this.hideWatcher);document.addEvent("keyup",this.keypressWatcher);A.stop()}});Jx.Panel=new Class({Implements:[Options,Events,Jx.UniqueId,Jx.ContentLoader],toolbarContainers:{top:null,right:null,bottom:null,left:null},options:{label:"&nbsp;",imageBaseUrl:Jx.baseURL+"images/",position:"absolute",height:null,collapse:true,detach:false,close:false,closed:false,hideTitle:false,type:"Panel"},initialize:function(O){this.toolbars=O.toolbars||[];this.setOptions(O);if($defined(this.options.height)&&!$defined(O.position)){this.options.position="relative"}this.initUniqueId();this.title=new Element("div",{"class":"jx"+this.options.type+"Title"});this.labelObj=new Element("span",{"class":"jx"+this.options.type+"Label",html:this.options.label});this.title.adopt(this.labelObj);var L=new Element("div",{"class":"jx"+this.options.type+"Controls"});var F=new Element("div");L.adopt(F);this.toolbar=new Jx.Toolbar({parent:F});this.title.adopt(L);var G=this;if(this.options.menu){this.menu=new Jx.Menu({image:Jx.baseURL+"images/panel_controls.png"});this.menu.domObj.addClass("jx"+this.options.type+"Menu");this.menu.domObj.addClass("jxButtonContentLeft");this.toolbar.add(this.menu)}if(this.options.collapse){var I=new Jx.Button({image:Jx.baseURL+"images/panel_controls.png",tooltip:"Collapse/Expand Panel",onClick:function(){G.toggleCollapse()}});I.domObj.addClass("jx"+this.options.type+"Collapse");this.toolbar.add(I);if(this.menu){var N=new Jx.Menu.Item({label:"Collapse",onClick:function(){G.toggleCollapse()}});var E=N.button;this.addEvent("collapse",function(){if(G.options.closed){E.setLabel("Expand")}else{E.setLabel("Collapse")}});this.menu.add(N)}}if(this.options.maximize){var I=new Jx.Button({image:Jx.baseURL+"images/panel_controls.png",tooltip:"Maximize Panel",onClick:function(){G.maximize()}});I.domObj.addClass("jx"+this.options.type+"Maximize");this.toolbar.add(I);if(this.menu){var N=new Jx.Menu.Item({label:"Maximize",onClick:function(){G.maximize()}});this.menu.add(N)}}if(this.options.close){var I=new Jx.Button({image:Jx.baseURL+"images/panel_controls.png",tooltip:"Close Panel",onClick:function(){G.close()}});I.domObj.addClass("jx"+this.options.type+"Close");this.toolbar.add(I);if(this.menu){var N=new Jx.Menu.Item({label:"Close",onClick:function(){G.close()}});this.menu.add(N)}}this.title.addEvent("dblclick",function(){G.toggleCollapse()});this.domObj=new Element("div",{"class":"jx"+this.options.type});if(this.options.id){this.domObj.id=this.options.id}if($(this.options.parent)){$(this.options.parent).adopt(this.domObj)}var H=new Jx.Layout(this.domObj,$merge(this.options,{propagate:false}));var M=this.layoutContent.bind(this);H.addEvent("sizeChange",M);if(!this.options.hideTitle){this.domObj.adopt(this.title)}this.contentContainer=new Element("div",{"class":"jx"+this.options.type+"ContentContainer"});this.domObj.adopt(this.contentContainer);for(var B=0;B<this.toolbars.length;B++){var A=this.toolbars[B];A.addEvent("add",M);A.addEvent("remove",M);var D=A.options.position;var K=this.toolbarContainers[D];if(!K){var K=new Element("div",{"class":"jxToolbarContainer jxBar"+D.capitalize()});new Jx.Layout(K);var C=new Element("div",{"class":"jxClearer"});K.appendChild(C);this.contentContainer.adopt(K);this.toolbarContainers[D]=K}var J=A.domObj;K.insertBefore(J,K.lastChild)}this.content=new Element("div",{"class":"jx"+this.options.type+"Content"});new Jx.Layout(this.contentContainer);new Jx.Layout(this.content);this.contentContainer.adopt(this.content);this.loadContent(this.content,O);this.toggleCollapse(this.options.closed)},layoutContent:function(){var G=0;var H=0;var A=0;var C=0;var J=0;var I;var D;var F;if(!this.options.hideTitle&&this.title.parentNode==this.domObj){G=this.title.getMarginBoxSize().height}var B=this.domObj.getContentBoxSize();if(B.height>G){this.contentContainer.setStyle("display","block");this.options.closed=false;this.contentContainer.resize({top:G,height:null,bottom:0});["left","right"].each(function(L){if(this.toolbarContainers[L]){this.toolbarContainers[L].style.width=""}},this);["top","bottom"].each(function(L){if(this.toolbarContainers[L]){this.toolbarContainers[L].style.height=""}},this);for(var E=0;E<this.toolbars.length;E++){D=this.toolbars[E];F=D.options.position;I=this.toolbarContainers[F];var K=I.getBorderBoxSize();switch(F){case"top":H=K.height;break;case"bottom":A=K.height;break;case"left":C=K.width;break;case"right":J=K.width;break}}I=this.toolbarContainers.top;if(I){I.resize({top:0,left:C,right:J,bottom:null,height:H,width:null})}I=this.toolbarContainers.bottom;if(I){I.resize({top:null,left:C,right:J,bottom:0,height:A,width:null})}I=this.toolbarContainers.left;if(I){I.resize({top:H,left:0,right:null,bottom:A,height:null,width:C})}I=this.toolbarContainers.right;if(I){I.resize({top:H,left:null,right:0,bottom:A,height:null,width:J})}this.content.resize({top:H,bottom:A,left:C,right:J})}else{this.contentContainer.setStyle("display","none");this.options.closed=true}},setLabel:function(A){this.labelObj.innerHTML=A},getLabel:function(){return this.labelObj.innerHTML},finalize:function(){this.domObj=null;this.deregisterIds()},maximize:function(){if(this.manager){this.manager.maximizePanel(this)}},setContent:function(A){this.content.innerHTML=A;this.bContentReady=true},setContentURL:function(B){this.bContentReady=false;this.setBusy(true);if(arguments[1]){this.onContentReady=arguments[1]}if(B.indexOf("?")==-1){B=B+"?"}var C={method:"get",onComplete:this.panelContentLoaded.bind(this),requestHeaders:["If-Modified-Since","Sat, 1 Jan 2000 00:00:00 GMT"]};var A=new Request(B,C).send()},panelContentLoaded:function(A){this.content.innerHTML=A.responseText;this.bContentReady=true;this.setBusy(false);if(this.onContentReady){window.setTimeout(this.onContentReady.bind(this),1)}},setBusy:function(A){this.busyCount+=A?1:-1;this.loadingObj.img.style.visibility=(this.busyCount>0)?"visible":"hidden"},addTo:function(B,A){B=$(B);A=A?$(A):null;if(A&&A.parentNode==B){B.insertBefore(this.domObj,A)}else{B.appendChild(this.domObj)}this.domObj.resize()},toggleCollapse:function(C){if($defined(C)){this.options.closed=C}else{this.options.closed=!this.options.closed}if(this.options.closed){if(!this.domObj.hasClass("jx"+this.options.type+"Min")){this.domObj.addClass("jx"+this.options.type+"Min");this.contentContainer.setStyle("display","none");var B=this.domObj.getMarginSize();var A=B.top+B.bottom;if(this.title.parentNode==this.domObj){A+=this.title.getMarginBoxSize().height}this.domObj.resize({height:A});this.fireEvent("collapse",this)}}else{if(this.domObj.hasClass("jx"+this.options.type+"Min")){this.domObj.removeClass("jx"+this.options.type+"Min");this.contentContainer.setStyle("display","block");this.domObj.resize({height:this.options.height});this.fireEvent("expand",this)}}},close:function(){this.domObj.dispose();this.fireEvent("close",this)}});Jx.Dialog=new Class({Extends:Jx.Panel,Implements:[Jx.AutoPosition,Jx.Chrome],blanket:null,options:{modal:true,position:"absolute",width:250,height:250,left:0,top:0,bottom:null,right:null,label:"New Dialog",id:"",parent:null,resize:false,move:true,close:true,collapse:true},initialize:function(A){if(!Jx.Dialog.Stack){Jx.Dialog.Stack=[];Jx.Dialog.ZIndex=[100]}this.isOpening=false;this.parent($merge({parent:document.body},A,{type:"Dialog",position:"absolute"}));this.options.parent=$(this.options.parent);if(!window.opera&&this.options.modal){this.blanket=new Element("div",{"class":"jxDialogModal",styles:{display:"none",zIndex:-1}});this.options.parent.adopt(this.blanket);(new Jx.Layout(this.blanket)).resize()}this.domObj.setStyle("display","none");this.options.parent.adopt(this.domObj);if(this.options.move){this.title.addClass("jxDialogMoveable");new Drag(this.domObj,{handle:this.title,onStart:(function(){this.contentContainer.setStyle("visibility","hidden")}).bind(this),onComplete:(function(){this.contentContainer.setStyle("visibility","");this.position(this.domObj,this.options.parent,{horizontal:[parseInt(this.domObj.style.left)+" left"],vertical:[parseInt(this.domObj.style.top)+" top"]});this.options.left=parseInt(this.domObj.style.left);this.options.top=parseInt(this.domObj.style.top);if(!this.options.closed){this.domObj.resize(this.options)}}).bind(this)})}if(this.options.resize){this.resizeHandle=new Element("div",{"class":"jxDialogResize",styles:{display:this.options.closed?"none":"block"}});this.domObj.appendChild(this.resizeHandle);this.resizeHandleSize=this.resizeHandle.getSize();this.resizeHandle.setStyles({bottom:this.resizeHandleSize.height,right:this.resizeHandleSize.width});this.domObj.makeResizable({handle:this.resizeHandle,onStart:(function(){this.contentContainer.setStyle("visibility","hidden")}).bind(this),onDrag:this.resizeChrome.bind(this),onComplete:(function(){var B=this.domObj.getMarginBoxSize();this.options.width=B.width;this.options.height=B.height;this.layoutContent();this.domObj.resize(this.options);this.contentContainer.setStyle("visibility","");this.fireEvent("resize")}).bind(this)})}this.domObj.addEvent("mousedown",(function(){Jx.Dialog.Stack.erase(this).push(this);Jx.Dialog.Stack.each(function(C,B){C.domObj.setStyle("zIndex",101+B)})}).bind(this))},sizeChanged:function(){if(!this.options.closed){this.layoutContent();this.resizeChrome()}},toggleCollapse:function(C){if($defined(C)){this.options.closed=C}else{this.options.closed=!this.options.closed}if(this.options.closed){if(!this.domObj.hasClass("jx"+this.options.type+"Min")){this.domObj.addClass("jx"+this.options.type+"Min")}this.contentContainer.setStyle("display","none");if(this.resizeHandle){this.resizeHandle.setStyle("display","none")}}else{if(this.domObj.hasClass("jx"+this.options.type+"Min")){this.domObj.removeClass("jx"+this.options.type+"Min")}this.contentContainer.setStyle("display","block");if(this.resizeHandle){this.resizeHandle.setStyle("display","block")}}if(this.options.closed){var B=this.domObj.getMarginSize();var A=this.title.getMarginBoxSize();this.domObj.resize({height:B.top+A.height+B.bottom});this.fireEvent("collapse")}else{this.domObj.resize(this.options);this.fireEvent("expand")}},setTitle:function(A){this.title.childNodes[0].innerHTML=A},show:function(){Jx.Dialog.Stack.push(this);if(this.options.modal){this.blanket.setStyles({zIndex:Jx.Dialog.ZIndex[0]++,visibility:"visible",display:"block"})}this.domObj.setStyles({zIndex:Jx.Dialog.ZIndex[0]++,display:"block"});if(this.options.closed){var B=this.domObj.getMarginSize();var A=this.title.getMarginBoxSize();this.domObj.resize({height:B.top+A.height+B.bottom})}else{this.domObj.resize(this.options)}this.showChrome(this.domObj);this.position(this.domObj,this.options.parent,{horizontal:[this.options.left+" left"],vertical:[this.options.top+" top"]});this.options.left=parseInt(this.domObj.style.left);this.options.top=parseInt(this.domObj.style.top)},hide:function(){Jx.Dialog.Stack.erase(this);Jx.Dialog.ZIndex[0]--;this.domObj.setStyle("display","none");if(this.options.modal){this.blanket.setStyle("visibility","hidden");Jx.Dialog.ZIndex[0]--}},open:function(){if(!this.isOpening){this.isOpening=true}if(this.contentIsLoaded){this.show();this.fireEvent("open",this);this.isOpening=false}},close:function(){this.isOpening=false;this.hide();this.fireEvent("close")},onContentLoaded:function(){if(this.isOpening){this.open()}}});Jx.PanelSet=new Class({panels:null,height:null,firstLayout:true,initialize:function(C,B){this.domObj=$(C);this.panels=B;var H=new Element("div",{styles:{position:"absolute"}});new Jx.Layout(H,{minHeight:0,maxHeight:0,height:0});var G=[H];B.each(function(I){G.push(I.domObj);I.options.hideTitle=true;I.contentContainer.resize({top:0});I.addEvent("expand",this.maximizePanel.bind(this,I));I.domObj.store("Jx.Panel",I)},this);this.splitter=new Jx.Splitter(this.domObj,{splitInto:B.length+1,layout:"vertical",elements:G});this.splitter.sizeChanged=this.sizeChanged.bind(this);for(var E=0;E<this.panels.length;E++){var A=this.panels[E];var F=this.splitter.bars[E];A.title.setStyle("visibility","hidden");document.body.adopt(A.title);var D=A.title.getBorderBoxSize();F.adopt(A.title);A.title.setStyle("visibility","");F.setStyle("height",D.height);F.removeClass("jxSplitterBar");F.addClass("jxPanelBar");A.manager=this}},sizeChanged:function(){if(this.firstLayout){if(this.panels[0].title.getBorderBoxSize().height!=0){for(var B=0;B<this.splitter.bars.length;B++){var A=this.panels[B];this.splitter.bars[B].style.height=A.title.getBorderBoxSize().height+"px";this.splitter.bars[B].store("size",null)}this.firstLayout=false;Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[])}}else{Jx.Splitter.prototype.sizeChanged.apply(this.splitter,[])}},maximizePanel:function(A){var E=this.domObj.getContentBoxSize().height;var D=0;for(var C=1;C<this.splitter.elements.length;C++){var F=this.splitter.elements[C];D+=F.retrieve("leftBar").getBorderBoxSize().height;if(F!==A.domObj){var B=F.retrieve("Jx.Panel");var G=F.retrieve("jxLayout").options;F.resize({top:D,height:G.minHeight,bottom:null});D+=G.minHeight;F.retrieve("rightBar").style.top=D+"px"}else{break}}b=E;for(var C=this.splitter.elements.length-1;C>0;C--){F=this.splitter.elements[C];if(F!==A.domObj){var G=F.retrieve("jxLayout").options;b-=G.minHeight;F.resize({top:b,height:G.minHeight,bottom:null});b-=F.retrieve("leftBar").getBorderBoxSize().height;F.retrieve("leftBar").style.top=b+"px"}else{break}}A.domObj.resize({top:D,height:b-D,bottom:null})}});Jx.Combo=new Class({Implements:[Options,Events,Jx.AutoPosition],domObj:null,ul:null,currentSelection:null,initialize:function(A){this.setOptions(A);this.domObj=new Element("div",{"class":"jxCombo"});if(this.options.id){this.domObj.id=this.options.id}if(this.options.editable){this.domInput=new Element("input",{"class":"jxComboInput",type:"text",events:{change:this.valueChanged.bindWithEvent(this),keydown:this.onKeyPress.bindWithEvent(this)}})}else{this.domInput=new Element("span",{"class":"jxComboInput"})}this.domObj.appendChild(this.domInput);this.domA=new Element("a",{"class":"jxComboDiscloser",href:"javascript:void(0)",events:{click:this.toggle.bind(this)}});this.domButton=new Element("img",{"class":"png24",src:Jx.baseURL+"images/disclose2.png"});this.domA.appendChild(this.domButton);this.domObj.appendChild(this.domA);if(!window.opera){this.domObj.appendChild(Jx.createIframeShim())}this.domListDiv=new Element("div",{"class":"jxComboOptions"});this.domList=new Element("ul");this.domListDiv.appendChild(this.domList);this.keypressHandler=this.keypress.bindWithEvent(this);this.clickHandler=this.click.bindWithEvent(this)},onKeyPress:function(A){if(A.key=="enter"){this.valueChanged()}},valueChanged:function(){this.fireEvent("changed",this)},add:function(D,B){var A=new Element("li");var C=new Element("a",{href:"javascript:void(0)",events:{click:this.pick.bindWithEvent(this)}});if($type(D)=="string"){C.innerHTML=D}else{C.appendChild(D)}A.appendChild(C);if(arguments.length>1&&this.domList.childNodes.length>B){this.domList.insertBefore(A,this.domList.childNodes[B])}else{this.domList.appendChild(A)}if(this.getValue()==""){this.setValue(C.childNodes[0])}},remove:function(A){if(A>0&&A<this.domList.childNodes.length){this.domList.removeChild(this.domList.childNodes[A])}},pick:function(B){var A=B.target;if(A.tagName=="A"){this.currentSelection=A;this.setValue(this.currentSelection.childNodes[0]);this.valueChanged()}this.close()},setValue:function(A){if(this.options.editable){if(typeof (A)=="string"){this.domInput.value=A}else{if(A.nodeType&&A.nodeType==3){this.domInput.value=A.nodeValue}else{this.domInput.value=A.innerHTML}}}else{if(typeof (A)=="string"){this.domInput.innerHTML=A}else{if(A.nodeType&&A.nodeType==3){this.domInput.innerHTML=A.nodeValue}else{this.domInput.appendChild(A)}}}},getValue:function(){value="";if(this.options.editable){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(){this.position(this.domListDiv,this.domObj,{horizontal:["left left","right right"],vertical:["bottom top","top bottom"]});this.domListDiv.width="";this.domListDiv.setStyle("visibility","hidden");document.body.adopt(this.domListDiv);this.domListDiv.setBorderBoxSize({width:Math.max(this.domListDiv.getSize().x,this.domObj.getSize().x)});this.domListDiv.setStyle("visibility","");document.addEvents({keydown:this.keypressHandler,click:this.clickHandler})},keypress:function(A){if(A.key=="esc"){this.close()}},click:function(A){if(!A.target.descendantOf(this.domListDiv)&&!A.target.descendantOf(this.domObj)){this.close()}},close:function(){this.domListDiv.dispose();document.removeEvents({keydown:this.keypressHandler,click:this.clickHandler})},getSelection:function(){return this.currentSelection?this.currentSelection.name:""}});Jx.Splitter=new Class({Implements:[Options],domObj:null,elements:null,bars:null,firstUpdate:true,options:{useChildren:false,splitInto:2,elements:null,containerOptions:[],barOptions:[],layout:"horizontal",snaps:[]},initialize:function(A,I){this.setOptions(I);this.domObj=$(A);this.domObj.addClass("jxSplitContainer");this.domObj.setStyle("overflow","hidden");var H=this.domObj.retrieve("jxLayout");if(H){H.addEvent("sizeChange",this.sizeChanged.bind(this))}this.elements=[];this.bars=[];var G=2;if(this.options.useChildren){this.elements=this.domObj.getChildren();G=this.elements.length}else{G=this.options.elements?this.options.elements.length:this.options.splitInto;for(var E=0;E<G;E++){var C;if(this.options.elements&&this.options.elements[E]){C=$(this.options.elements[E]);if(!C){C=this.prepareElement();C.id=this.options.elements[E]}}else{C=this.prepareElement()}this.elements[E]=C;this.domObj.adopt(this.elements[E])}}this.elements.each(function(J){J.addClass("jxSplitArea")});for(var E=0;E<G;E++){if(!this.elements[E].retrieve("jxLayout")){new Jx.Layout(this.elements[E],this.options.containerOptions[E])}}for(var E=1;E<G;E++){this.bars[E-1]=this.prepareBar();this.bars[E-1].store("leftSide",this.elements[E-1]);this.bars[E-1].store("rightSide",this.elements[E]);this.elements[E-1].store("rightBar",this.bars[E-1]);this.elements[E].store("leftBar",this.bars[E-1]);this.domObj.adopt(this.bars[E-1])}this.establishConstraints();for(var E=0;E<this.options.barOptions.length;E++){if(!this.bars[E]){continue}var B=this.options.barOptions[E];if(B&&B.snap&&(B.snap=="before"||B.snap=="after")){var F;if(B.snap=="before"){F=this.bars[E].retrieve("leftSide")}else{if(B.snap=="after"){F=this.bars[E].retrieve("rightSide")}}var D=new Element("a",{"class":"jxSnap"+this.options.layout.capitalize()+B.snap.capitalize(),href:"javascript:void(0)"});this.bars[E].adopt(D);new Jx.Splitter.Snap(D,F,this)}}for(var E=0;E<this.options.snaps.length;E++){if(this.options.snaps[E]){new Jx.Splitter.Snap(this.options.snaps[E],this.elements[E],this)}}},prepareElement:function(){var A=new Element("div",{styles:{position:"absolute"}});return A},prepareBar:function(){var A=new Element("div",{"class":"jxSplitBar"+this.options.layout.capitalize(),title:"drag this bar to resize"});A.store("splitterObj",this);return A},establishConstraints:function(){var A={};var B;if(this.options.layout=="horizontal"){A.y=[0,0];B=this.dragHorizontal}else{A.x=[0,0];B=this.dragVertical}this.bars.each(function(C){new Drag(C,{limit:A,onSnap:function(D){D.addClass("jxSplitBarDrag")},onComplete:(function(D){D.removeClass("jxSplitBarDrag");if(D.retrieve("splitterObj")!=this){return }B.apply(this,[D])}).bind(this)})},this)},dragHorizontal:function(F){var A=parseInt(F.style.left);var H=F.retrieve("leftSide");var C=F.retrieve("rightSide");var D=H.retrieve("jxLayout");var G=C.retrieve("jxLayout");var E=this.domObj.getPaddingSize().left;var I,O,K;var N=F.retrieve("size");if(!N){N=F.getBorderBoxSize();F.store("size",N)}I=A+N.width-E;var B=this.domObj.getContentBoxSize();if(G.options.width!=null){O=G.options.width+G.options.left-I;K=B.width-I-O}else{O=B.width-G.options.right-I;K=G.options.right}if(O<0){O=0}if(O<G.options.minWidth){O=G.options.minWidth}if(G.options.maxWidth>=0&&O>G.options.maxWidth){O=G.options.maxWidth}I=B.width-K-O;A=I-N.width;var J,M;J=D.options.left;M=A-J;if(M<0){M=0}if(M<D.options.minWidth){M=D.options.minWidth}if(D.options.maxWidth>=0&&M>D.options.maxWidth){M=D.options.maxWidth}if(J+M!=A){A=J+M;var L=A+N.width-I;I+=L;O-=L}F.style.left=E+A+"px";if(D.options.width==null){var B=this.domObj.getContentBoxSize();H.resize({right:B.width-J-M})}else{H.resize({width:M})}if(G.options.width==null){C.resize({left:I})}else{C.resize({left:I,width:O})}},dragVertical:function(F){var J=parseInt(F.style.top);var D=F.retrieve("leftSide");var A=F.retrieve("rightSide");var E=D.retrieve("jxLayout");var H=A.retrieve("jxLayout");var N=this.domObj.getPaddingSize().top;var O=F.retrieve("size");if(!O){O=F.getBorderBoxSize();F.store("size",O)}var B=this.domObj.getContentBoxSize();var C,M,K;C=J+O.height-N;if(H.options.height!=null){M=H.options.height+H.options.top-C;K=B.height-C-M}else{M=B.height-H.options.bottom-C;K=H.options.bottom}if(M<0){M=0}if(M<H.options.minHeight){M=H.options.minHeight}if(H.options.maxHeight>=0&&M>H.options.maxHeight){M=H.options.maxHeight}C=B.height-K-M;J=C-O.height;var I,G;I=E.options.top;G=J-I;if(G<0){G=0}if(G<E.options.minHeight){G=E.options.minHeight}if(E.options.maxHeight>=0&&G>E.options.maxHeight){G=E.options.maxHeight}if(I+G!=J){J=I+G;var L=J+O.height-C;C+=L;M-=L}F.style.top=N+J+"px";if(E.options.height==null){D.resize({bottom:B.height-I-G})}else{D.resize({height:G})}if(H.options.height==null){A.resize({top:C})}else{A.resize({top:C,height:M})}},sizeChanged:function(){if(this.options.layout=="horizontal"){this.horizontalResize()}else{this.verticalResize()}},horizontalResize:function(){var O=this.domObj.getContentBoxSize().width;var D=O;for(var E=0;E<this.bars.length;E++){var L=this.bars[E];var Q=L.retrieve("size");if(!Q||Q.width==0){Q=L.getBorderBoxSize();L.store("size",Q)}O-=Q.width}var I=0;var H;for(var E=0;E<this.elements.length;E++){var K=this.elements[E];H=K.retrieve("jxLayout").options;if(H.width!=null){O-=parseInt(H.width)}else{var N=0;if(H.right!=0||H.left!=0){N=K.getBorderBoxSize().width}O-=N;I++}}if(I==0){O+=H.width;H.width=null;I=1}var G=parseInt(O/I);var P=O%I;var B=this.domObj.getPaddingSize().left;var C=0;for(var E=0;E<this.elements.length;E++){var K=this.elements[E];var J=K.retrieve("jxLayout");var H=J.options;if(H.width!=null){J.resize({left:C});C+=H.width}else{var M=G;if(I==1){M+=P}I--;var N=0;if(H.right!=0||H.left!=0){N=K.getBorderBoxSize().width+M}else{N=M}if(N<0){if(I>0){G=G+N/I}N=0}if(N<H.minWidth){if(I>0){G=G+(N-H.minWidth)/I}N=H.minWidth}if(H.maxWidth>=0&&N>H.maxWidth){if(I>0){G=G+(N-H.maxWidth)/I}N=K.options.maxWidth}var A=D-C-N;J.resize({left:C,right:A});C+=N}var F=K.retrieve("rightBar");if(F){F.setStyle("left",B+C);C+=F.retrieve("size").width}}},verticalResize:function(){var N=this.domObj.getContentBoxSize().height;var B=N;for(var D=0;D<this.bars.length;D++){var L=this.bars[D];var Q=L.retrieve("size");if(!Q||Q.height==0){Q=L.getBorderBoxSize();L.store("size",Q)}N-=Q.height}var I=0;var H;for(var D=0;D<this.elements.length;D++){var K=this.elements[D];H=K.retrieve("jxLayout").options;if(H.height!=null){N-=parseInt(H.height)}else{var G=0;if(H.bottom!=0||H.top!=0){G=K.getBorderBoxSize().height}N-=G;I++}}if(I==0){N+=H.height;H.height=null;I=1}var F=parseInt(N/I);var O=N%I;var P=this.domObj.getPaddingSize().top;var C=0;for(var D=0;D<this.elements.length;D++){var K=this.elements[D];var J=K.retrieve("jxLayout");var H=J.options;if(H.height!=null){J.resize({top:C});C+=H.height}else{var M=F;if(I==1){M+=O}I--;var G=0;if(H.bottom!=0||H.top!=0){G=K.getBorderBoxSize().height+M}else{G=M}if(G<0){if(I>0){F=F+G/I}G=0}if(G<H.minHeight){if(I>0){F=F+(G-H.minHeight)/I}G=H.minHeight}if(H.maxHeight>=0&&G>H.maxHeight){if(I>0){F=F+(G-H.maxHeight)/I}G=H.maxHeight}var A=B-C-G;J.resize({top:C,bottom:A});C+=G}var E=K.retrieve("rightBar");if(E){E.style.top=P+C+"px";C+=E.retrieve("size").height}}}});Jx.Splitter.Snap=new Class({snap:null,element:null,splitter:null,layout:"vertical",initialize:function(A,E,F){this.snap=A;this.element=E;var D=E.retrieve("jxLayout");D.addEvent("sizeChange",this.sizeChange.bind(this));this.splitter=F;this.layout=F.options.layout;var B=D.options;var C=this.element.getContentBoxSize();if(this.layout=="vertical"){this.originalSize=C.height;this.minimumSize=B.minHeight?B.minHeight:0}else{this.originalSize=C.width;this.minimumSize=B.minWidth?B.minWidth:0}A.addEvent("click",this.toggleElement.bind(this))},toggleElement:function(){var B=this.element.getContentBoxSize();var A={};if(this.layout=="vertical"){if(B.height==this.minimumSize){A.height=this.originalSize}else{this.originalSize=B.height;A.height=this.minimumSize}}else{if(B.width==this.minimumSize){A.width=this.originalSize}else{this.originalSize=B.width;A.width=this.minimumSize}}this.element.resize(A);this.splitter.sizeChanged()},sizeChange:function(){var A=this.element.getBorderBoxSize();if(this.layout=="vertical"){if(A.height==this.minimumSize){this.snap.addClass("jxSnapClosed");this.snap.removeClass("jxSnapOpened")}else{this.snap.addClass("jxSnapOpened");this.snap.removeClass("jxSnapClosed")}}else{if(A.width==this.minimumSize){this.snap.addClass("jxSnapClosed");this.snap.removeClass("jxSnapOpened")}else{this.snap.addClass("jxSnapOpened");this.snap.removeClass("jxSnapClosed")}}}});Jx.TabSet=new Class({Implements:[Options,Events],tabs:null,domObj:null,initialize:function(B,A){this.setOptions(A);this.tabs=[];this.domObj=$(B);if(!this.domObj.hasClass("jxTabSetContainer")){this.domObj.addClass("jxTabSetContainer")}this.selectionChangedFn=this.selectionChanged.bind(this)},resizeTabBox:function(){var B=Element.getContentBoxSize(this.domObj.parentNode);Element.setBorderBoxSize(this.domObj,{width:B.width,height:B.height});for(var A=0;A<this.domObj.childNodes.length;A++){if(this.domObj.childNodes[A].nodeType==3){continue}Element.setBorderBoxSize(this.domObj.childNodes[A],{height:B.height});if(this.domObj.childNodes[A].resize){this.domObj.childNodes[A].resize()}}},add:function(){$A(arguments).each(function(A){if(A instanceof Jx.Button.Tab){A.addEvent("down",this.selectionChangedFn);this.domObj.appendChild(A.content);if(!this.activeTab){A.setActive(true)}this.tabs.push(A)}},this)},remove:function(A){if(A instanceof Jx.Button.Tab&&this.tabs.indexOf(A)!=-1){this.tabs.erase(A);if(this.activeTab==A){if(this.tabs.length){this.tabs[0].setActive(true)}}A.removeEvent("down",this.selectionChangedFn);A.content.dispose()}},setActiveTab:function(A){if(this.activeTab&&this.activeTab!=A){this.activeTab.setActive(false)}this.activeTab=A;if(this.activeTab.content.resize){this.activeTab.content.resize()}},selectionChanged:function(A){this.setActiveTab(A);this.fireEvent("tabChange",this,A)}});Jx.TabSet=new Class({Implements:[Options,Events],tabs:null,domObj:null,initialize:function(B,A){this.setOptions(A);this.tabs=[];this.domObj=$(B);if(!this.domObj.hasClass("jxTabSetContainer")){this.domObj.addClass("jxTabSetContainer")}this.selectionChangedFn=this.selectionChanged.bind(this)},resizeTabBox:function(){var B=Element.getContentBoxSize(this.domObj.parentNode);Element.setBorderBoxSize(this.domObj,{width:B.width,height:B.height});for(var A=0;A<this.domObj.childNodes.length;A++){if(this.domObj.childNodes[A].nodeType==3){continue}Element.setBorderBoxSize(this.domObj.childNodes[A],{height:B.height});if(this.domObj.childNodes[A].resize){this.domObj.childNodes[A].resize()}}},add:function(){$A(arguments).each(function(A){if(A instanceof Jx.Button.Tab){A.addEvent("down",this.selectionChangedFn);this.domObj.appendChild(A.content);if(!this.activeTab){A.setActive(true)}this.tabs.push(A)}},this)},remove:function(A){if(A instanceof Jx.Button.Tab&&this.tabs.indexOf(A)!=-1){this.tabs.erase(A);if(this.activeTab==A){if(this.tabs.length){this.tabs[0].setActive(true)}}A.removeEvent("down",this.selectionChangedFn);A.content.dispose()}},setActiveTab:function(A){if(this.activeTab&&this.activeTab!=A){this.activeTab.setActive(false)}this.activeTab=A;if(this.activeTab.content.resize){this.activeTab.content.resize()}},selectionChanged:function(A){this.setActiveTab(A);this.fireEvent("tabChange",this,A)}});Jx.Button.Tab=new Class({Extends:Jx.Button,Implements:[Options,Events,Jx.ContentLoader],content:null,initialize:function(A){A=$merge(A,{type:"Tab",toggle:true});this.parent(A);this.content=new Element("div",{"class":"tabContent"});this.loadContent(this.content);new Jx.Layout(this.content,A);var B=this;this.addEvent("down",function(){B.content.addClass("tabContentActive")});this.addEvent("up",function(){B.content.removeClass("tabContentActive")})},clicked:function(A){this.setActive(true)}});Jx.Toolbar=new Class({Implements:[Options,Events],items:null,domObj:null,isActive:false,options:{position:"top",parent:null},initialize:function(B){this.setOptions(B);this.domObj=new Element("ul",{"class":"jxToolbar"});if(this.options.parent){var A=$(this.options.parent);if(!A.hasClass("jxToolbarContainer")){A.addClass("jxToolbarContainer");A.appendChild(this.domObj);var C=new Element("div",{"class":"jxClearer"});A.appendChild(C)}else{A.insertBefore(this.domObj,A.lastChild)}if(["top","right","bottom","left"].contains(this.options.position)){A.addClass("jxBar"+this.options.position.capitalize())}else{A.addClass("jxBarTop")}}this.deactivateWatcher=this.deactivate.bindWithEvent(this)},add:function(){for(var B=0;B<arguments.length;B++){var A=arguments[B];A.toolbar=this;if(A.domObj){A=A.domObj}if(A.tagName=="LI"){if(!A.hasClass("jxToolItem")){A.addClass("jxToolItem")}this.domObj.appendChild(A)}else{var C=new Jx.Toolbar.Item(A);this.domObj.appendChild(C.domObj)}}if(arguments.length>0){this.fireEvent("add",this)}},remove:function(B){if(B.domObj){B=B.domObj}var A=B.findElement("LI");if(A&&A.parentNode==this.domObj){B.dispose();this.fireEvent("remove",this)}else{return null}},deactivate:function(){this.items.each(function(A){A.hide()});this.setActive(false)},isActive:function(){return this.isActive},setActive:function(A){this.isActive=A;if(this.isActive){document.addEvent("click",this.deactivateWatcher);Event.observe(document,"click",this.deactivateWatcher)}else{document.removeEvent("click",this.deactivateWatcher)}},setVisibleItem:function(A){if(this.visibleItem&&this.visibleItem.hide&&this.visibleItem!=A){this.visibleItem.hide()}this.visibleItem=A;if(this.isActive()){this.visibleItem.show()}}});Jx.Toolbar.Item=new Class({domObj:null,initialize:function(A){this.al=[];this.domObj=new Element("li",{"class":"jxToolItem"});if(A){if(A.domObj){this.domObj.appendChild(A.domObj);if(A instanceof Jx.Tab){this.domObj.addClass("jxTabItem")}}else{this.domObj.appendChild(A);if(A.hasClass("jxTab")){this.domObj.addClass("jxTabItem")}}}}});Jx.Toolbar.Separator=new Class({domObj:null,initialize:function(){this.domObj=new Element("li",{"class":"jxToolItem"});this.domSpan=new Element("span",{"class":"separator"});this.domObj.appendChild(this.domSpan)}});Jx.TreeItem=new Class({Implements:[Options,Events],domObj:null,owner:null,options:{label:"",data:null,contextMenu:null,image:null,enabled:true,type:"Item",imageClass:""},initialize:function(A){this.setOptions(A);this.domObj=new Element("li",{"class":"jxTree"+this.options.type});if(this.options.id){this.domObj.id=this.options.id}this.domNode=new Element("img",{"class":"jxTreeImage",src:Jx.aPixel.src});this.domObj.appendChild(this.domNode);this.domImg=new Element("img",{"class":"jxTreeIcon",src:Jx.aPixel.src});if(this.options.image){this.domImg.setStyle("backgroundImage","url("+this.options.image+")")}if(this.options.imageClass){this.domImg.addClass(this.options.imageClass)}this.domA=new Element("a",{href:"javascript:void(0)",html:this.options.label,events:{click:this.selected.bindWithEvent(this),dblclick:this.selected.bindWithEvent(this),contextmenu:this.showMenu.bindWithEvent(this)}});this.domA.store("jxTreeItem",this);this.domA.appendChild(this.domImg);this.domObj.appendChild(this.domA);this.domObj.store("jxTreeItem",this);if(!this.options.enabled){this.domObj.addClass("jxDisabled")}},finalize:function(){this.finalizeItem()},finalizeItem:function(){if(!this.domObj){return }this.domA.removeEvents();this.options=null;this.domObj=null;this.owner=null},clone:function(){return new Jx.TreeItem(this.options)},update:function(B){var A=(arguments.length>1)?arguments[1]:(this.owner&&this.owner.isLastNode(this));if(A){this.domObj.removeClass("jxTree"+this.options.type);this.domObj.addClass("jxTree"+this.options.type+"Last")}else{this.domObj.removeClass("jxTree"+this.options.type+"Last");this.domObj.addClass("jxTree"+this.options.type)}},selected:function(A){this.lastEvent=A;this.fireEvent("click",this)},showMenu:function(A){this.lastEvent=A;this.fireEvent("click",this);if(this.contextMenu){this.contextMenu.show(this.lastEvent)}A.stop()},getName:function(){return this.options.label},setName:function(A){this.domA.set("html",A);this.options.label=A},propertyChanged:function(A){this.options.enabled=A.isEnabled();if(this.options.enabled){this.domObj.removeClass("jxDisabled")}else{this.domObj.addClass("jxDisabled")}}});Jx.TreeFolder=new Class({Extends:Jx.TreeItem,subDomObj:null,nodes:null,isOpen:false,options:{folderCloseImage:Jx.baseURL+"images/tree_folder.png",folderOpenImage:Jx.baseURL+"images/tree_folder_open.png"},initialize:function(A){this.parent($merge(A,{type:"Branch"}));this.domObj.childNodes[0].addEvent("click",this.clicked.bindWithEvent(this));this.nodes=[];this.subDomObj=new Element("ul",{"class":"jxTree"});this.domObj.appendChild(this.subDomObj);this.subDomObj.className="jxTree";if(this.options.isOpen){this.expand()}else{this.collapse()}},finalize:function(){this.finalizeFolder();this.finalizeItem();this.subDomObj=null},finalizeFolder:function(){this.domObj.childNodes[0].removeEvents();for(var A=this.nodes.length-1;A>=0;A--){this.nodes[A].finalize();if(this.nodes[A].domObj){this.subDomObj.removeChild(this.nodes[A].domObj)}this.nodes.pop()}},clone:function(){var A=new Jx.TreeFolder(this.options);this.nodes.each(function(B){A.append(B.clone())});return A},isLastNode:function(A){if(this.nodes.length==0){return false}else{return this.nodes[this.nodes.length-1]==A}},update:function(C){if(!this.parent){return }var B=false;if(arguments.length>1){B=arguments[1]}else{B=(this.owner&&this.owner.isLastNode(this))}var D="jxTree"+this.options.type;D+=B?"Last":"";D+=this.options.isOpen?"Open":"Closed";this.domObj.className=D;if(B){this.subDomObj.className="jxTree"}else{this.subDomObj.className="jxTree jxTreeNest"}if(this.nodes&&C){var A=this;this.nodes.each(function(F,E){F.update(false,E==A.nodes.length-1)})}},append:function(A){A.owner=this;this.nodes.push(A);this.subDomObj.appendChild(A.domObj);this.update(true)},insert:function(D,B){D.owner=this;if(!B){this.nodes.unshift(D);if(this.subDomObj.childNodes.length==0){this.subDomObj.appendChild(D.domObj)}else{this.subDomObj.insertBefore(D.domObj,this.subDomObj.childNodes[0])}}else{var A=false;for(var C=0;C<this.nodes.length;C++){if(this.nodes[C]==B){C=C+1;if(C<this.nodes.length){this.nodes.splice(C,0,D);this.subDomObj.insertBefore(D.domObj,this.subDomObj.childNodes[C]);A=true;break}}}if(!A){this.nodes.push(D);this.subDomObj.appendChild(D.domObj)}}this.update(true)},remove:function(B){B.owner=null;for(var A=0;A<this.nodes.length;A++){if(this.nodes[A]==B){this.nodes.splice(A,1);this.subDomObj.removeChild(this.subDomObj.childNodes[A]);break}}this.update(true)},replace:function(D,B){var A=false;for(var C=0;C<this.nodes.length;C++){if(this.nodes[C]==B){if(C<this.nodes.length){D.owner=this;this.nodes.splice(C,1,D);this.subDomObj.replaceChild(D.domObj,B.domObj);return true}}}return false},clicked:function(A){if(this.options.isOpen){this.collapse()}else{this.expand()}},expand:function(){this.options.isOpen=true;this.subDomObj.setStyle("display","block");this.update(true);this.fireEvent("disclosed",this)},collapse:function(){this.options.isOpen=false;this.subDomObj.setStyle("display","none");this.update(true);this.fireEvent("disclosed",this)},findChild:function(C){if(C.length==0){return this}if(C.length==1){for(var B=0;B<this.nodes.length;B++){if(this.nodes[B].getName()==C[0]){return this.nodes[B]}}return null}var A=C.shift();for(var B=0;B<this.nodes.length;B++){if(this.nodes[B].getName()==A&&this.nodes[B].findChild){return this.nodes[B].findChild(C)}}return null}});Jx.Tree=new Class({Extends:Jx.TreeFolder,initialize:function(A){this.parent();this.subDomObj=new Element("ul",{"class":"jxTreeRoot"});$(A).appendChild(this.subDomObj);this.nodes=[];this.isOpen=true},finalize:function(){this.clear();this.subDomObj.parentNode.removeChild(this.subDomObj)},clear:function(){for(var A=this.nodes.length-1;A>=0;A--){this.subDomObj.removeChild(this.nodes[A].domObj);this.nodes[A].finalize();this.nodes.pop()}},update:function(A){var B=true;if(this.subDomObj){if(B){this.subDomObj.removeClass("jxTreeNest")}else{this.subDomObj.addClass("jxTreeNest")}}if(this.nodes&&A){this.nodes.each(function(C){C.update(false)})}},append:function(A){A.owner=this;this.nodes.push(A);this.subDomObj.appendChild(A.domObj);this.update(true)}});
\ No newline at end of file

Added: sandbox/jx2/jx/lib/jxlib.uncompressed.js
===================================================================
--- sandbox/jx2/jx/lib/jxlib.uncompressed.js	                        (rev 0)
+++ sandbox/jx2/jx/lib/jxlib.uncompressed.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -0,0 +1,13148 @@
+/*
+Script: Core.js
+	MooTools - My Object Oriented JavaScript Tools.
+
+License:
+	MIT-style license.
+
+Copyright:
+	Copyright (c) 2006-2007 [Valerio Proietti](http://mad4milk.net/).
+
+Code & Documentation:
+	[The MooTools production team](http://mootools.net/developers/).
+
+Inspiration:
+	- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
+	- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
+*/
+
+var MooTools = {
+	'version': '1.2dev',
+	'build': ''
+};
+      
+var Native = function(options){
+	options = options || {};
+
+	var afterImplement = options.afterImplement || function(){};
+	var generics = options.generics;
+	generics = (generics !== false);
+	var legacy = options.legacy;
+	var initialize = options.initialize;
+	var protect = options.protect;
+	var name = options.name;
+
+	var object = initialize || legacy;
+
+	object.constructor = Native;
+	object.$family = {name: 'native'};
+	if (legacy && initialize) object.prototype = legacy.prototype;
+	object.prototype.constructor = object;
+
+	if (name){
+		var family = name.toLowerCase();
+		object.prototype.$family = {name: family};
+		Native.typize(object, family);
+	}
+
+	var add = function(obj, name, method, force){
+		if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
+		if (generics) Native.genericize(obj, name, protect);
+		afterImplement.call(obj, name, method);
+		return obj;
+	};
+	
+	object.implement = function(a1, a2, a3){
+		if (typeof a1 == 'string') return add(this, a1, a2, a3);
+		for (var p in a1) add(this, p, a1[p], a2);
+		return this;
+	};
+	
+	object.alias = function(a1, a2, a3){
+		if (typeof a1 == 'string'){
+			a1 = this.prototype[a1];
+			if (a1) add(this, a2, a1, a3);
+		} else {
+			for (var a in a1) this.alias(a, a1[a], a2);
+		}
+		return this;
+	};
+
+	return object;
+};
+
+Native.implement = function(objects, properties){
+	for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
+};
+
+Native.genericize = function(object, property, check){
+	if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
+		var args = Array.prototype.slice.call(arguments);
+		return object.prototype[property].apply(args.shift(), args);
+	};
+};
+
+Native.typize = function(object, family){
+	if (!object.type) object.type = function(item){
+		return ($type(item) === family);
+	};
+};
+
+Native.alias = function(objects, a1, a2, a3){
+	for (var i = 0, j = objects.length; i < j; i++) objects[i].alias(a1, a2, a3);
+};
+
+(function(objects){
+	for (var name in objects) Native.typize(objects[name], name);
+})({'boolean': Boolean, 'native': Native, 'object': Object});
+
+(function(objects){
+	for (var name in objects) new Native({name: name, initialize: objects[name], protect: true});
+})({'String': String, 'Function': Function, 'Number': Number, 'Array': Array, 'RegExp': RegExp, 'Date': Date});
+
+(function(object, methods){
+	for (var i = methods.length; i--; i) Native.genericize(object, methods[i], true);
+	return arguments.callee;
+})
+(Array, ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'toString', 'valueOf', 'indexOf', 'lastIndexOf'])
+(String, ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase', 'valueOf']);
+
+function $chk(obj){
+	return !!(obj || obj === 0);
+};
+
+function $clear(timer){
+	clearTimeout(timer);
+	clearInterval(timer);
+	return null;
+};
+
+function $defined(obj){
+	return (obj != undefined);
+};
+
+function $empty(){};
+
+function $arguments(i){
+	return function(){
+		return arguments[i];
+	};
+};
+
+function $lambda(value){
+	return (typeof value == 'function') ? value : function(){
+		return value;
+	};
+};
+
+function $extend(original, extended){
+	for (var key in (extended || {})) original[key] = extended[key];
+	return original;
+};
+
+function $unlink(object){
+	var unlinked;
+	
+	switch ($type(object)){
+		case 'object':
+			unlinked = {};
+			for (var p in object) unlinked[p] = $unlink(object[p]);
+		break;
+		case 'hash':
+			unlinked = $unlink(object.getClean());
+		break;
+		case 'array':
+			unlinked = [];
+			for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
+		break;
+		default: return object;
+	}
+	
+	return unlinked;
+};
+
+function $merge(){
+	var mix = {};
+	for (var i = 0, l = arguments.length; i < l; i++){
+		var object = arguments[i];
+		if ($type(object) != 'object') continue;
+		for (var key in object){
+			var op = object[key], mp = mix[key];
+			mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
+		}
+	}
+	return mix;
+};
+
+function $pick(){
+	for (var i = 0, l = arguments.length; i < l; i++){
+		if (arguments[i] != undefined) return arguments[i];
+	}
+	return null;
+};
+
+function $random(min, max){
+	return Math.floor(Math.random() * (max - min + 1) + min);
+};
+
+function $splat(obj){
+	var type = $type(obj);
+	return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
+};
+
+var $time = Date.now || function(){
+	return new Date().getTime();
+};
+
+function $try(){
+	for (var i = 0, l = arguments.length; i < l; i++){
+		try {
+			return arguments[i]();
+		} catch(e){}
+	}
+	return null;
+};
+
+function $type(obj){
+	if (obj == undefined) return false;
+	if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
+	if (obj.nodeName){
+		switch (obj.nodeType){
+			case 1: return 'element';
+			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
+		}
+	} else if (typeof obj.length == 'number'){
+		if (obj.callee) return 'arguments';
+		else if (obj.item) return 'collection';
+	}
+	return typeof obj;
+};
+
+var Hash = new Native({
+
+	name: 'Hash',
+
+	initialize: function(object){
+		if ($type(object) == 'hash') object = $unlink(object.getClean());
+		for (var key in object) this[key] = object[key];
+		return this;
+	}
+
+});
+
+Hash.implement({
+	
+	getLength: function(){
+		var length = 0;
+		for (var key in this){
+			if (this.hasOwnProperty(key)) length++;
+		}
+		return length;
+	},
+
+	forEach: function(fn, bind){
+		for (var key in this){
+			if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
+		}
+	},
+	
+	getClean: function(){
+		var clean = {};
+		for (var key in this){
+			if (this.hasOwnProperty(key)) clean[key] = this[key];
+		}
+		return clean;
+	}
+
+});
+
+Hash.alias('forEach', 'each');
+
+function $H(object){
+	return new Hash(object);
+};
+
+Array.implement({
+
+	forEach: function(fn, bind){
+		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
+	}
+
+});
+
+Array.alias('forEach', 'each');
+
+function $A(iterable){
+	if (iterable.item){
+		var array = [];
+		for (var i = 0, l = iterable.length; i < l; i++) array[i] = iterable[i];
+		return array;
+	}
+	return Array.prototype.slice.call(iterable);
+};
+
+function $each(iterable, fn, bind){
+	var type = $type(iterable);
+	((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
+};
+
+
+/*
+Script: Browser.js
+	The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
+
+License:
+	MIT-style license.
+*/
+
+var Browser = new Hash({
+	Engine: {name: 'unknown', version: ''},
+	Platform: {name: (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
+	Features: {xpath: !!(document.evaluate), air: !!(window.runtime)},
+	Plugins: {}
+});
+
+if (window.opera) Browser.Engine = {name: 'presto', version: (document.getElementsByClassName) ? 950 : 925};
+else if (window.ActiveXObject) Browser.Engine = {name: 'trident', version: (window.XMLHttpRequest) ? 5 : 4};
+else if (!navigator.taintEnabled) Browser.Engine = {name: 'webkit', version: (Browser.Features.xpath) ? 420 : 419};
+else if (document.getBoxObjectFor != null) Browser.Engine = {name: 'gecko', version: (document.getElementsByClassName) ? 19 : 18};
+Browser.Engine[Browser.Engine.name] = Browser.Engine[Browser.Engine.name + Browser.Engine.version] = true;
+
+if (window.orientation != undefined) Browser.Platform.name = 'ipod';
+
+Browser.Platform[Browser.Platform.name] = true;
+
+Browser.Request = function(){
+	return $try(function(){
+		return new XMLHttpRequest();
+	}, function(){
+		return new ActiveXObject('MSXML2.XMLHTTP');
+	});
+};
+
+Browser.Features.xhr = !!(Browser.Request());
+
+Browser.Plugins.Flash = (function(){
+	var version = ($try(function(){
+		return navigator.plugins['Shockwave Flash'].description;
+	}, function(){
+		return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+	}) || '0 r0').match(/\d+/g);
+	return {version: parseInt(version[0] || 0 + '.' + version[1] || 0), build: parseInt(version[2] || 0)};
+})();
+
+function $exec(text){
+	if (!text) return text;
+	if (window.execScript){
+		window.execScript(text);
+	} else {
+		var script = document.createElement('script');
+		script.setAttribute('type', 'text/javascript');
+		script.text = text;
+		document.head.appendChild(script);
+		document.head.removeChild(script);
+	}
+	return text;
+};
+
+Native.UID = 1;
+
+var $uid = (Browser.Engine.trident) ? function(item){
+	return (item.uid || (item.uid = [Native.UID++]))[0];
+} : function(item){
+	return item.uid || (item.uid = Native.UID++);
+};
+
+var Window = new Native({
+
+	name: 'Window',
+
+	legacy: (Browser.Engine.trident) ? null: window.Window,
+
+	initialize: function(win){
+		$uid(win);
+		if (!win.Element){
+			win.Element = $empty;
+			if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
+			win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
+		}
+		return $extend(win, Window.Prototype);
+	},
+
+	afterImplement: function(property, value){
+		window[property] = Window.Prototype[property] = value;
+	}
+
+});
+
+Window.Prototype = {$family: {name: 'window'}};
+
+new Window(window);
+
+var Document = new Native({
+
+	name: 'Document',
+
+	legacy: (Browser.Engine.trident) ? null: window.Document,
+
+	initialize: function(doc){
+		$uid(doc);
+		doc.head = doc.getElementsByTagName('head')[0];
+		doc.html = doc.getElementsByTagName('html')[0];
+		doc.window = doc.defaultView || doc.parentWindow;
+		if (Browser.Engine.trident4) $try(function(){
+			doc.execCommand("BackgroundImageCache", false, true);
+		});
+		return $extend(doc, Document.Prototype);
+	},
+
+	afterImplement: function(property, value){
+		document[property] = Document.Prototype[property] = value;
+	}
+
+});
+
+Document.Prototype = {$family: {name: 'document'}};
+
+new Document(document);
+
+/*
+Script: Array.js
+	Contains Array Prototypes like copy, each, contains, and remove.
+
+License:
+	MIT-style license.
+*/
+
+Array.implement({
+
+	every: function(fn, bind){
+		for (var i = 0, l = this.length; i < l; i++){
+			if (!fn.call(bind, this[i], i, this)) return false;
+		}
+		return true;
+	},
+
+	filter: function(fn, bind){
+		var results = [];
+		for (var i = 0, l = this.length; i < l; i++){
+			if (fn.call(bind, this[i], i, this)) results.push(this[i]);
+		}
+		return results;
+	},
+	
+	clean: function() {
+		return this.filter($defined);
+	},
+
+	indexOf: function(item, from){
+		var len = this.length;
+		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
+			if (this[i] === item) return i;
+		}
+		return -1;
+	},
+
+	map: function(fn, bind){
+		var results = [];
+		for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
+		return results;
+	},
+
+	some: function(fn, bind){
+		for (var i = 0, l = this.length; i < l; i++){
+			if (fn.call(bind, this[i], i, this)) return true;
+		}
+		return false;
+	},
+
+	associate: function(keys){
+		var obj = {}, length = Math.min(this.length, keys.length);
+		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
+		return obj;
+	},
+
+	link: function(object){
+		var result = {};
+		for (var i = 0, l = this.length; i < l; i++){
+			for (var key in object){
+				if (object[key](this[i])){
+					result[key] = this[i];
+					delete object[key];
+					break;
+				}
+			}
+		}
+		return result;
+	},
+
+	contains: function(item, from){
+		return this.indexOf(item, from) != -1;
+	},
+
+	extend: function(array){
+		for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
+		return this;
+	},
+
+	getLast: function(){
+		return (this.length) ? this[this.length - 1] : null;
+	},
+
+	getRandom: function(){
+		return (this.length) ? this[$random(0, this.length - 1)] : null;
+	},
+
+	include: function(item){
+		if (!this.contains(item)) this.push(item);
+		return this;
+	},
+
+	combine: function(array){
+		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
+		return this;
+	},
+
+	erase: function(item){
+		for (var i = this.length; i--; i){
+			if (this[i] === item) this.splice(i, 1);
+		}
+		return this;
+	},
+
+	empty: function(){
+		this.length = 0;
+		return this;
+	},
+
+	flatten: function(){
+		var array = [];
+		for (var i = 0, l = this.length; i < l; i++){
+			var type = $type(this[i]);
+			if (!type) continue;
+			array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
+		}
+		return array;
+	},
+
+	hexToRgb: function(array){
+		if (this.length != 3) return null;
+		var rgb = this.map(function(value){
+			if (value.length == 1) value += value;
+			return value.toInt(16);
+		});
+		return (array) ? rgb : 'rgb(' + rgb + ')';
+	},
+
+	rgbToHex: function(array){
+		if (this.length < 3) return null;
+		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
+		var hex = [];
+		for (var i = 0; i < 3; i++){
+			var bit = (this[i] - 0).toString(16);
+			hex.push((bit.length == 1) ? '0' + bit : bit);
+		}
+		return (array) ? hex : '#' + hex.join('');
+	}
+
+});
+
+/*
+Script: Function.js
+	Contains Function Prototypes like create, bind, pass, and delay.
+
+License:
+	MIT-style license.
+*/
+
+Function.implement({
+
+	extend: function(properties){
+		for (var property in properties) this[property] = properties[property];
+		return this;
+	},
+
+	create: function(options){
+		var self = this;
+		options = options || {};
+		return function(event){
+			var args = options.arguments;
+			args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
+			if (options.event) args = [event || window.event].extend(args);
+			var returns = function(){
+				return self.apply(options.bind || null, args);
+			};
+			if (options.delay) return setTimeout(returns, options.delay);
+			if (options.periodical) return setInterval(returns, options.periodical);
+			if (options.attempt) return $try(returns);
+			return returns();
+		};
+	},
+
+	pass: function(args, bind){
+		return this.create({arguments: args, bind: bind});
+	},
+
+	attempt: function(args, bind){
+		return this.create({arguments: args, bind: bind, attempt: true})();
+	},
+
+	bind: function(bind, args){
+		return this.create({bind: bind, arguments: args});
+	},
+
+	bindWithEvent: function(bind, args){
+		return this.create({bind: bind, event: true, arguments: args});
+	},
+
+	delay: function(delay, bind, args){
+		return this.create({delay: delay, bind: bind, arguments: args})();
+	},
+
+	periodical: function(interval, bind, args){
+		return this.create({periodical: interval, bind: bind, arguments: args})();
+	},
+
+	run: function(args, bind){
+		return this.apply(bind, $splat(args));
+	}
+
+});
+
+/*
+Script: Number.js
+	Contains Number Prototypes like limit, round, times, and ceil.
+
+License:
+	MIT-style license.
+*/
+
+Number.implement({
+
+	limit: function(min, max){
+		return Math.min(max, Math.max(min, this));
+	},
+
+	round: function(precision){
+		precision = Math.pow(10, precision || 0);
+		return Math.round(this * precision) / precision;
+	},
+
+	times: function(fn, bind){
+		for (var i = 0; i < this; i++) fn.call(bind, i, this);
+	},
+
+	toFloat: function(){
+		return parseFloat(this);
+	},
+
+	toInt: function(base){
+		return parseInt(this, base || 10);
+	}
+
+});
+
+Number.alias('times', 'each');
+
+(function(math){
+	var methods = {};
+	math.each(function(name){
+		if (!Number[name]) methods[name] = function(){
+			return Math[name].apply(null, [this].concat($A(arguments)));
+		};
+	});
+	Number.implement(methods);
+})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
+
+/*
+Script: String.js
+	Contains String Prototypes like camelCase, capitalize, test, and toInt.
+
+License:
+	MIT-style license.
+*/
+
+String.implement({
+
+	test: function(regex, params){
+		return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
+	},
+
+	contains: function(string, separator){
+		return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
+	},
+
+	trim: function(){
+		return this.replace(/^\s+|\s+$/g, '');
+	},
+
+	clean: function(){
+		return this.replace(/\s+/g, ' ').trim();
+	},
+
+	camelCase: function(){
+		return this.replace(/-\D/g, function(match){
+			return match.charAt(1).toUpperCase();
+		});
+	},
+
+	hyphenate: function(){
+		return this.replace(/[A-Z]/g, function(match){
+			return ('-' + match.charAt(0).toLowerCase());
+		});
+	},
+
+	capitalize: function(){
+		return this.replace(/\b[a-z]/g, function(match){
+			return match.toUpperCase();
+		});
+	},
+
+	escapeRegExp: function(){
+		return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
+	},
+
+	toInt: function(base){
+		return parseInt(this, base || 10);
+	},
+
+	toFloat: function(){
+		return parseFloat(this);
+	},
+
+	hexToRgb: function(array){
+		var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
+		return (hex) ? hex.slice(1).hexToRgb(array) : null;
+	},
+
+	rgbToHex: function(array){
+		var rgb = this.match(/\d{1,3}/g);
+		return (rgb) ? rgb.rgbToHex(array) : null;
+	},
+
+	stripScripts: function(option){
+		var scripts = '';
+		var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
+			scripts += arguments[1] + '\n';
+			return '';
+		});
+		if (option === true) $exec(scripts);
+		else if ($type(option) == 'function') option(scripts, text);
+		return text;
+	},
+
+	substitute: function(object, regexp){
+		return this.replace(regexp || (/\\?\{([^}]+)\}/g), function(match, name){
+			if (match.charAt(0) == '\\') return match.slice(1);
+			return (object[name] != undefined) ? object[name] : '';
+		});
+	}
+
+});
+
+/*
+Script: Hash.js
+	Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
+
+License:
+	MIT-style license.
+*/
+
+Hash.implement({
+
+	has: Object.prototype.hasOwnProperty,
+
+	keyOf: function(value){
+		for (var key in this){
+			if (this.hasOwnProperty(key) && this[key] === value) return key;
+		}
+		return null;
+	},
+
+	hasValue: function(value){
+		return (Hash.keyOf(this, value) !== null);
+	},
+
+	extend: function(properties){
+		Hash.each(properties, function(value, key){
+			Hash.set(this, key, value);
+		}, this);
+		return this;
+	},
+
+	combine: function(properties){
+		Hash.each(properties, function(value, key){
+			Hash.include(this, key, value);
+		}, this);
+		return this;
+	},
+
+	erase: function(key){
+		if (this.hasOwnProperty(key)) delete this[key];
+		return this;
+	},
+
+	get: function(key){
+		return (this.hasOwnProperty(key)) ? this[key] : null;
+	},
+
+	set: function(key, value){
+		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
+		return this;
+	},
+
+	empty: function(){
+		Hash.each(this, function(value, key){
+			delete this[key];
+		}, this);
+		return this;
+	},
+
+	include: function(key, value){
+		var k = this[key];
+		if (k == undefined) this[key] = value;
+		return this;
+	},
+
+	map: function(fn, bind){
+		var results = new Hash;
+		Hash.each(this, function(value, key){
+			results.set(key, fn.call(bind, value, key, this));
+		}, this);
+		return results;
+	},
+
+	filter: function(fn, bind){
+		var results = new Hash;
+		Hash.each(this, function(value, key){
+			if (fn.call(bind, value, key, this)) results.set(key, value);
+		}, this);
+		return results;
+	},
+
+	every: function(fn, bind){
+		for (var key in this){
+			if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
+		}
+		return true;
+	},
+
+	some: function(fn, bind){
+		for (var key in this){
+			if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
+		}
+		return false;
+	},
+
+	getKeys: function(){
+		var keys = [];
+		Hash.each(this, function(value, key){
+			keys.push(key);
+		});
+		return keys;
+	},
+
+	getValues: function(){
+		var values = [];
+		Hash.each(this, function(value){
+			values.push(value);
+		});
+		return values;
+	},
+	
+	toQueryString: function(base){
+		var queryString = [];
+		Hash.each(this, function(value, key){
+			if (base) key = base + '[' + key + ']';
+			var result;
+			switch ($type(value)){
+				case 'object': result = Hash.toQueryString(value, key); break;
+				case 'array':
+					var qs = {};
+					value.each(function(val, i){
+						qs[i] = val;
+					});
+					result = Hash.toQueryString(qs, key);
+				break;
+				default: result = key + '=' + encodeURIComponent(value);
+			}
+			if (value != undefined) queryString.push(result);
+		});
+		
+		return queryString.join('&');
+	}
+
+});
+
+Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
+
+/*
+Script: Event.js
+	Contains the Event Native, to make the event object completely crossbrowser.
+
+License:
+	MIT-style license.
+*/
+
+var Event = new Native({
+
+	name: 'Event',
+
+	initialize: function(event, win){
+		win = win || window;
+		var doc = win.document;
+		event = event || win.event;
+		if (event.$extended) return event;
+		this.$extended = true;
+		var type = event.type;
+		var target = event.target || event.srcElement;
+		while (target && target.nodeType == 3) target = target.parentNode;
+		
+		if (type.test(/key/)){
+			var code = event.which || event.keyCode;
+			var key = Event.Keys.keyOf(code);
+			if (type == 'keydown'){
+				var fKey = code - 111;
+				if (fKey > 0 && fKey < 13) key = 'f' + fKey;
+			}
+			key = key || String.fromCharCode(code).toLowerCase();
+		} else if (type.match(/(click|mouse|menu)/i)){
+			doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
+			var page = {
+				x: event.pageX || event.clientX + doc.scrollLeft,
+				y: event.pageY || event.clientY + doc.scrollTop
+			};
+			var client = {
+				x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
+				y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
+			};
+			if (type.match(/DOMMouseScroll|mousewheel/)){
+				var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
+			}
+			var rightClick = (event.which == 3) || (event.button == 2);
+			var related = null;
+			if (type.match(/over|out/)){
+				switch (type){
+					case 'mouseover': related = event.relatedTarget || event.fromElement; break;
+					case 'mouseout': related = event.relatedTarget || event.toElement;
+				}
+				if (!(function(){
+					while (related && related.nodeType == 3) related = related.parentNode;
+					return true;
+				}).create({attempt: Browser.Engine.gecko})()) related = false;
+			}
+		}
+
+		return $extend(this, {
+			event: event,
+			type: type,
+			
+			page: page,
+			client: client,
+			rightClick: rightClick,
+			
+			wheel: wheel,
+			
+			relatedTarget: related,
+			target: target,
+			
+			code: code,
+			key: key,
+			
+			shift: event.shiftKey,
+			control: event.ctrlKey,
+			alt: event.altKey,
+			meta: event.metaKey
+		});
+	}
+
+});
+
+Event.Keys = new Hash({
+	'enter': 13,
+	'up': 38,
+	'down': 40,
+	'left': 37,
+	'right': 39,
+	'esc': 27,
+	'space': 32,
+	'backspace': 8,
+	'tab': 9,
+	'delete': 46
+});
+
+Event.implement({
+
+	stop: function(){
+		return this.stopPropagation().preventDefault();
+	},
+
+	stopPropagation: function(){
+		if (this.event.stopPropagation) this.event.stopPropagation();
+		else this.event.cancelBubble = true;
+		return this;
+	},
+
+	preventDefault: function(){
+		if (this.event.preventDefault) this.event.preventDefault();
+		else this.event.returnValue = false;
+		return this;
+	}
+
+});
+
+/*
+Script: Class.js
+	Contains the Class Function for easily creating, extending, and implementing reusable Classes.
+
+License:
+	MIT-style license.
+*/
+
+var Class = new Native({
+
+	name: 'Class',
+
+	initialize: function(properties){
+		properties = properties || {};
+		var klass = function(empty){
+			for (var key in this) this[key] = $unlink(this[key]);
+			for (var mutator in Class.Mutators){
+				if (!this[mutator]) continue;
+				Class.Mutators[mutator](this, this[mutator]);
+				delete this[mutator];
+			}
+
+			this.constructor = klass;
+			if (empty === $empty) return this;
+			
+			var self = (this.initialize) ? this.initialize.apply(this, arguments) : this;
+			if (this.options && this.options.initialize) this.options.initialize.call(this);
+			return self;
+		};
+
+		$extend(klass, this);
+		klass.constructor = Class;
+		klass.prototype = properties;
+		return klass;
+	}
+
+});
+
+Class.implement({
+
+	implement: function(){
+		Class.Mutators.Implements(this.prototype, Array.slice(arguments));
+		return this;
+	}
+
+});
+
+Class.Mutators = {
+  
+  Implements: function(self, klasses){
+  	$splat(klasses).each(function(klass){
+  		$extend(self, ($type(klass) == 'class') ? new klass($empty) : klass);
+  	});
+  },
+  
+  Extends: function(self, klass){
+  	var instance = new klass($empty);
+  	delete instance.parent;
+  	delete instance.parentOf;
+
+  	for (var key in instance){
+  		var current = self[key], previous = instance[key];
+  		if (current == undefined){
+  			self[key] = previous;
+  			continue;
+  		}
+
+  		var ctype = $type(current), ptype = $type(previous);
+  		if (ctype != ptype) continue;
+
+  		switch (ctype){
+  			case 'function': 
+  				// this code will be only executed if the current browser does not support function.caller (currently only opera).
+  				// we replace the function code with brute force. Not pretty, but it will only be executed if function.caller is not supported.
+
+  				if (!arguments.callee.caller) self[key] = eval('(' + String(current).replace(/\bthis\.parent\(\s*(\))?/g, function(full, close){
+  					return 'arguments.callee._parent_.call(this' + (close || ', ');
+  				}) + ')');
+
+  				// end "opera" code
+  				self[key]._parent_ = previous;
+  			  break;
+  			case 'object': self[key] = $merge(previous, current);
+  		}
+
+  	}
+
+  	self.parent = function(){
+  		return arguments.callee.caller._parent_.apply(this, arguments);
+  	};
+
+  	self.parentOf = function(descendant){
+  		return descendant._parent_.apply(this, Array.slice(arguments, 1));
+  	};
+  }
+  
+};
+
+
+/*
+Script: Class.Extras.js
+	Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
+
+License:
+	MIT-style license.
+*/
+
+var Chain = new Class({
+
+	chain: function(){
+		this.$chain = (this.$chain || []).extend(arguments);
+		return this;
+	},
+
+	callChain: function(){
+		return (this.$chain && this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
+	},
+
+	clearChain: function(){
+		if (this.$chain) this.$chain.empty();
+		return this;
+	}
+
+});
+
+var Events = new Class({
+
+	addEvent: function(type, fn, internal){
+		type = Events.removeOn(type);
+		if (fn != $empty){
+			this.$events = this.$events || {};
+			this.$events[type] = this.$events[type] || [];
+			this.$events[type].include(fn);
+			if (internal) fn.internal = true;
+		}
+		return this;
+	},
+
+	addEvents: function(events){
+		for (var type in events) this.addEvent(type, events[type]);
+		return this;
+	},
+
+	fireEvent: function(type, args, delay){
+		type = Events.removeOn(type);
+		if (!this.$events || !this.$events[type]) return this;
+		this.$events[type].each(function(fn){
+			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
+		}, this);
+		return this;
+	},
+
+	removeEvent: function(type, fn){
+		type = Events.removeOn(type);
+		if (!this.$events || !this.$events[type]) return this;
+		if (!fn.internal) this.$events[type].erase(fn);
+		return this;
+	},
+
+	removeEvents: function(type){
+		for (var e in this.$events){
+			if (type && type != e) continue;
+			var fns = this.$events[e];
+			for (var i = fns.length; i--; i) this.removeEvent(e, fns[i]);
+		}
+		return this;
+	}
+
+});
+
+Events.removeOn = function(string){
+	return string.replace(/^on([A-Z])/, function(full, first) {
+		return first.toLowerCase();
+	});
+};
+
+var Options = new Class({
+
+	setOptions: function(){
+		this.options = $merge.run([this.options].extend(arguments));
+		if (!this.addEvent) return this;
+		for (var option in this.options){
+			if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
+			this.addEvent(option, this.options[option]);
+			delete this.options[option];
+		}
+		return this;
+	}
+
+});
+
+/*
+Script: Element.js
+	One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
+	time-saver methods to let you easily work with HTML Elements.
+
+License:
+	MIT-style license.
+*/
+
+Document.implement({
+
+	newElement: function(tag, props){
+		if (Browser.Engine.trident && props){
+			['name', 'type', 'checked'].each(function(attribute){
+				if (!props[attribute]) return;
+				tag += ' ' + attribute + '="' + props[attribute] + '"';
+				if (attribute != 'checked') delete props[attribute];
+			});
+			tag = '<' + tag + '>';
+		}
+		return $.element(this.createElement(tag)).set(props);
+	},
+
+	newTextNode: function(text){
+		return this.createTextNode(text);
+	},
+
+	getDocument: function(){
+		return this;
+	},
+
+	getWindow: function(){
+		return this.defaultView || this.parentWindow;
+	},
+
+	purge: function(){
+		var elements = this.getElementsByTagName('*');
+		for (var i = 0, l = elements.length; i < l; i++) Browser.freeMem(elements[i]);
+	}
+
+});
+
+var Element = new Native({
+
+	name: 'Element',
+
+	legacy: window.Element,
+
+	initialize: function(tag, props){
+		var konstructor = Element.Constructors.get(tag);
+		if (konstructor) return konstructor(props);
+		if (typeof tag == 'string') return document.newElement(tag, props);
+		return $(tag).set(props);
+	},
+
+	afterImplement: function(key, value){
+		if (!Array[key]) Elements.implement(key, Elements.multi(key));
+		Element.Prototype[key] = value;
+	}
+
+});
+
+Element.Prototype = {$family: {name: 'element'}};
+
+Element.Constructors = new Hash;
+
+var IFrame = new Native({
+
+	name: 'IFrame',
+
+	generics: false,
+
+	initialize: function(){
+		var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
+		var props = params.properties || {};
+		var iframe = $(params.iframe) || false;
+		var onload = props.onload || $empty;
+		delete props.onload;
+		props.id = props.name = $pick(props.id, props.name, iframe.id, iframe.name, 'IFrame_' + $time());
+		iframe = new Element(iframe || 'iframe', props);
+		var onFrameLoad = function(){
+			var host = $try(function(){
+				return iframe.contentWindow.location.host;
+			});
+			if (host && host == window.location.host){
+				var win = new Window(iframe.contentWindow);
+				var doc = new Document(iframe.contentWindow.document);
+				$extend(win.Element.prototype, Element.Prototype);
+			}
+			onload.call(iframe.contentWindow, iframe.contentWindow.document);
+		};
+		(!window.frames[props.id]) ? iframe.addListener('load', onFrameLoad) : onFrameLoad();
+		return iframe;
+	}
+
+});
+
+var Elements = new Native({
+
+	initialize: function(elements, options){
+		options = $extend({ddup: true, cash: true}, options);
+		elements = elements || [];
+		if (options.ddup || options.cash){
+			var uniques = {}, returned = [];
+			for (var i = 0, l = elements.length; i < l; i++){
+				var el = $.element(elements[i], !options.cash);
+				if (options.ddup){
+					if (uniques[el.uid]) continue;
+					uniques[el.uid] = true;
+				}
+				returned.push(el);
+			}
+			elements = returned;
+		}
+		return (options.cash) ? $extend(elements, this) : elements;
+	}
+
+});
+
+Elements.implement({
+
+	filter: function(filter, bind){
+		if (!filter) return this;
+		return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
+			return item.match(filter);
+		} : filter, bind));
+	}
+
+});
+
+Elements.multi = function(property){
+	return function(){
+		var items = [];
+		var elements = true;
+		for (var i = 0, j = this.length; i < j; i++){
+			var returns = this[i][property].apply(this[i], arguments);
+			items.push(returns);
+			if (elements) elements = ($type(returns) == 'element');
+		}
+		return (elements) ? new Elements(items) : items;
+	};
+};
+
+Window.implement({
+
+	$: function(el, nocash){
+		if (el && el.$family && el.uid) return el;
+		var type = $type(el);
+		return ($[type]) ? $[type](el, nocash, this.document) : null;
+	},
+
+	$$: function(selector){
+		if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
+		var elements = [];
+		var args = Array.flatten(arguments);
+		for (var i = 0, l = args.length; i < l; i++){
+			var item = args[i];
+			switch ($type(item)){
+				case 'element': item = [item]; break;
+				case 'string': item = this.document.getElements(item, true); break;
+				default: item = false;
+			}
+			if (item) elements.extend(item);
+		}
+		return new Elements(elements);
+	},
+
+	getDocument: function(){
+		return this.document;
+	},
+
+	getWindow: function(){
+		return this;
+	}
+
+});
+
+$.string = function(id, nocash, doc){
+	id = doc.getElementById(id);
+	return (id) ? $.element(id, nocash) : null;
+};
+
+$.element = function(el, nocash){
+	$uid(el);
+	if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
+		var proto = Element.Prototype;
+		for (var p in proto) el[p] = proto[p];
+	};
+	return el;
+};
+
+$.object = function(obj, nocash, doc){
+	if (obj.toElement) return $.element(obj.toElement(doc), nocash);
+	return null;
+};
+
+$.textnode = $.whitespace = $.window = $.document = $arguments(0);
+
+Native.implement([Element, Document], {
+
+	getElement: function(selector, nocash){
+		return $(this.getElements(selector, true)[0] || null, nocash);
+	},
+
+	getElements: function(tags, nocash){
+		tags = tags.split(',');
+		var elements = [];
+		var ddup = (tags.length > 1);
+		tags.each(function(tag){
+			var partial = this.getElementsByTagName(tag.trim());
+			(ddup) ? elements.extend(partial) : elements = partial;
+		}, this);
+		return new Elements(elements, {ddup: ddup, cash: !nocash});
+	}
+
+});
+
+Element.Storage = {
+
+	get: function(uid){
+		return (this[uid] || (this[uid] = {}));
+	}
+
+};
+
+Element.Inserters = new Hash({
+
+	before: function(context, element){
+		if (element.parentNode) element.parentNode.insertBefore(context, element);
+	},
+
+	after: function(context, element){
+		if (!element.parentNode) return;
+		var next = element.nextSibling;
+		(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
+	},
+
+	bottom: function(context, element){
+		element.appendChild(context);
+	},
+
+	top: function(context, element){
+		var first = element.firstChild;
+		(first) ? element.insertBefore(context, first) : element.appendChild(context);
+	}
+
+});
+
+Element.Inserters.inside = Element.Inserters.bottom;
+
+Element.Inserters.each(function(value, key){
+
+	var Key = key.capitalize();
+
+	Element.implement('inject' + Key, function(el){
+		value(this, $(el, true));
+		return this;
+	});
+
+	Element.implement('grab' + Key, function(el){
+		value($(el, true), this);
+		return this;
+	});
+
+});
+
+Element.implement({
+
+	getDocument: function(){
+		return this.ownerDocument;
+	},
+
+	getWindow: function(){
+		return this.ownerDocument.getWindow();
+	},
+
+	getElementById: function(id, nocash){
+		var el = this.ownerDocument.getElementById(id);
+		if (!el) return null;
+		for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
+			if (!parent) return null;
+		}
+		return $.element(el, nocash);
+	},
+
+	set: function(prop, value){
+		switch ($type(prop)){
+			case 'object':
+				for (var p in prop) this.set(p, prop[p]);
+				break;
+			case 'string':
+				var property = Element.Properties.get(prop);
+				(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
+		}
+		return this;
+	},
+
+	get: function(prop){
+		var property = Element.Properties.get(prop);
+		return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
+	},
+
+	erase: function(prop){
+		var property = Element.Properties.get(prop);
+		(property && property.erase) ? property.erase.apply(this, Array.slice(arguments, 1)) : this.removeProperty(prop);
+		return this;
+	},
+
+	match: function(tag){
+		return (!tag || Element.get(this, 'tag') == tag);
+	},
+
+	inject: function(el, where){
+		Element.Inserters.get(where || 'bottom')(this, $(el, true));
+		return this;
+	},
+
+	wraps: function(el, where){
+		el = $(el, true);
+		return this.replaces(el).grab(el, where);
+	},
+
+	grab: function(el, where){
+		Element.Inserters.get(where || 'bottom')($(el, true), this);
+		return this;
+	},
+
+	appendText: function(text, where){
+		return this.grab(this.getDocument().newTextNode(text), where);
+	},
+
+	adopt: function(){
+		Array.flatten(arguments).each(function(element){
+			element = $(element, true);
+			if (element) this.appendChild(element);
+		}, this);
+		return this;
+	},
+
+	dispose: function(){
+		return (this.parentNode) ? this.parentNode.removeChild(this) : this;
+	},
+
+	clone: function(contents, keepid){
+		switch ($type(this)){
+			case 'element':
+				var attributes = {};
+				for (var j = 0, l = this.attributes.length; j < l; j++){
+					var attribute = this.attributes[j], key = attribute.nodeName.toLowerCase();
+					if (Browser.Engine.trident && (/input/i).test(this.tagName) && (/width|height/).test(key)) continue;
+					var value = (key == 'style' && this.style) ? this.style.cssText : attribute.nodeValue;
+					if (!$chk(value) || key == 'uid' || (key == 'id' && !keepid)) continue;
+					if (value != 'inherit' && ['string', 'number'].contains($type(value))) attributes[key] = value;
+				}
+				var element = new Element(this.nodeName.toLowerCase(), attributes);
+				if (contents !== false){
+					for (var i = 0, k = this.childNodes.length; i < k; i++){
+						var child = Element.clone(this.childNodes[i], true, keepid);
+						if (child) element.grab(child);
+					}
+				}
+				return element;
+			case 'textnode': return document.newTextNode(this.nodeValue);
+		}
+		return null;
+	},
+
+	replaces: function(el){
+		el = $(el, true);
+		el.parentNode.replaceChild(this, el);
+		return this;
+	},
+
+	hasClass: function(className){
+		return this.className.contains(className, ' ');
+	},
+
+	addClass: function(className){
+		if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
+		return this;
+	},
+
+	removeClass: function(className){
+		this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
+		return this;
+	},
+
+	toggleClass: function(className){
+		return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
+	},
+
+	getComputedStyle: function(property){
+		if (this.currentStyle) return this.currentStyle[property.camelCase()];
+		var computed = this.getWindow().getComputedStyle(this, null);
+		return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
+	},
+
+	empty: function(){
+		$A(this.childNodes).each(function(node){
+			Browser.freeMem(node);
+			Element.empty(node);
+			Element.dispose(node);
+		}, this);
+		return this;
+	},
+
+	destroy: function(){
+		Browser.freeMem(this.empty().dispose());
+		return null;
+	},
+
+	getSelected: function(){
+		return new Elements($A(this.options).filter(function(option){
+			return option.selected;
+		}));
+	},
+
+	toQueryString: function(){
+		var queryString = [];
+		this.getElements('input, select, textarea').each(function(el){
+			if (!el.name || el.disabled) return;
+			var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
+				return opt.value;
+			}) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
+			$splat(value).each(function(val){
+				if (val) queryString.push(el.name + '=' + encodeURIComponent(val));
+			});
+		});
+		return queryString.join('&');
+	},
+
+	getProperty: function(attribute){
+		var EA = Element.Attributes, key = EA.Props[attribute];
+		var value = (key) ? this[key] : this.getAttribute(attribute, 2);
+		return (EA.Bools[attribute]) ? !!value : (key) ? value : value || null;
+	},
+
+	getProperties: function(){
+		var args = $A(arguments);
+		return args.map(function(attr){
+			return this.getProperty(attr);
+		}, this).associate(args);
+	},
+
+	setProperty: function(attribute, value){
+		var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value);
+		if (key && EA.Bools[attribute]) value = (value || !hasValue) ? true : false;
+		else if (!hasValue) return this.removeProperty(attribute);
+		(key) ? this[key] = value : this.setAttribute(attribute, value);
+		return this;
+	},
+
+	setProperties: function(attributes){
+		for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
+		return this;
+	},
+
+	removeProperty: function(attribute){
+		var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]);
+		(key) ? this[key] = (isBool) ? false : '' : this.removeAttribute(attribute);
+		return this;
+	},
+
+	removeProperties: function(){
+		Array.each(arguments, this.removeProperty, this);
+		return this;
+	}
+
+});
+
+(function(){
+
+var walk = function(element, walk, start, match, all, nocash){
+	var el = element[start || walk];
+	var elements = [];
+	while (el){
+		if (el.nodeType == 1 && (!match || Element.match(el, match))){
+			elements.push(el);
+			if (!all) break;
+		}
+		el = el[walk];
+	}
+	return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : $(elements[0], nocash);
+};
+
+Element.implement({
+
+	getPrevious: function(match, nocash){
+		return walk(this, 'previousSibling', null, match, false, nocash);
+	},
+
+	getAllPrevious: function(match, nocash){
+		return walk(this, 'previousSibling', null, match, true, nocash);
+	},
+
+	getNext: function(match, nocash){
+		return walk(this, 'nextSibling', null, match, false, nocash);
+	},
+
+	getAllNext: function(match, nocash){
+		return walk(this, 'nextSibling', null, match, true, nocash);
+	},
+
+	getFirst: function(match, nocash){
+		return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
+	},
+
+	getLast: function(match, nocash){
+		return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
+	},
+
+	getParent: function(match, nocash){
+		return walk(this, 'parentNode', null, match, false, nocash);
+	},
+
+	getParents: function(match, nocash){
+		return walk(this, 'parentNode', null, match, true, nocash);
+	},
+
+	getChildren: function(match, nocash){
+		return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
+	},
+
+	hasChild: function(el){
+		el = $(el, true);
+		return (!!el && $A(this.getElementsByTagName(el.tagName)).contains(el));
+	}
+
+});
+
+})();
+
+Element.Properties = new Hash;
+
+Element.Properties.style = {
+
+	set: function(style){
+		this.style.cssText = style;
+	},
+
+	get: function(){
+		return this.style.cssText;
+	},
+
+	erase: function(){
+		this.style.cssText = '';
+	}
+
+};
+
+Element.Properties.tag = {get: function(){
+	return this.tagName.toLowerCase();
+}};
+
+Element.Properties.href = {get: function(){
+	return (!this.href) ? null : this.href.replace(new RegExp('^' + document.location.protocol + '\/\/' + document.location.host), '');
+}};
+
+Element.Properties.html = {set: function(){
+	return this.innerHTML = Array.flatten(arguments).join('');
+}};
+
+Native.implement([Element, Window, Document], {
+
+	addListener: function(type, fn){
+		if (this.addEventListener) this.addEventListener(type, fn, false);
+		else this.attachEvent('on' + type, fn);
+		return this;
+	},
+
+	removeListener: function(type, fn){
+		if (this.removeEventListener) this.removeEventListener(type, fn, false);
+		else this.detachEvent('on' + type, fn);
+		return this;
+	},
+
+	retrieve: function(property, dflt){
+		var storage = Element.Storage.get(this.uid);
+		var prop = storage[property];
+		if ($defined(dflt) && !$defined(prop)) prop = storage[property] = dflt;
+		return $pick(prop);
+	},
+
+	store: function(property, value){
+		var storage = Element.Storage.get(this.uid);
+		storage[property] = value;
+		return this;
+	},
+
+	eliminate: function(property){
+		var storage = Element.Storage.get(this.uid);
+		delete storage[property];
+		return this;
+	}
+
+});
+
+Element.Attributes = new Hash({
+	Props: {'html': 'innerHTML', 'class': 'className', 'for': 'htmlFor', 'text': (Browser.Engine.trident) ? 'innerText' : 'textContent'},
+	Bools: ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'],
+	Camels: ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']
+});
+
+Browser.freeMem = function(item){
+	if (!item) return;
+	if (Browser.Engine.trident && (/object/i).test(item.tagName)){
+		for (var p in item){
+			if (typeof item[p] == 'function') item[p] = $empty;
+		}
+		Element.dispose(item);
+	}
+	if (item.uid && item.removeEvents) item.removeEvents();
+};
+
+(function(EA){
+
+	var EAB = EA.Bools, EAC = EA.Camels;
+	EA.Bools = EAB = EAB.associate(EAB);
+	Hash.extend(Hash.combine(EA.Props, EAB), EAC.associate(EAC.map(function(v){
+		return v.toLowerCase();
+	})));
+	EA.erase('Camels');
+
+})(Element.Attributes);
+
+window.addListener('unload', function(){
+	window.removeListener('unload', arguments.callee);
+	document.purge();
+	if (Browser.Engine.trident) CollectGarbage();
+});
+
+/*
+Script: Element.Event.js
+	Contains Element methods for dealing with events, and custom Events.
+
+License:
+	MIT-style license.
+*/
+
+Element.Properties.events = {set: function(events){
+	this.addEvents(events);
+}};
+
+Native.implement([Element, Window, Document], {
+
+	addEvent: function(type, fn){
+		var events = this.retrieve('events', {});
+		events[type] = events[type] || {'keys': [], 'values': []};
+		if (events[type].keys.contains(fn)) return this;
+		events[type].keys.push(fn);
+		var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
+		if (custom){
+			if (custom.onAdd) custom.onAdd.call(this, fn);
+			if (custom.condition){
+				condition = function(event){
+					if (custom.condition.call(this, event)) return fn.call(this, event);
+					return false;
+				};
+			}
+			realType = custom.base || realType;
+		}
+		var defn = function(){
+			return fn.call(self);
+		};
+		var nativeEvent = Element.NativeEvents[realType] || 0;
+		if (nativeEvent){
+			if (nativeEvent == 2){
+				defn = function(event){
+					event = new Event(event, self.getWindow());
+					if (condition.call(self, event) === false) event.stop();
+				};
+			}
+			this.addListener(realType, defn);
+		}
+		events[type].values.push(defn);
+		return this;
+	},
+
+	removeEvent: function(type, fn){
+		var events = this.retrieve('events');
+		if (!events || !events[type]) return this;
+		var pos = events[type].keys.indexOf(fn);
+		if (pos == -1) return this;
+		var key = events[type].keys.splice(pos, 1)[0];
+		var value = events[type].values.splice(pos, 1)[0];
+		var custom = Element.Events.get(type);
+		if (custom){
+			if (custom.onRemove) custom.onRemove.call(this, fn);
+			type = custom.base || type;
+		}
+		return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
+	},
+
+	addEvents: function(events){
+		for (var event in events) this.addEvent(event, events[event]);
+		return this;
+	},
+
+	removeEvents: function(type){
+		var events = this.retrieve('events');
+		if (!events) return this;
+		if (!type){
+			for (var evType in events) this.removeEvents(evType);
+			events = null;
+		} else if (events[type]){
+			while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);
+			events[type] = null;
+		}
+		return this;
+	},
+
+	fireEvent: function(type, args, delay){
+		var events = this.retrieve('events');
+		if (!events || !events[type]) return this;
+		events[type].keys.each(function(fn){
+			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
+		}, this);
+		return this;
+	},
+
+	cloneEvents: function(from, type){
+		from = $(from);
+		var fevents = from.retrieve('events');
+		if (!fevents) return this;
+		if (!type){
+			for (var evType in fevents) this.cloneEvents(from, evType);
+		} else if (fevents[type]){
+			fevents[type].keys.each(function(fn){
+				this.addEvent(type, fn);
+			}, this);
+		}
+		return this;
+	}
+
+});
+
+Element.NativeEvents = {
+	click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
+	mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
+	mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
+	keydown: 2, keypress: 2, keyup: 2, //keyboard
+	focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
+	load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
+	error: 1, abort: 1, scroll: 1 //misc
+};
+
+(function(){
+
+var $check = function(event){
+	var related = event.relatedTarget;
+	if (related == undefined) return true;
+	if (related === false) return false;
+	return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
+};
+
+Element.Events = new Hash({
+
+	mouseenter: {
+		base: 'mouseover',
+		condition: $check
+	},
+
+	mouseleave: {
+		base: 'mouseout',
+		condition: $check
+	},
+
+	mousewheel: {
+		base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
+	}
+
+});
+
+})();
+
+/*
+Script: Element.Style.js
+	Contains methods for interacting with the styles of Elements in a fashionable way.
+
+License:
+	MIT-style license.
+*/
+
+Element.Properties.styles = {set: function(styles){
+	this.setStyles(styles);
+}};
+
+Element.Properties.opacity = {
+
+	set: function(opacity, novisibility){
+		if (!novisibility){
+			if (opacity == 0){
+				if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
+			} else {
+				if (this.style.visibility != 'visible') this.style.visibility = 'visible';
+			}
+		}
+		if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
+		if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
+		this.style.opacity = opacity;
+		this.store('opacity', opacity);
+	},
+
+	get: function(){
+		return this.retrieve('opacity', 1);
+	}
+
+};
+
+Element.implement({
+	
+	setOpacity: function(value){
+		return this.set('opacity', value, true);
+	},
+	
+	getOpacity: function(){
+		return this.get('opacity');
+	},
+
+	setStyle: function(property, value){
+		switch (property){
+			case 'opacity': return this.set('opacity', parseFloat(value));
+			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
+		}
+		property = property.camelCase();
+		if ($type(value) != 'string'){
+			var map = (Element.Styles.get(property) || '@').split(' ');
+			value = $splat(value).map(function(val, i){
+				if (!map[i]) return '';
+				return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
+			}).join(' ');
+		} else if (value == String(Number(value))){
+			value = Math.round(value);
+		}
+		this.style[property] = value;
+		return this;
+	},
+
+	getStyle: function(property){
+		switch (property){
+			case 'opacity': return this.get('opacity');
+			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
+		}
+		property = property.camelCase();
+		var result = this.style[property];
+		if (!$chk(result)){
+			result = [];
+			for (var style in Element.ShortStyles){
+				if (property != style) continue;
+				for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
+				return result.join(' ');
+			}
+			result = this.getComputedStyle(property);
+		}
+		if (result){
+			result = String(result);
+			var color = result.match(/rgba?\([\d\s,]+\)/);
+			if (color) result = result.replace(color[0], color[0].rgbToHex());
+		}
+		if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))){
+			if (property.test(/^(height|width)$/)){
+				var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
+				values.each(function(value){
+					size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
+				}, this);
+				return this['offset' + property.capitalize()] - size + 'px';
+			}
+			if (Browser.Engine.presto && String(result).test('px')) return result;
+			if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
+		}
+		return result;
+	},
+
+	setStyles: function(styles){
+		for (var style in styles) this.setStyle(style, styles[style]);
+		return this;
+	},
+
+	getStyles: function(){
+		var result = {};
+		Array.each(arguments, function(key){
+			result[key] = this.getStyle(key);
+		}, this);
+		return result;
+	}
+
+});
+
+Element.Styles = new Hash({
+	left: '@px', top: '@px', bottom: '@px', right: '@px',
+	width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
+	backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
+	fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
+	margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
+	borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
+	zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
+});
+
+Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
+
+['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
+	var Short = Element.ShortStyles;
+	var All = Element.Styles;
+	['margin', 'padding'].each(function(style){
+		var sd = style + direction;
+		Short[style][sd] = All[sd] = '@px';
+	});
+	var bd = 'border' + direction;
+	Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
+	var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
+	Short[bd] = {};
+	Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
+	Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
+	Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
+});
+
+
+/*
+Script: Element.Dimensions.js
+	Contains methods to work with size, scroll, or positioning of Elements and the window object.
+
+License:
+	MIT-style license.
+
+Credits:
+	- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
+	- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
+*/
+
+(function(){
+
+Element.implement({
+
+	scrollTo: function(x, y){
+		if (isBody(this)){
+			this.getWindow().scrollTo(x, y);
+		} else {
+			this.scrollLeft = x;
+			this.scrollTop = y;
+		}
+		return this;
+	},
+
+	getSize: function(){
+		if (isBody(this)) return this.getWindow().getSize();
+		return {x: this.offsetWidth, y: this.offsetHeight};
+	},
+
+	getScrollSize: function(){
+		if (isBody(this)) return this.getWindow().getScrollSize();
+		return {x: this.scrollWidth, y: this.scrollHeight};
+	},
+
+	getScroll: function(){
+		if (isBody(this)) return this.getWindow().getScroll();
+		return {x: this.scrollLeft, y: this.scrollTop};
+	},
+
+	getScrolls: function(){
+		var element = this, position = {x: 0, y: 0};
+		while (element && !isBody(element)){
+			position.x += element.scrollLeft;
+			position.y += element.scrollTop;
+			element = element.parentNode;
+		}
+		return position;
+	},
+	
+	getOffsetParent: function(){
+		var element = this;
+		if (isBody(element)) return null; 
+		if (!Browser.Engine.trident) return element.offsetParent;
+		while ((element = element.parentNode) && !isBody(element)){ 
+			if (styleString(element, 'position') != 'static') return element;
+		} 
+		return null;
+	},
+
+	getOffsets: function(){
+		var element = this, position = {x: 0, y: 0};
+		if (isBody(this)) return position;
+
+		while (element && !isBody(element)){
+			position.x += element.offsetLeft;
+			position.y += element.offsetTop;
+
+			if (Browser.Engine.gecko){
+				if (!borderBox(element)){
+					position.x += leftBorder(element);
+					position.y += topBorder(element);
+				}
+				var parent = element.parentNode;
+				if (parent && styleString(parent, 'overflow') != 'visible'){
+					position.x += leftBorder(parent);
+					position.y += topBorder(parent);
+				}
+			} else if (element != this && (Browser.Engine.trident || Browser.Engine.webkit)){
+				position.x += leftBorder(element);
+				position.y += topBorder(element);
+			}
+
+			element = element.offsetParent;
+			if (Browser.Engine.trident){
+				while (element && !element.currentStyle.hasLayout) element = element.offsetParent;
+			}
+		}
+		if (Browser.Engine.gecko && !borderBox(this)){
+			position.x -= leftBorder(this);
+			position.y -= topBorder(this);
+		}
+		return position;
+	},
+
+	getPosition: function(relative){
+		if (isBody(this)) return {x: 0, y: 0};
+		var offset = this.getOffsets(), scroll = this.getScrolls();
+		var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
+		var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
+		return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
+	},
+
+	getCoordinates: function(element){
+		if (isBody(this)) return this.getWindow().getCoordinates();
+		var position = this.getPosition(element), size = this.getSize();
+		var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
+		obj.right = obj.left + obj.width;
+		obj.bottom = obj.top + obj.height;
+		return obj;
+	},
+
+	computePosition: function(obj){
+		return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
+	},
+
+	position: function(obj){
+		return this.setStyles(this.computePosition(obj));
+	}
+
+});
+
+Native.implement([Document, Window], {
+
+	getSize: function(){
+		var win = this.getWindow();
+		if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
+		var doc = getCompatElement(this);
+		return {x: doc.clientWidth, y: doc.clientHeight};
+	},
+
+	getScroll: function(){
+		var win = this.getWindow();
+		var doc = getCompatElement(this);
+		return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
+	},
+
+	getScrollSize: function(){
+		var doc = getCompatElement(this);
+		var min = this.getSize();
+		return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
+	},
+
+	getPosition: function(){
+		return {x: 0, y: 0};
+	},
+
+	getCoordinates: function(){
+		var size = this.getSize();
+		return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
+	}
+
+});
+
+// private methods
+
+var styleString = Element.getComputedStyle;
+
+function styleNumber(element, style){
+	return styleString(element, style).toInt() || 0;
+};
+
+function borderBox(element){
+	return styleString(element, '-moz-box-sizing') == 'border-box';
+};
+
+function topBorder(element){
+	return styleNumber(element, 'border-top-width');
+};
+
+function leftBorder(element){
+	return styleNumber(element, 'border-left-width');
+};
+
+function isBody(element){
+	return (/^(?:body|html)$/i).test(element.tagName);
+};
+
+function getCompatElement(element){
+	var doc = element.getDocument();
+	return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
+};
+
+})();
+
+//aliases
+
+Native.implement([Window, Document, Element], {
+
+	getHeight: function(){
+		return this.getSize().y;
+	},
+
+	getWidth: function(){
+		return this.getSize().x;
+	},
+
+	getScrollTop: function(){
+		return this.getScroll().y;
+	},
+
+	getScrollLeft: function(){
+		return this.getScroll().x;
+	},
+
+	getScrollHeight: function(){
+		return this.getScrollSize().y;
+	},
+
+	getScrollWidth: function(){
+		return this.getScrollSize().x;
+	},
+
+	getTop: function(){
+		return this.getPosition().y;
+	},
+
+	getLeft: function(){
+		return this.getPosition().x;
+	}
+
+});
+
+/*
+Script: Selectors.js
+	Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
+
+License:
+	MIT-style license.
+*/
+
+Native.implement([Document, Element], {
+	
+	getElements: function(expression, nocash){
+		expression = expression.split(',');
+		var items, local = {};
+		for (var i = 0, l = expression.length; i < l; i++){
+			var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
+			if (i != 0 && elements.item) elements = $A(elements);
+			items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
+		}
+		return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
+	}
+	
+});
+
+Element.implement({
+	
+	match: function(selector){
+		if (!selector) return true;
+		var tagid = Selectors.Utils.parseTagAndID(selector);
+		var tag = tagid[0], id = tagid[1];
+		if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
+		var parsed = Selectors.Utils.parseSelector(selector);
+		return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
+	}
+	
+});
+
+var Selectors = {Cache: {nth: {}, parsed: {}}};
+
+Selectors.RegExps = {
+	id: (/#([\w-]+)/),
+	tag: (/^(\w+|\*)/),
+	quick: (/^(\w+|\*)$/),
+	splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
+	combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
+};
+
+Selectors.Utils = {
+	
+	chk: function(item, uniques){
+		if (!uniques) return true;
+		var uid = $uid(item);
+		if (!uniques[uid]) return uniques[uid] = true;
+		return false;
+	},
+	
+	parseNthArgument: function(argument){
+		if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
+		var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
+		if (!parsed) return false;
+		var inta = parseInt(parsed[1]);
+		var a = (inta || inta === 0) ? inta : 1;
+		var special = parsed[2] || false;
+		var b = parseInt(parsed[3]) || 0;
+		if (a != 0){
+			b--;
+			while (b < 1) b += a;
+			while (b >= a) b -= a;
+		} else {
+			a = b;
+			special = 'index';
+		}
+		switch (special){
+			case 'n': parsed = {a: a, b: b, special: 'n'}; break;
+			case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
+			case 'even': parsed =  {a: 2, b: 1, special: 'n'}; break;
+			case 'first': parsed = {a: 0, special: 'index'}; break;
+			case 'last': parsed = {special: 'last-child'}; break;
+			case 'only': parsed = {special: 'only-child'}; break;
+			default: parsed = {a: (a - 1), special: 'index'};
+		}
+		
+		return Selectors.Cache.nth[argument] = parsed;
+	},
+	
+	parseSelector: function(selector){
+		if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
+		var m, parsed = {classes: [], pseudos: [], attributes: []};
+		while ((m = Selectors.RegExps.combined.exec(selector))){
+			var cn = m[1], an = m[2], ao = m[3], av = m[4], pn = m[5], pa = m[6];
+			if (cn){
+				parsed.classes.push(cn);
+			} else if (pn){
+				var parser = Selectors.Pseudo.get(pn);
+				if (parser) parsed.pseudos.push({parser: parser, argument: pa});
+				else parsed.attributes.push({name: pn, operator: '=', value: pa});
+			} else if (an){
+				parsed.attributes.push({name: an, operator: ao, value: av});
+			}
+		}
+		if (!parsed.classes.length) delete parsed.classes;
+		if (!parsed.attributes.length) delete parsed.attributes;
+		if (!parsed.pseudos.length) delete parsed.pseudos;
+		if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
+		return Selectors.Cache.parsed[selector] = parsed;
+	},
+	
+	parseTagAndID: function(selector){
+		var tag = selector.match(Selectors.RegExps.tag);
+		var id = selector.match(Selectors.RegExps.id);
+		return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
+	},
+	
+	filter: function(item, parsed, local){
+		var i;
+		if (parsed.classes){
+			for (i = parsed.classes.length; i--; i){
+				var cn = parsed.classes[i];
+				if (!Selectors.Filters.byClass(item, cn)) return false;
+			}
+		}
+		if (parsed.attributes){
+			for (i = parsed.attributes.length; i--; i){
+				var att = parsed.attributes[i];
+				if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
+			}
+		}
+		if (parsed.pseudos){
+			for (i = parsed.pseudos.length; i--; i){
+				var psd = parsed.pseudos[i];
+				if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
+			}
+		}
+		return true;
+	},
+	
+	getByTagAndID: function(ctx, tag, id){
+		if (id){
+			var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
+			return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
+		} else {
+			return ctx.getElementsByTagName(tag);
+		}
+	},
+	
+	search: function(self, expression, local){
+		var splitters = [];
+		
+		var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
+			splitters.push(m1);
+			return ':)' + m2;
+		}).split(':)');
+		
+		var items, match, filtered, item;
+		
+		for (var i = 0, l = selectors.length; i < l; i++){
+			
+			var selector = selectors[i];
+			
+			if (i == 0 && Selectors.RegExps.quick.test(selector)){
+				items = self.getElementsByTagName(selector);
+				continue;
+			}
+			
+			var splitter = splitters[i - 1];
+			
+			var tagid = Selectors.Utils.parseTagAndID(selector);
+			var tag = tagid[0], id = tagid[1];
+
+			if (i == 0){
+				items = Selectors.Utils.getByTagAndID(self, tag, id);
+			} else {
+				var uniques = {}, found = [];
+				for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
+				items = found;
+			}
+			
+			var parsed = Selectors.Utils.parseSelector(selector);
+			
+			if (parsed){
+				filtered = [];
+				for (var m = 0, n = items.length; m < n; m++){
+					item = items[m];
+					if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
+				}
+				items = filtered;
+			}
+			
+		}
+		
+		return items;
+		
+	}
+	
+};
+
+Selectors.Getters = {
+	
+	' ': function(found, self, tag, id, uniques){
+		var items = Selectors.Utils.getByTagAndID(self, tag, id);
+		for (var i = 0, l = items.length; i < l; i++){
+			var item = items[i];
+			if (Selectors.Utils.chk(item, uniques)) found.push(item);
+		}
+		return found;
+	},
+	
+	'>': function(found, self, tag, id, uniques){
+		var children = Selectors.Utils.getByTagAndID(self, tag, id);
+		for (var i = 0, l = children.length; i < l; i++){
+			var child = children[i];
+			if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
+		}
+		return found;
+	},
+	
+	'+': function(found, self, tag, id, uniques){
+		while ((self = self.nextSibling)){
+			if (self.nodeType == 1){
+				if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
+				break;
+			}
+		}
+		return found;
+	},
+	
+	'~': function(found, self, tag, id, uniques){
+		
+		while ((self = self.nextSibling)){
+			if (self.nodeType == 1){
+				if (!Selectors.Utils.chk(self, uniques)) break;
+				if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
+			} 
+		}
+		return found;
+	}
+	
+};
+
+Selectors.Filters = {
+	
+	byTag: function(self, tag){
+		return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
+	},
+	
+	byID: function(self, id){
+		return (!id || (self.id && self.id == id));
+	},
+	
+	byClass: function(self, klass){
+		return (self.className && self.className.contains(klass, ' '));
+	},
+	
+	byPseudo: function(self, parser, argument, local){
+		return parser.call(self, argument, local);
+	},
+	
+	byAttribute: function(self, name, operator, value){
+		var result = Element.prototype.getProperty.call(self, name);
+		if (!result) return false;
+		if (!operator || value == undefined) return true;
+		switch (operator){
+			case '=': return (result == value);
+			case '*=': return (result.contains(value));
+			case '^=': return (result.substr(0, value.length) == value);
+			case '$=': return (result.substr(result.length - value.length) == value);
+			case '!=': return (result != value);
+			case '~=': return result.contains(value, ' ');
+			case '|=': return result.contains(value, '-');
+		}
+		return false;
+	}
+	
+};
+
+Selectors.Pseudo = new Hash({
+	
+	// w3c pseudo selectors
+	
+	empty: function(){
+		return !(this.innerText || this.textContent || '').length;
+	},
+	
+	not: function(selector){
+		return !Element.match(this, selector);
+	},
+	
+	contains: function(text){
+		return (this.innerText || this.textContent || '').contains(text);
+	},
+	
+	'first-child': function(){
+		return Selectors.Pseudo.index.call(this, 0);
+	},
+	
+	'last-child': function(){
+		var element = this;
+		while ((element = element.nextSibling)){
+			if (element.nodeType == 1) return false;
+		}
+		return true;
+	},
+	
+	'only-child': function(){
+		var prev = this;
+		while ((prev = prev.previousSibling)){
+			if (prev.nodeType == 1) return false;
+		}
+		var next = this;
+		while ((next = next.nextSibling)){
+			if (next.nodeType == 1) return false;
+		}
+		return true;
+	},
+	
+	'nth-child': function(argument, local){
+		argument = (argument == undefined) ? 'n' : argument;
+		var parsed = Selectors.Utils.parseNthArgument(argument);
+		if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
+		var count = 0;
+		local.positions = local.positions || {};
+		var uid = $uid(this);
+		if (!local.positions[uid]){
+			var self = this;
+			while ((self = self.previousSibling)){
+				if (self.nodeType != 1) continue;
+				count ++;
+				var position = local.positions[$uid(self)];
+				if (position != undefined){
+					count = position + count;
+					break;
+				}
+			}
+			local.positions[uid] = count;
+		}
+		return (local.positions[uid] % parsed.a == parsed.b);
+	},
+	
+	// custom pseudo selectors
+	
+	index: function(index){
+		var element = this, count = 0;
+		while ((element = element.previousSibling)){
+			if (element.nodeType == 1 && ++count > index) return false;
+		}
+		return (count == index);
+	},
+	
+	even: function(argument, local){
+		return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
+	},
+
+	odd: function(argument, local){
+		return Selectors.Pseudo['nth-child'].call(this, '2n', local);
+	}
+	
+});
+
+/*
+Script: Domready.js
+	Contains the domready custom event.
+
+License:
+	MIT-style license.
+*/
+
+Element.Events.domready = {
+
+	onAdd: function(fn){
+		if (Browser.loaded) fn.call(this);
+	}
+
+};
+
+(function(){
+	
+	var domready = function(){
+		if (Browser.loaded) return;
+		Browser.loaded = true;
+		window.fireEvent('domready');
+		document.fireEvent('domready');
+	};
+	
+	switch (Browser.Engine.name){
+
+		case 'webkit': (function(){
+			(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
+		})(); break;
+
+		case 'trident':
+			var temp = document.createElement('div');
+			(function(){
+				($try(function(){
+					temp.doScroll('left');
+					return $(temp).inject(document.body).set('html', 'temp').dispose();
+				})) ? domready() : arguments.callee.delay(50);
+			})();
+		break;
+		
+		default:
+			window.addEvent('load', domready);
+			document.addEvent('DOMContentLoaded', domready);
+
+	}
+	
+})();
+
+/*
+Script: JSON.js
+	JSON encoder and decoder.
+
+License:
+	MIT-style license.
+
+See Also:
+	<http://www.json.org/>
+*/
+
+var JSON = new Hash({
+
+	encode: function(obj){
+		switch ($type(obj)){
+			case 'string':
+				return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
+			case 'array':
+				return '[' + String(obj.map(JSON.encode).filter($defined)) + ']';
+			case 'object': case 'hash':
+				var string = [];
+				Hash.each(obj, function(value, key){
+					var json = JSON.encode(value);
+					if (json) string.push(JSON.encode(key) + ':' + json);
+				});
+				return '{' + string + '}';
+			case 'number': case 'boolean': return String(obj);
+			case false: return 'null';
+		}
+		return null;
+	},
+
+	$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
+
+	$replaceChars: function(chr){
+		return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
+	},
+
+	decode: function(string, secure){
+		if ($type(string) != 'string' || !string.length) return null;
+		if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
+		return eval('(' + string + ')');
+	}
+
+});
+
+Native.implement([Hash, Array, String, Number], {
+
+	toJSON: function(){
+		return JSON.encode(this);
+	}
+
+});
+
+
+/*
+Script: Cookie.js
+	Class for creating, loading, and saving browser Cookies.
+
+License:
+	MIT-style license.
+
+Credits:
+	Based on the functions by Peter-Paul Koch (http://quirksmode.org).
+*/
+
+var Cookie = new Class({
+
+	Implements: Options,
+
+	options: {
+		path: false,
+		domain: false,
+		duration: false,
+		secure: false,
+		document: document
+	},
+
+	initialize: function(key, options){
+		this.key = key;
+		this.setOptions(options);
+	},
+
+	write: function(value){
+		value = encodeURIComponent(value);
+		if (this.options.domain) value += '; domain=' + this.options.domain;
+		if (this.options.path) value += '; path=' + this.options.path;
+		if (this.options.duration){
+			var date = new Date();
+			date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
+			value += '; expires=' + date.toGMTString();
+		}
+		if (this.options.secure) value += '; secure';
+		this.options.document.cookie = this.key + '=' + value;
+		return this;
+	},
+
+	read: function(){
+		var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
+		return (value) ? decodeURIComponent(value[1]) : null;
+	},
+
+	dispose: function(){
+		new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
+		return this;
+	}
+
+});
+
+Cookie.write = function(key, value, options){
+	return new Cookie(key, options).write(value);
+};
+
+Cookie.read = function(key){
+	return new Cookie(key).read();
+};
+
+Cookie.dispose = function(key, options){
+	return new Cookie(key, options).dispose();
+};
+
+/*
+Script: Swiff.js
+	Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
+
+License:
+	MIT-style license.
+
+Credits:
+	Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
+*/
+
+var Swiff = new Class({
+
+	Implements: [Options],
+
+	options: {
+		id: null,
+		height: 1,
+		width: 1,
+		container: null,
+		properties: {},
+		params: {
+			quality: 'high',
+			allowScriptAccess: 'always',
+			wMode: 'transparent',
+			swLiveConnect: true
+		},
+		callBacks: {},
+		vars: {}
+	},
+
+	toElement: function(){
+		return this.object;
+	},
+
+	initialize: function(path, options){
+		this.instance = 'Swiff_' + $time();
+
+		this.setOptions(options);
+		options = this.options;
+		var id = this.id = options.id || this.instance;
+		var container = $(options.container);
+
+		Swiff.CallBacks[this.instance] = {};
+
+		var params = options.params, vars = options.vars, callBacks = options.callBacks;
+		var properties = $extend({height: options.height, width: options.width}, options.properties);
+
+		var self = this;
+
+		for (var callBack in callBacks){
+			Swiff.CallBacks[this.instance][callBack] = (function(option){
+				return function(){
+					return option.apply(self.object, arguments);
+				};
+			})(callBacks[callBack]);
+			vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
+		}
+
+		params.flashVars = Hash.toQueryString(vars);
+		if (Browser.Engine.trident){
+			properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
+			params.movie = path;
+		} else {
+			properties.type = 'application/x-shockwave-flash';
+			properties.data = path;
+		}
+		var build = '<object id="' + id + '"';
+		for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
+		build += '>';
+		for (var param in params){
+			if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
+		}
+		build += '</object>';
+		this.object =  ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
+	},
+
+	replaces: function(element){
+		element = $(element, true);
+		element.parentNode.replaceChild(this.toElement(), element);
+		return this;
+	},
+
+	inject: function(element){
+		$(element, true).appendChild(this.toElement());
+		return this;
+	},
+
+	remote: function(){
+		return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments));
+	}
+
+});
+
+Swiff.CallBacks = {};
+
+Swiff.remote = function(obj, fn){
+	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
+	return eval(rs);
+};
+
+/*
+Script: Fx.js
+	Contains the basic animation logic to be extended by all other Fx Classes.
+
+License:
+	MIT-style license.
+*/
+
+var Fx = new Class({
+
+	Implements: [Chain, Events, Options],
+
+	options: {
+		/*
+		onStart: $empty,
+		onCancel: $empty,
+		onComplete: $empty,
+		*/
+		fps: 50,
+		unit: false,
+		duration: 500,
+		link: 'ignore',
+		transition: function(p){
+			return -(Math.cos(Math.PI * p) - 1) / 2;
+		}
+	},
+
+	initialize: function(options){
+		this.subject = this.subject || this;
+		this.setOptions(options);
+		this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
+		var wait = this.options.wait;
+		if (wait === false) this.options.link = 'cancel';
+	},
+
+	step: function(){
+		var time = $time();
+		if (time < this.time + this.options.duration){
+			var delta = this.options.transition((time - this.time) / this.options.duration);
+			this.set(this.compute(this.from, this.to, delta));
+		} else {
+			this.set(this.compute(this.from, this.to, 1));
+			this.complete();
+		}
+	},
+
+	set: function(now){
+		return now;
+	},
+
+	compute: function(from, to, delta){
+		return Fx.compute(from, to, delta);
+	},
+
+	check: function(caller){
+		if (!this.timer) return true;
+		switch (this.options.link){
+			case 'cancel': this.cancel(); return true;
+			case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
+		}
+		return false;
+	},
+
+	start: function(from, to){
+		if (!this.check(arguments.callee, from, to)) return this;
+		this.from = from;
+		this.to = to;
+		this.time = 0;
+		this.startTimer();
+		this.onStart();
+		return this;
+	},
+
+	complete: function(){
+		if (this.stopTimer()) this.onComplete();
+		return this;
+	},
+
+	cancel: function(){
+		if (this.stopTimer()) this.onCancel();
+		return this;
+	},
+
+	onStart: function(){
+		this.fireEvent('start', this.subject);
+	},
+
+	onComplete: function(){
+		this.fireEvent('complete', this.subject);
+		if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
+	},
+
+	onCancel: function(){
+		this.fireEvent('cancel', this.subject).clearChain();
+	},
+
+	pause: function(){
+		this.stopTimer();
+		return this;
+	},
+
+	resume: function(){
+		this.startTimer();
+		return this;
+	},
+
+	stopTimer: function(){
+		if (!this.timer) return false;
+		this.time = $time() - this.time;
+		this.timer = $clear(this.timer);
+		return true;
+	},
+
+	startTimer: function(){
+		if (this.timer) return false;
+		this.time = $time() - this.time;
+		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
+		return true;
+	}
+
+});
+
+Fx.compute = function(from, to, delta){
+	return (to - from) * delta + from;
+};
+
+Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
+
+
+/*
+Script: Fx.CSS.js
+	Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
+
+License:
+	MIT-style license.
+*/
+
+Fx.CSS = new Class({
+
+	Extends: Fx,
+
+	//prepares the base from/to object
+
+	prepare: function(element, property, values){
+		values = $splat(values);
+		var values1 = values[1];
+		if (!$chk(values1)){
+			values[1] = values[0];
+			values[0] = element.getStyle(property);
+		}
+		var parsed = values.map(this.parse);
+		return {from: parsed[0], to: parsed[1]};
+	},
+
+	//parses a value into an array
+
+	parse: function(value){
+		value = $lambda(value)();
+		value = (typeof value == 'string') ? value.split(' ') : $splat(value);
+		return value.map(function(val){
+			val = String(val);
+			var found = false;
+			Fx.CSS.Parsers.each(function(parser, key){
+				if (found) return;
+				var parsed = parser.parse(val);
+				if ($chk(parsed)) found = {value: parsed, parser: parser};
+			});
+			found = found || {value: val, parser: Fx.CSS.Parsers.String};
+			return found;
+		});
+	},
+
+	//computes by a from and to prepared objects, using their parsers.
+
+	compute: function(from, to, delta){
+		var computed = [];
+		(Math.min(from.length, to.length)).times(function(i){
+			computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
+		});
+		computed.$family = {name: 'fx:css:value'};
+		return computed;
+	},
+
+	//serves the value as settable
+
+	serve: function(value, unit){
+		if ($type(value) != 'fx:css:value') value = this.parse(value);
+		var returned = [];
+		value.each(function(bit){
+			returned = returned.concat(bit.parser.serve(bit.value, unit));
+		});
+		return returned;
+	},
+
+	//renders the change to an element
+
+	render: function(element, property, value, unit){
+		element.setStyle(property, this.serve(value, unit));
+	},
+
+	//searches inside the page css to find the values for a selector
+
+	search: function(selector){
+		if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
+		var to = {};
+		Array.each(document.styleSheets, function(sheet, j){
+			var href = sheet.href;
+			if (href && href.contains('://') && !href.contains(document.domain)) return;
+			var rules = sheet.rules || sheet.cssRules;
+			Array.each(rules, function(rule, i){
+				if (!rule.style) return;
+				var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
+					return m.toLowerCase();
+				}) : null;
+				if (!selectorText || !selectorText.test('^' + selector + '$')) return;
+				Element.Styles.each(function(value, style){
+					if (!rule.style[style] || Element.ShortStyles[style]) return;
+					value = String(rule.style[style]);
+					to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
+				});
+			});
+		});
+		return Fx.CSS.Cache[selector] = to;
+	}
+
+});
+
+Fx.CSS.Cache = {};
+
+Fx.CSS.Parsers = new Hash({
+
+	Color: {
+		parse: function(value){
+			if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
+			return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
+		},
+		compute: function(from, to, delta){
+			return from.map(function(value, i){
+				return Math.round(Fx.compute(from[i], to[i], delta));
+			});
+		},
+		serve: function(value){
+			return value.map(Number);
+		}
+	},
+
+	Number: {
+		parse: parseFloat,
+		compute: Fx.compute,
+		serve: function(value, unit){
+			return (unit) ? value + unit : value;
+		}
+	},
+
+	String: {
+		parse: $lambda(false),
+		compute: $arguments(1),
+		serve: $arguments(0)
+	}
+
+});
+
+
+/*
+Script: Fx.Tween.js
+	Formerly Fx.Style, effect to transition any CSS property for an element.
+
+License:
+	MIT-style license.
+*/
+
+Fx.Tween = new Class({
+
+	Extends: Fx.CSS,
+
+	initialize: function(element, options){
+		this.element = this.subject = $(element);
+		this.parent(options);
+	},
+
+	set: function(property, now){
+		if (arguments.length == 1){
+			now = property;
+			property = this.property || this.options.property;
+		}
+		this.render(this.element, property, now, this.options.unit);
+		return this;
+	},
+
+	start: function(property, from, to){
+		if (!this.check(arguments.callee, property, from, to)) return this;
+		var args = Array.flatten(arguments);
+		this.property = this.options.property || args.shift();
+		var parsed = this.prepare(this.element, this.property, args);
+		return this.parent(parsed.from, parsed.to);
+	}
+
+});
+
+Element.Properties.tween = {
+
+	set: function(options){
+		var tween = this.retrieve('tween');
+		if (tween) tween.cancel();
+		return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
+	},
+
+	get: function(options){
+		if (options || !this.retrieve('tween')){
+			if (options || !this.retrieve('tween:options')) this.set('tween', options);
+			this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
+		}
+		return this.retrieve('tween');
+	}
+
+};
+
+Element.implement({
+
+	tween: function(property, from, to){
+		this.get('tween').start(arguments);
+		return this;
+	},
+
+	fade: function(how){
+		var fade = this.get('tween'), o = 'opacity', toggle;
+		how = $pick(how, 'toggle');
+		switch (how){
+			case 'in': fade.start(o, 1); break;
+			case 'out': fade.start(o, 0); break;
+			case 'show': fade.set(o, 1); break;
+			case 'hide': fade.set(o, 0); break;
+			case 'toggle':
+				var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
+				fade.start(o, (flag) ? 0 : 1);
+				this.store('fade:flag', !flag);
+				toggle = true;
+			break;
+			default: fade.start(o, arguments);
+		}
+		if (!toggle) this.eliminate('fade:flag');
+		return this;
+	},
+
+	highlight: function(start, end){
+		if (!end){
+			end = this.retrieve('highlight:original', this.getStyle('background-color'));
+			end = (end == 'transparent') ? '#fff' : end;
+		}
+		var tween = this.get('tween');
+		tween.start('background-color', start || '#ffff88', end).chain(function(){
+			this.setStyle('background-color', this.retrieve('highlight:original'));
+			tween.callChain();
+		}.bind(this));
+		return this;
+	}
+
+});
+
+
+/*
+Script: Fx.Morph.js
+	Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
+
+License:
+	MIT-style license.
+*/
+
+Fx.Morph = new Class({
+
+	Extends: Fx.CSS,
+
+	initialize: function(element, options){
+		this.element = this.subject = $(element);
+		this.parent(options);
+	},
+
+	set: function(now){
+		if (typeof now == 'string') now = this.search(now);
+		for (var p in now) this.render(this.element, p, now[p], this.options.unit);
+		return this;
+	},
+
+	compute: function(from, to, delta){
+		var now = {};
+		for (var p in from) now[p] = this.parent(from[p], to[p], delta);
+		return now;
+	},
+
+	start: function(properties){
+		if (!this.check(arguments.callee, properties)) return this;
+		if (typeof properties == 'string') properties = this.search(properties);
+		var from = {}, to = {};
+		for (var p in properties){
+			var parsed = this.prepare(this.element, p, properties[p]);
+			from[p] = parsed.from;
+			to[p] = parsed.to;
+		}
+		return this.parent(from, to);
+	}
+
+});
+
+Element.Properties.morph = {
+
+	set: function(options){
+		var morph = this.retrieve('morph');
+		if (morph) morph.cancel();
+		return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
+	},
+
+	get: function(options){
+		if (options || !this.retrieve('morph')){
+			if (options || !this.retrieve('morph:options')) this.set('morph', options);
+			this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
+		}
+		return this.retrieve('morph');
+	}
+
+};
+
+Element.implement({
+
+	morph: function(props){
+		this.get('morph').start(props);
+		return this;
+	}
+
+});
+
+/*
+Script: Fx.Transitions.js
+	Contains a set of advanced transitions to be used with any of the Fx Classes.
+
+License:
+	MIT-style license.
+
+Credits:
+	Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
+*/
+
+(function(){
+
+	var old = Fx.prototype.initialize;
+
+	Fx.prototype.initialize = function(options){
+		old.call(this, options);
+		var trans = this.options.transition;
+		if (typeof trans == 'string' && (trans = trans.split(':'))){
+			var base = Fx.Transitions;
+			base = base[trans[0]] || base[trans[0].capitalize()];
+			if (trans[1]) base = base['ease' + trans[1].capitalize() + (trans[2] ? trans[2].capitalize() : '')];
+			this.options.transition = base;
+		}
+	};
+
+})();
+
+Fx.Transition = function(transition, params){
+	params = $splat(params);
+	return $extend(transition, {
+		easeIn: function(pos){
+			return transition(pos, params);
+		},
+		easeOut: function(pos){
+			return 1 - transition(1 - pos, params);
+		},
+		easeInOut: function(pos){
+			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
+		}
+	});
+};
+
+Fx.Transitions = new Hash({
+
+	linear: $arguments(0)
+
+});
+
+Fx.Transitions.extend = function(transitions){
+	for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
+};
+
+Fx.Transitions.extend({
+
+	Pow: function(p, x){
+		return Math.pow(p, x[0] || 6);
+	},
+
+	Expo: function(p){
+		return Math.pow(2, 8 * (p - 1));
+	},
+
+	Circ: function(p){
+		return 1 - Math.sin(Math.acos(p));
+	},
+
+	Sine: function(p){
+		return 1 - Math.sin((1 - p) * Math.PI / 2);
+	},
+
+	Back: function(p, x){
+		x = x[0] || 1.618;
+		return Math.pow(p, 2) * ((x + 1) * p - x);
+	},
+
+	Bounce: function(p){
+		var value;
+		for (var a = 0, b = 1; 1; a += b, b /= 2){
+			if (p >= (7 - 4 * a) / 11){
+				value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
+				break;
+			}
+		}
+		return value;
+	},
+
+	Elastic: function(p, x){
+		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
+	}
+
+});
+
+['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
+	Fx.Transitions[transition] = new Fx.Transition(function(p){
+		return Math.pow(p, [i + 2]);
+	});
+});
+
+
+/*
+Script: Request.js
+	Powerful all purpose Request Class. Uses XMLHTTPRequest.
+
+License:
+	MIT-style license.
+*/
+
+var Request = new Class({
+
+	Implements: [Chain, Events, Options],
+
+	options: {
+		/*onRequest: $empty,
+		onSuccess: $empty,
+		onFailure: $empty,
+		onException: $empty,*/
+		url: '',
+		data: '',
+		headers: {
+			'X-Requested-With': 'XMLHttpRequest',
+			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+		},
+		async: true,
+		format: false,
+		method: 'post',
+		link: 'ignore',
+		isSuccess: null,
+		emulation: true,
+		urlEncoded: true,
+		encoding: 'utf-8',
+		evalScripts: false,
+		evalResponse: false
+	},
+
+	initialize: function(options){
+		this.xhr = new Browser.Request();
+		this.setOptions(options);
+		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
+		this.headers = new Hash(this.options.headers);
+	},
+
+	onStateChange: function(){
+		if (this.xhr.readyState != 4 || !this.running) return;
+		this.running = false;
+		this.status = 0;
+		$try(function(){
+			this.status = this.xhr.status;
+		}.bind(this));
+		if (this.options.isSuccess.call(this, this.status)){
+			this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
+			this.success(this.response.text, this.response.xml);
+		} else {
+			this.response = {text: null, xml: null};
+			this.failure();
+		}
+		this.xhr.onreadystatechange = $empty;
+	},
+
+	isSuccess: function(){
+		return ((this.status >= 200) && (this.status < 300));
+	},
+
+	processScripts: function(text){
+		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
+		return text.stripScripts(this.options.evalScripts);
+	},
+
+	success: function(text, xml){
+		this.onSuccess(this.processScripts(text), xml);
+	},
+	
+	onSuccess: function(){
+		this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
+	},
+	
+	failure: function(){
+		this.onFailure();
+	},
+
+	onFailure: function(){
+		this.fireEvent('complete').fireEvent('failure', this.xhr);
+	},
+
+	setHeader: function(name, value){
+		this.headers.set(name, value);
+		return this;
+	},
+
+	getHeader: function(name){
+		return $try(function(){
+			return this.xhr.getResponseHeader(name);
+		}.bind(this));
+	},
+
+	check: function(caller){
+		if (!this.running) return true;
+		switch (this.options.link){
+			case 'cancel': this.cancel(); return true;
+			case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
+		}
+		return false;
+	},
+
+	send: function(options){
+		if (!this.check(arguments.callee, options)) return this;
+		this.running = true;
+
+		var type = $type(options);
+		if (type == 'string' || type == 'element') options = {data: options};
+
+		var old = this.options;
+		options = $extend({data: old.data, url: old.url, method: old.method}, options);
+		var data = options.data, url = options.url, method = options.method;
+
+		switch ($type(data)){
+			case 'element': data = $(data).toQueryString(); break;
+			case 'object': case 'hash': data = Hash.toQueryString(data);
+		}
+
+		if (this.options.format){
+			var format = 'format=' + this.options.format;
+			data = (data) ? format + '&' + data : format;
+		}
+
+		if (this.options.emulation && ['put', 'delete'].contains(method)){
+			var _method = '_method=' + method;
+			data = (data) ? _method + '&' + data : _method;
+			method = 'post';
+		}
+
+		if (this.options.urlEncoded && method == 'post'){
+			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
+			this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
+		}
+
+		if (data && method == 'get'){
+			url = url + (url.contains('?') ? '&' : '?') + data;
+			data = null;
+		}
+
+		this.xhr.open(method.toUpperCase(), url, this.options.async);
+
+		this.xhr.onreadystatechange = this.onStateChange.bind(this);
+
+		this.headers.each(function(value, key){
+			if (!$try(function(){
+				this.xhr.setRequestHeader(key, value);
+				return true;
+			}.bind(this))) this.fireEvent('exception', [key, value]);
+		}, this);
+
+		this.fireEvent('request');
+		this.xhr.send(data);
+		if (!this.options.async) this.onStateChange();
+		return this;
+	},
+
+	cancel: function(){
+		if (!this.running) return this;
+		this.running = false;
+		this.xhr.abort();
+		this.xhr.onreadystatechange = $empty;
+		this.xhr = new Browser.Request();
+		this.fireEvent('cancel');
+		return this;
+	}
+
+});
+
+(function(){
+
+var methods = {};
+['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
+	methods[method] = function(){
+		var params = Array.link(arguments, {url: String.type, data: $defined});
+		return this.send($extend(params, {method: method.toLowerCase()}));
+	};
+});
+
+Request.implement(methods);
+
+})();
+
+Element.Properties.send = {
+	
+	set: function(options){
+		var send = this.retrieve('send');
+		if (send) send.cancel();
+		return this.eliminate('send').store('send:options', $extend({
+			data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
+		}, options));
+	},
+
+	get: function(options){
+		if (options || !this.retrieve('send')){
+			if (options || !this.retrieve('send:options')) this.set('send', options);
+			this.store('send', new Request(this.retrieve('send:options')));
+		}
+		return this.retrieve('send');
+	}
+
+};
+
+Element.implement({
+
+	send: function(url){
+		var sender = this.get('send');
+		sender.send({data: this, url: url || sender.options.url});
+		return this;
+	}
+
+});
+
+
+/*
+Script: Request.HTML.js
+	Extends the basic Request Class with additional methods for interacting with HTML responses.
+
+License:
+	MIT-style license.
+*/
+
+Request.HTML = new Class({
+
+	Extends: Request,
+
+	options: {
+		update: false,
+		evalScripts: true,
+		filter: false
+	},
+
+	processHTML: function(text){
+		var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
+		text = (match) ? match[1] : text;
+		
+		var container = new Element('div');
+		
+		return $try(function(){
+			var root = '<root>' + text + '</root>', doc;
+			if (Browser.Engine.trident){
+				doc = new ActiveXObject('Microsoft.XMLDOM');
+				doc.async = false;
+				doc.loadXML(root);
+			} else {
+				doc = new DOMParser().parseFromString(root, 'text/xml');
+			}
+			root = doc.getElementsByTagName('root')[0];
+			for (var i = 0, k = root.childNodes.length; i < k; i++){
+				var child = Element.clone(root.childNodes[i], true, true);
+				if (child) container.grab(child);
+			}
+			return container;
+		}) || container.set('html', text);
+	},
+
+	success: function(text){
+		var options = this.options, response = this.response;
+		
+		response.html = text.stripScripts(function(script){
+			response.javascript = script;
+		});
+		
+		var temp = this.processHTML(response.html);
+		
+		response.tree = temp.childNodes;
+		response.elements = temp.getElements('*');
+		
+		if (options.filter) response.tree = response.elements.filter(options.filter);
+		if (options.update) $(options.update).empty().adopt(response.tree);
+		if (options.evalScripts) $exec(response.javascript);
+		
+		this.onSuccess(response.tree, response.elements, response.html, response.javascript);
+	}
+
+});
+
+Element.Properties.load = {
+	
+	set: function(options){
+		var load = this.retrieve('load');
+		if (load) send.cancel();
+		return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
+	},
+
+	get: function(options){
+		if (options || ! this.retrieve('load')){
+			if (options || !this.retrieve('load:options')) this.set('load', options);
+			this.store('load', new Request.HTML(this.retrieve('load:options')));
+		}
+		return this.retrieve('load');
+	}
+
+};
+
+Element.implement({
+	
+	load: function(){
+		this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
+		return this;
+	}
+
+});
+
+
+/*
+Script: Request.JSON.js
+	Extends the basic Request Class with additional methods for sending and receiving JSON data.
+
+License:
+	MIT-style license.
+*/
+
+Request.JSON = new Class({
+
+	Extends: Request,
+
+	options: {
+		secure: true
+	},
+
+	initialize: function(options){
+		this.parent(options);
+		this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
+	},
+
+	success: function(text){
+		this.response.json = JSON.decode(text, this.options.secure);
+		this.onSuccess(this.response.json, text);
+	}
+
+});//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
+
+/*
+Script: Fx.Slide.js
+	Effect to slide an element in and out of view.
+
+License:
+	MIT-style license.
+*/
+
+Fx.Slide = new Class({
+
+	Extends: Fx,
+
+	options: {
+		mode: 'vertical'
+	},
+
+	initialize: function(element, options){
+		this.addEvent('complete', function(){
+			this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0);
+			if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper);
+		}, true);
+		this.element = this.subject = $(element);
+		this.parent(options);
+		var wrapper = this.element.retrieve('wrapper');
+		this.wrapper = wrapper || new Element('div', {
+			styles: $extend(this.element.getStyles('margin', 'position'), {'overflow': 'hidden'})
+		}).wraps(this.element);
+		this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
+		this.now = [];
+		this.open = true;
+	},
+
+	vertical: function(){
+		this.margin = 'margin-top';
+		this.layout = 'height';
+		this.offset = this.element.offsetHeight;
+	},
+
+	horizontal: function(){
+		this.margin = 'margin-left';
+		this.layout = 'width';
+		this.offset = this.element.offsetWidth;
+	},
+
+	set: function(now){
+		this.element.setStyle(this.margin, now[0]);
+		this.wrapper.setStyle(this.layout, now[1]);
+		return this;
+	},
+
+	compute: function(from, to, delta){
+		var now = [];
+		var x = 2;
+		x.times(function(i){
+			now[i] = Fx.compute(from[i], to[i], delta);
+		});
+		return now;
+	},
+
+	start: function(how, mode){
+		if (!this.check(arguments.callee, how, mode)) return this;
+		this[mode || this.options.mode]();
+		var margin = this.element.getStyle(this.margin).toInt();
+		var layout = this.wrapper.getStyle(this.layout).toInt();
+		var caseIn = [[margin, layout], [0, this.offset]];
+		var caseOut = [[margin, layout], [-this.offset, 0]];
+		var start;
+		switch (how){
+			case 'in': start = caseIn; break;
+			case 'out': start = caseOut; break;
+			case 'toggle': start = (this.wrapper['offset' + this.layout.capitalize()] == 0) ? caseIn : caseOut;
+		}
+		return this.parent(start[0], start[1]);
+	},
+
+	slideIn: function(mode){
+		return this.start('in', mode);
+	},
+
+	slideOut: function(mode){
+		return this.start('out', mode);
+	},
+
+	hide: function(mode){
+		this[mode || this.options.mode]();
+		this.open = false;
+		return this.set([-this.offset, 0]);
+	},
+
+	show: function(mode){
+		this[mode || this.options.mode]();
+		this.open = true;
+		return this.set([0, this.offset]);
+	},
+
+	toggle: function(mode){
+		return this.start('toggle', mode);
+	}
+
+});
+
+Element.Properties.slide = {
+
+	set: function(options){
+		var slide = this.retrieve('slide');
+		if (slide) slide.cancel();
+		return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options));
+	},
+	
+	get: function(options){
+		if (options || !this.retrieve('slide')){
+			if (options || !this.retrieve('slide:options')) this.set('slide', options);
+			this.store('slide', new Fx.Slide(this, this.retrieve('slide:options')));
+		}
+		return this.retrieve('slide');
+	}
+
+};
+
+Element.implement({
+
+	slide: function(how, mode){
+		how = how || 'toggle';
+		var slide = this.get('slide'), toggle;
+		switch (how){
+			case 'hide': slide.hide(mode); break;
+			case 'show': slide.show(mode); break;
+			case 'toggle':
+				var flag = this.retrieve('slide:flag', slide.open);
+				slide[(flag) ? 'slideOut' : 'slideIn'](mode);
+				this.store('slide:flag', !flag);
+				toggle = true;
+			break;
+			default: slide.start(how, mode);
+		}
+		if (!toggle) this.eliminate('slide:flag');
+		return this;
+	}
+
+});
+
+
+/*
+Script: Fx.Scroll.js
+	Effect to smoothly scroll any element, including the window.
+
+License:
+	MIT-style license.
+*/
+
+Fx.Scroll = new Class({
+
+	Extends: Fx,
+
+	options: {
+		offset: {'x': 0, 'y': 0},
+		wheelStops: true
+	},
+
+	initialize: function(element, options){
+		this.element = this.subject = $(element);
+		this.parent(options);
+		var cancel = this.cancel.bind(this, false);
+
+		if ($type(this.element) != 'element') this.element = $(this.element.getDocument().body);
+
+		var stopper = this.element;
+
+		if (this.options.wheelStops){
+			this.addEvent('start', function(){
+				stopper.addEvent('mousewheel', cancel);
+			}, true);
+			this.addEvent('complete', function(){
+				stopper.removeEvent('mousewheel', cancel);
+			}, true);
+		}
+	},
+
+	set: function(){
+		var now = Array.flatten(arguments);
+		this.element.scrollTo(now[0], now[1]);
+	},
+
+	compute: function(from, to, delta){
+		var now = [];
+		var x = 2;
+		x.times(function(i){
+			now.push(Fx.compute(from[i], to[i], delta));
+		});
+		return now;
+	},
+
+	start: function(x, y){
+		if (!this.check(arguments.callee, x, y)) return this;
+		var offsetSize = this.element.getSize(), scrollSize = this.element.getScrollSize();
+		var scroll = this.element.getScroll(), values = {x: x, y: y};
+		for (var z in values){
+			var max = scrollSize[z] - offsetSize[z];
+			if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
+			else values[z] = scroll[z];
+			values[z] += this.options.offset[z];
+		}
+		return this.parent([scroll.x, scroll.y], [values.x, values.y]);
+	},
+
+	toTop: function(){
+		return this.start(false, 0);
+	},
+
+	toLeft: function(){
+		return this.start(0, false);
+	},
+
+	toRight: function(){
+		return this.start('right', false);
+	},
+
+	toBottom: function(){
+		return this.start(false, 'bottom');
+	},
+
+	toElement: function(el){
+		var position = $(el).getPosition(this.element);
+		return this.start(position.x, position.y);
+	}
+
+});
+
+
+/*
+Script: Fx.Elements.js
+	Effect to change any number of CSS properties of any number of Elements.
+
+License:
+	MIT-style license.
+*/
+
+Fx.Elements = new Class({
+
+	Extends: Fx.CSS,
+
+	initialize: function(elements, options){
+		this.elements = this.subject = $$(elements);
+		this.parent(options);
+	},
+
+	compute: function(from, to, delta){
+		var now = {};
+		for (var i in from){
+			var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
+			for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
+		}
+		return now;
+	},
+
+	set: function(now){
+		for (var i in now){
+			var iNow = now[i];
+			for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
+		}
+		return this;
+	},
+
+	start: function(obj){
+		if (!this.check(arguments.callee, obj)) return this;
+		var from = {}, to = {};
+		for (var i in obj){
+			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
+			for (var p in iProps){
+				var parsed = this.prepare(this.elements[i], p, iProps[p]);
+				iFrom[p] = parsed.from;
+				iTo[p] = parsed.to;
+			}
+		}
+		return this.parent(from, to);
+	}
+
+});
+
+/*
+Script: Drag.js
+	The base Drag Class. Can be used to drag and resize Elements using mouse events.
+
+License:
+	MIT-style license.
+*/
+
+var Drag = new Class({
+
+	Implements: [Events, Options],
+
+	options: {/*
+		onBeforeStart: $empty,
+		onStart: $empty,
+		onDrag: $empty,
+		onCancel: $empty,
+		onComplete: $empty,*/
+		snap: 6,
+		unit: 'px',
+		grid: false,
+		style: true,
+		limit: false,
+		handle: false,
+		invert: false,
+		preventDefault: false,
+		modifiers: {x: 'left', y: 'top'}
+	},
+
+	initialize: function(){
+		var params = Array.link(arguments, {'options': Object.type, 'element': $defined});
+		this.element = $(params.element);
+		this.document = this.element.getDocument();
+		this.setOptions(params.options || {});
+		var htype = $type(this.options.handle);
+		this.handles = (htype == 'array' || htype == 'collection') ? $$(this.options.handle) : $(this.options.handle) || this.element;
+		this.mouse = {'now': {}, 'pos': {}};
+		this.value = {'start': {}, 'now': {}};
+		
+		this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown';
+		
+		this.bound = {
+			start: this.start.bind(this),
+			check: this.check.bind(this),
+			drag: this.drag.bind(this),
+			stop: this.stop.bind(this),
+			cancel: this.cancel.bind(this),
+			eventStop: $lambda(false)
+		};
+		this.attach();
+	},
+
+	attach: function(){
+		this.handles.addEvent('mousedown', this.bound.start);
+		return this;
+	},
+
+	detach: function(){
+		this.handles.removeEvent('mousedown', this.bound.start);
+		return this;
+	},
+
+	start: function(event){
+		if (this.options.preventDefault) event.preventDefault();
+		this.fireEvent('beforeStart', this.element);
+		this.mouse.start = event.page;
+		var limit = this.options.limit;
+		this.limit = {'x': [], 'y': []};
+		for (var z in this.options.modifiers){
+			if (!this.options.modifiers[z]) continue;
+			if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
+			else this.value.now[z] = this.element[this.options.modifiers[z]];
+			if (this.options.invert) this.value.now[z] *= -1;
+			this.mouse.pos[z] = event.page[z] - this.value.now[z];
+			if (limit && limit[z]){
+				for (var i = 2; i--; i){
+					if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
+				}
+			}
+		}
+		if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid};
+		this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
+		this.document.addEvent(this.selection, this.bound.eventStop);
+	},
+
+	check: function(event){
+		if (this.options.preventDefault) event.preventDefault();
+		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
+		if (distance > this.options.snap){
+			this.cancel();
+			this.document.addEvents({
+				mousemove: this.bound.drag,
+				mouseup: this.bound.stop
+			});
+			this.fireEvent('start', this.element).fireEvent('snap', this.element);
+		}
+	},
+
+	drag: function(event){
+		if (this.options.preventDefault) event.preventDefault();
+		this.mouse.now = event.page;
+		for (var z in this.options.modifiers){
+			if (!this.options.modifiers[z]) continue;
+			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
+			if (this.options.invert) this.value.now[z] *= -1;
+			if (this.options.limit && this.limit[z]){
+				if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
+					this.value.now[z] = this.limit[z][1];
+				} else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
+					this.value.now[z] = this.limit[z][0];
+				}
+			}
+			if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]);
+			if (this.options.style) this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
+			else this.element[this.options.modifiers[z]] = this.value.now[z];
+		}
+		this.fireEvent('drag', this.element);
+	},
+
+	cancel: function(event){
+		this.document.removeEvent('mousemove', this.bound.check);
+		this.document.removeEvent('mouseup', this.bound.cancel);
+		if (event){
+			this.document.removeEvent(this.selection, this.bound.eventStop);
+			this.fireEvent('cancel', this.element);
+		}
+	},
+
+	stop: function(event){
+		this.document.removeEvent(this.selection, this.bound.eventStop);
+		this.document.removeEvent('mousemove', this.bound.drag);
+		this.document.removeEvent('mouseup', this.bound.stop);
+		if (event) this.fireEvent('complete', this.element);
+	}
+
+});
+
+Element.implement({
+	
+	makeResizable: function(options){
+		return new Drag(this, $merge({modifiers: {'x': 'width', 'y': 'height'}}, options));
+	}
+
+});
+
+/*
+Script: Drag.Move.js
+	A Drag extension that provides support for the constraining of draggables to containers and droppables.
+
+License:
+	MIT-style license.
+*/
+
+Drag.Move = new Class({
+
+	Extends: Drag,
+
+	options: {
+		droppables: [],
+		container: false
+	},
+
+	initialize: function(element, options){
+		this.parent(element, options);
+		this.droppables = $$(this.options.droppables);
+		this.container = $(this.options.container);
+		if (this.container && $type(this.container) != 'element') this.container = $(this.container.getDocument().body);
+		element = this.element;
+		
+		var current = element.getStyle('position');
+		var position = (current != 'static') ? current : 'absolute';
+		if (element.getStyle('left') == 'auto' || element.getStyle('top') == 'auto') element.position(element.getPosition(element.offsetParent));
+		
+		element.setStyle('position', position);
+		
+		this.addEvent('start', function(){
+			this.checkDroppables();
+		}, true);
+	},
+
+	start: function(event){
+		if (this.container){
+			var el = this.element, cont = this.container, ccoo = cont.getCoordinates(el.offsetParent), cps = {}, ems = {};
+
+			['top', 'right', 'bottom', 'left'].each(function(pad){
+				cps[pad] = cont.getStyle('padding-' + pad).toInt();
+				ems[pad] = el.getStyle('margin-' + pad).toInt();
+			}, this);
+
+			var width = el.offsetWidth + ems.left + ems.right, height = el.offsetHeight + ems.top + ems.bottom;
+			var x = [ccoo.left + cps.left, ccoo.right - cps.right - width];
+			var y = [ccoo.top + cps.top, ccoo.bottom - cps.bottom - height];
+
+			this.options.limit = {x: x, y: y};
+		}
+		this.parent(event);
+	},
+
+	checkAgainst: function(el){
+		el = el.getCoordinates();
+		var now = this.mouse.now;
+		return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
+	},
+
+	checkDroppables: function(){
+		var overed = this.droppables.filter(this.checkAgainst, this).getLast();
+		if (this.overed != overed){
+			if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
+			if (overed){
+				this.overed = overed;
+				this.fireEvent('enter', [this.element, overed]);
+			} else {
+				this.overed = null;
+			}
+		}
+	},
+
+	drag: function(event){
+		this.parent(event);
+		if (this.droppables.length) this.checkDroppables();
+	},
+
+	stop: function(event){
+		this.checkDroppables();
+		this.fireEvent('drop', [this.element, this.overed]);
+		this.overed = null;
+		return this.parent(event);
+	}
+
+});
+
+Element.implement({
+
+	makeDraggable: function(options){
+		return new Drag.Move(this, options);
+	}
+
+});
+
+
+/*
+Script: Hash.Cookie.js
+	Class for creating, reading, and deleting Cookies in JSON format.
+
+License:
+	MIT-style license.
+*/
+
+Hash.Cookie = new Class({
+
+	Extends: Cookie,
+
+	options: {
+		autoSave: true
+	},
+
+	initialize: function(name, options){
+		this.parent(name, options);
+		this.load();
+	},
+
+	save: function(){
+		var value = JSON.encode(this.hash);
+		if (!value || value.length > 4096) return false; //cookie would be truncated!
+		if (value == '{}') this.dispose();
+		else this.write(value);
+		return true;
+	},
+
+	load: function(){
+		this.hash = new Hash(JSON.decode(this.read(), true));
+		return this;
+	}
+
+});
+
+Hash.Cookie.implement((function(){
+	
+	var methods = {};
+	
+	Hash.each(Hash.prototype, function(method, name){
+		methods[name] = function(){
+			var value = method.apply(this.hash, arguments);
+			if (this.options.autoSave) this.save();
+			return value;
+		};
+	});
+	
+	return methods;
+	
+})());
+
+/*
+Script: Color.js
+	Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
+
+License:
+	MIT-style license.
+*/
+
+var Color = new Native({
+  
+	initialize: function(color, type){
+		if (arguments.length >= 3){
+			type = "rgb"; color = Array.slice(arguments, 0, 3);
+		} else if (typeof color == 'string'){
+			if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
+			else if (color.match(/hsb/)) color = color.hsbToRgb();
+			else color = color.hexToRgb(true);
+		}
+		type = type || 'rgb';
+		switch (type){
+			case 'hsb':
+				var old = color;
+				color = color.hsbToRgb();
+				color.hsb = old;
+			break;
+			case 'hex': color = color.hexToRgb(true); break;
+		}
+		color.rgb = color.slice(0, 3);
+		color.hsb = color.hsb || color.rgbToHsb();
+		color.hex = color.rgbToHex();
+		return $extend(color, this);
+	}
+
+});
+
+Color.implement({
+
+	mix: function(){
+		var colors = Array.slice(arguments);
+		var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50;
+		var rgb = this.slice();
+		colors.each(function(color){
+			color = new Color(color);
+			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
+		});
+		return new Color(rgb, 'rgb');
+	},
+
+	invert: function(){
+		return new Color(this.map(function(value){
+			return 255 - value;
+		}));
+	},
+
+	setHue: function(value){
+		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
+	},
+
+	setSaturation: function(percent){
+		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
+	},
+
+	setBrightness: function(percent){
+		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
+	}
+
+});
+
+function $RGB(r, g, b){
+	return new Color([r, g, b], 'rgb');
+};
+
+function $HSB(h, s, b){
+	return new Color([h, s, b], 'hsb');
+};
+
+function $HEX(hex){
+	return new Color(hex, 'hex');
+};
+
+Array.implement({
+
+	rgbToHsb: function(){
+		var red = this[0], green = this[1], blue = this[2];
+		var hue, saturation, brightness;
+		var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
+		var delta = max - min;
+		brightness = max / 255;
+		saturation = (max != 0) ? delta / max : 0;
+		if (saturation == 0){
+			hue = 0;
+		} else {
+			var rr = (max - red) / delta;
+			var gr = (max - green) / delta;
+			var br = (max - blue) / delta;
+			if (red == max) hue = br - gr;
+			else if (green == max) hue = 2 + rr - br;
+			else hue = 4 + gr - rr;
+			hue /= 6;
+			if (hue < 0) hue++;
+		}
+		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
+	},
+
+	hsbToRgb: function(){
+		var br = Math.round(this[2] / 100 * 255);
+		if (this[1] == 0){
+			return [br, br, br];
+		} else {
+			var hue = this[0] % 360;
+			var f = hue % 60;
+			var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
+			var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
+			var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
+			switch (Math.floor(hue / 60)){
+				case 0: return [br, t, p];
+				case 1: return [q, br, p];
+				case 2: return [p, br, t];
+				case 3: return [p, q, br];
+				case 4: return [t, p, br];
+				case 5: return [br, p, q];
+			}
+		}
+		return false;
+	}
+
+});
+
+String.implement({
+
+	rgbToHsb: function(){
+		var rgb = this.match(/\d{1,3}/g);
+		return (rgb) ? hsb.rgbToHsb() : null;
+	},
+	
+	hsbToRgb: function(){
+		var hsb = this.match(/\d{1,3}/g);
+		return (hsb) ? hsb.hsbToRgb() : null;
+	}
+
+});
+
+
+/*
+Script: Group.js
+	Class for monitoring collections of events
+
+License:
+	MIT-style license.
+*/
+
+var Group = new Class({
+
+	initialize: function(){
+		this.instances = Array.flatten(arguments);
+		this.events = {};
+		this.checker = {};
+	},
+
+	addEvent: function(type, fn){
+		this.checker[type] = this.checker[type] || {};
+		this.events[type] = this.events[type] || [];
+		if (this.events[type].contains(fn)) return false;
+		else this.events[type].push(fn);
+		this.instances.each(function(instance, i){
+			instance.addEvent(type, this.check.bind(this, [type, instance, i]));
+		}, this);
+		return this;
+	},
+
+	check: function(type, instance, i){
+		this.checker[type][i] = true;
+		var every = this.instances.every(function(current, j){
+			return this.checker[type][j] || false;
+		}, this);
+		if (!every) return;
+		this.checker[type] = {};
+		this.events[type].each(function(event){
+			event.call(this, this.instances, instance);
+		}, this);
+	}
+
+});
+
+
+/*
+Script: Assets.js
+	Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
+
+License:
+	MIT-style license.
+*/
+
+var Asset = new Hash({
+
+	javascript: function(source, properties){
+		properties = $extend({
+			onload: $empty,
+			document: document,
+			check: $lambda(true)
+		}, properties);
+		
+		var script = new Element('script', {'src': source, 'type': 'text/javascript'});
+		
+		var load = properties.onload.bind(script), check = properties.check, doc = properties.document;
+		delete properties.onload; delete properties.check; delete properties.document;
+		
+		script.addEvents({
+			load: load,
+			readystatechange: function(){
+				if (['loaded', 'complete'].contains(this.readyState)) load();
+			}
+		}).setProperties(properties);
+		
+		
+		if (Browser.Engine.webkit419) var checker = (function(){
+			if (!$try(check)) return;
+			$clear(checker);
+			load();
+		}).periodical(50);
+		
+		return script.inject(doc.head);
+	},
+
+	css: function(source, properties){
+		return new Element('link', $merge({
+			'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source
+		}, properties)).inject(document.head);
+	},
+
+	image: function(source, properties){
+		properties = $merge({
+			'onload': $empty,
+			'onabort': $empty,
+			'onerror': $empty
+		}, properties);
+		var image = new Image();
+		var element = $(image) || new Element('img');
+		['load', 'abort', 'error'].each(function(name){
+			var type = 'on' + name;
+			var event = properties[type];
+			delete properties[type];
+			image[type] = function(){
+				if (!image) return;
+				if (!element.parentNode){
+					element.width = image.width;
+					element.height = image.height;
+				}
+				image = image.onload = image.onabort = image.onerror = null;
+				event.delay(1, element, element);
+				element.fireEvent(name, element, 1);
+			};
+		});
+		image.src = element.src = source;
+		if (image && image.complete) image.onload.delay(1);
+		return element.setProperties(properties);
+	},
+
+	images: function(sources, options){
+		options = $merge({
+			onComplete: $empty,
+			onProgress: $empty
+		}, options);
+		if (!sources.push) sources = [sources];
+		var images = [];
+		var counter = 0;
+		sources.each(function(source){
+			var img = new Asset.image(source, {
+				'onload': function(){
+					options.onProgress.call(this, counter, sources.indexOf(source));
+					counter++;
+					if (counter == sources.length) options.onComplete();
+				}
+			});
+			images.push(img);
+		});
+		return new Elements(images);
+	}
+
+});
+
+/*
+Script: Sortables.js
+	Class for creating a drag and drop sorting interface for lists of items.
+
+License:
+	MIT-style license.
+*/
+
+var Sortables = new Class({
+
+	Implements: [Events, Options],
+
+	options: {/*
+		onSort: $empty,
+		onStart: $empty,
+		onComplete: $empty,*/
+		snap: 4,
+		opacity: 1,
+		clone: false,
+		revert: false,
+		handle: false,
+		constrain: false
+	},
+
+	initialize: function(lists, options){
+		this.setOptions(options);
+		this.elements = [];
+		this.lists = [];
+		this.idle = true;
+		
+		this.addLists($$($(lists) || lists));
+		if (!this.options.clone) this.options.revert = false;
+		if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert));
+	},
+
+	attach: function(){
+		this.addLists(this.lists);
+		return this;
+	},
+
+	detach: function(){
+		this.lists = this.removeLists(this.lists);
+		return this;
+	},
+
+	addItems: function(){
+		Array.flatten(arguments).each(function(element){
+			this.elements.push(element);
+			var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element));
+			(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
+		}, this);
+		return this;
+	},
+
+	addLists: function(){
+		Array.flatten(arguments).each(function(list){
+			this.lists.push(list);
+			this.addItems(list.getChildren());
+		}, this);
+		return this;
+	},
+
+	removeItems: function(){
+		var elements = [];
+		Array.flatten(arguments).each(function(element){
+			elements.push(element);
+			this.elements.erase(element);
+			var start = element.retrieve('sortables:start');
+			(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
+		}, this);
+		return $$(elements);
+	},
+
+	removeLists: function(){
+		var lists = [];
+		Array.flatten(arguments).each(function(list){
+			lists.push(list);
+			this.lists.erase(list);
+			this.removeItems(list.getChildren());
+		}, this);
+		return $$(lists);
+	},
+
+	getClone: function(event, element){
+		if (!this.options.clone) return new Element('div').inject(document.body);
+		if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
+		return element.clone(true).setStyles({
+			'margin': '0px',
+			'position': 'absolute',
+			'visibility': 'hidden',
+			'width': element.getStyle('width')
+		}).inject(this.list).position(element.getPosition(element.getOffsetParent()));
+	},
+
+	getDroppables: function(){
+		var droppables = this.list.getChildren();
+		if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list);
+		return droppables.erase(this.clone).erase(this.element);
+	},
+
+	insert: function(dragging, element){
+		var where = 'inside';
+		if (this.lists.contains(element)){
+			this.list = element;
+			this.drag.droppables = this.getDroppables();
+		} else {
+			where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
+		}
+		this.element.inject(element, where);
+		this.fireEvent('sort', [this.element, this.clone]);
+	},
+
+	start: function(event, element){
+		if (!this.idle) return;
+		this.idle = false;
+		this.element = element;
+		this.opacity = element.get('opacity');
+		this.list = element.getParent();
+		this.clone = this.getClone(event, element);
+		
+		this.drag = new Drag.Move(this.clone, {
+			snap: this.options.snap,
+			container: this.options.constrain && this.element.getParent(),
+			droppables: this.getDroppables(),
+			onSnap: function(){
+				event.stop();
+				this.clone.setStyle('visibility', 'visible');
+				this.element.set('opacity', this.options.opacity || 0);
+				this.fireEvent('start', [this.element, this.clone]);
+			}.bind(this),
+			onEnter: this.insert.bind(this),
+			onCancel: this.reset.bind(this),
+			onComplete: this.end.bind(this)
+		});
+		
+		this.clone.inject(this.element, 'before');
+		this.drag.start(event);
+	},
+
+	end: function(){
+		this.drag.detach();
+		this.element.set('opacity', this.opacity);
+		if (this.effect){
+			var dim = this.element.getStyles('width', 'height');
+			var pos = this.clone.computePosition(this.element.getPosition(this.clone.offsetParent));
+			this.effect.element = this.clone;
+			this.effect.start({
+				top: pos.top,
+				left: pos.left,
+				width: dim.width,
+				height: dim.height,
+				opacity: 0.25
+			}).chain(this.reset.bind(this));
+		} else {
+			this.reset();
+		}
+	},
+
+	reset: function(){
+		this.idle = true;
+		this.clone.destroy();
+		this.fireEvent('complete', this.element);
+	},
+
+	serialize: function(){
+		var params = Array.link(arguments, {modifier: Function.type, index: $defined});
+		var serial = this.lists.map(function(list){
+			return list.getChildren().map(params.modifier || function(element){
+				return element.get('id');
+			}, this);
+		}, this);
+		
+		var index = params.index;
+		if (this.lists.length == 1) index = 0;
+		return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial;
+	}
+
+});
+
+/*
+Script: Tips.js
+	Class for creating nice tips that follow the mouse cursor when hovering an element.
+
+License:
+	MIT-style license.
+*/
+
+var Tips = new Class({
+
+	Implements: [Events, Options],
+
+	options: {
+		onShow: function(tip){
+			tip.setStyle('visibility', 'visible');
+		},
+		onHide: function(tip){
+			tip.setStyle('visibility', 'hidden');
+		},
+		showDelay: 100,
+		hideDelay: 100,
+		className: null,
+		offsets: {x: 16, y: 16},
+		fixed: false
+	},
+
+	initialize: function(){
+		var params = Array.link(arguments, {options: Object.type, elements: $defined});
+		this.setOptions(params.options || null);
+		
+		this.tip = new Element('div').inject(document.body);
+		
+		if (this.options.className) this.tip.addClass(this.options.className);
+		
+		var top = new Element('div', {'class': 'tip-top'}).inject(this.tip);
+		this.container = new Element('div', {'class': 'tip'}).inject(this.tip);
+		var bottom = new Element('div', {'class': 'tip-bottom'}).inject(this.tip);
+
+		this.tip.setStyles({position: 'absolute', top: 0, left: 0, visibility: 'hidden'});
+		
+		if (params.elements) this.attach(params.elements);
+	},
+	
+	attach: function(elements){
+		$$(elements).each(function(element){
+			var title = element.retrieve('tip:title', element.get('title'));
+			var text = element.retrieve('tip:text', element.get('rel') || element.get('href'));
+			var enter = element.retrieve('tip:enter', this.elementEnter.bindWithEvent(this, element));
+			var leave = element.retrieve('tip:leave', this.elementLeave.bindWithEvent(this, element));
+			element.addEvents({mouseenter: enter, mouseleave: leave});
+			if (!this.options.fixed){
+				var move = element.retrieve('tip:move', this.elementMove.bindWithEvent(this, element));
+				element.addEvent('mousemove', move);
+			}
+			element.store('tip:native', element.get('title'));
+			element.erase('title');
+		}, this);
+		return this;
+	},
+	
+	detach: function(elements){
+		$$(elements).each(function(element){
+			element.removeEvent('mouseenter', element.retrieve('tip:enter') || $empty);
+			element.removeEvent('mouseleave', element.retrieve('tip:leave') || $empty);
+			element.removeEvent('mousemove', element.retrieve('tip:move') || $empty);
+			element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
+			var original = element.retrieve('tip:native');
+			if (original) element.set('title', original);
+		});
+		return this;
+	},
+	
+	elementEnter: function(event, element){
+		
+		$A(this.container.childNodes).each(Element.dispose);
+		
+		var title = element.retrieve('tip:title');
+		
+		if (title){
+			this.titleElement = new Element('div', {'class': 'tip-title'}).inject(this.container);
+			this.fill(this.titleElement, title);
+		}
+		
+		var text = element.retrieve('tip:text');
+		if (text){
+			this.textElement = new Element('div', {'class': 'tip-text'}).inject(this.container);
+			this.fill(this.textElement, text);
+		}
+		
+		this.timer = $clear(this.timer);
+		this.timer = this.show.delay(this.options.showDelay, this);
+
+		this.position((!this.options.fixed) ? event : {page: element.getPosition()});
+	},
+	
+	elementLeave: function(event){
+		$clear(this.timer);
+		this.timer = this.hide.delay(this.options.hideDelay, this);
+	},
+	
+	elementMove: function(event){
+		this.position(event);
+	},
+	
+	position: function(event){
+		var size = window.getSize(), scroll = window.getScroll();
+		var tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight};
+		var props = {x: 'left', y: 'top'};
+		for (var z in props){
+			var pos = event.page[z] + this.options.offsets[z];
+			if ((pos + tip[z] - scroll[z]) > size[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
+			this.tip.setStyle(props[z], pos);
+		}
+	},
+	
+	fill: function(element, contents){
+		(typeof contents == 'string') ? element.set('html', contents) : element.adopt(contents);
+	},
+
+	show: function(){
+		this.fireEvent('show', this.tip);
+	},
+
+	hide: function(){
+		this.fireEvent('hide', this.tip);
+	}
+
+});
+
+/*
+Script: SmoothScroll.js
+	Class for creating a smooth scrolling effect to all internal links on the page.
+
+License:
+	MIT-style license.
+*/
+
+var SmoothScroll = new Class({
+
+	Extends: Fx.Scroll,
+
+	initialize: function(options, context){
+		context = context || document;
+		var doc = context.getDocument(), win = context.getWindow();
+		this.parent(doc, options);
+		this.links = (this.options.links) ? $$(this.options.links) : $$(doc.links);
+		var location = win.location.href.match(/^[^#]*/)[0] + '#';
+		this.links.each(function(link){
+			if (link.href.indexOf(location) != 0) return;
+			var anchor = link.href.substr(location.length);
+			if (anchor && $(anchor)) this.useLink(link, anchor);
+		}, this);
+		if (!Browser.Engine.webkit419) this.addEvent('complete', function(){
+			win.location.hash = this.anchor;
+		}, true);
+	},
+
+	useLink: function(link, anchor){
+		link.addEvent('click', function(event){
+			this.anchor = anchor;
+			this.toElement(anchor);
+			event.stop();
+		}.bind(this));
+	}
+
+});
+
+/*
+Script: Slider.js
+	Class for creating horizontal and vertical slider controls.
+
+License:
+	MIT-style license.
+*/
+
+var Slider = new Class({
+
+	Implements: [Events, Options],
+
+	options: {/*
+		onChange: $empty,
+		onComplete: $empty,*/
+		onTick: function(position){
+			if(this.options.snap) position = this.toPosition(this.step);
+			this.knob.setStyle(this.property, position);
+		},
+		snap: false,
+		offset: 0,
+		range: false,
+		wheel: false,
+		steps: 100,
+		mode: 'horizontal'
+	},
+
+	initialize: function(element, knob, options){
+		this.setOptions(options);
+		this.element = $(element);
+		this.knob = $(knob);
+		this.previousChange = this.previousEnd = this.step = -1;
+		this.element.addEvent('mousedown', this.clickedElement.bind(this));
+		if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement.bindWithEvent(this));
+		var offset, limit = {}, modifiers = {'x': false, 'y': false};
+		switch (this.options.mode){
+			case 'vertical':
+				this.axis = 'y';
+				this.property = 'top';
+				offset = 'offsetHeight';
+				break;
+			case 'horizontal':
+				this.axis = 'x';
+				this.property = 'left';
+				offset = 'offsetWidth';
+		}
+		this.half = this.knob[offset] / 2;
+		this.full = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
+		this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
+		this.max = $chk(this.options.range[1]) ? this.options.range[1] : this.options.steps;
+		this.range = this.max - this.min;
+		this.steps = this.options.steps || this.full;
+		this.stepSize = Math.abs(this.range) / this.steps;
+		this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;
+		
+		this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset);
+		modifiers[this.axis] = this.property;
+		limit[this.axis] = [- this.options.offset, this.full - this.options.offset];
+		this.drag = new Drag(this.knob, {
+			snap: 0,
+			limit: limit,
+			modifiers: modifiers,
+			onDrag: this.draggedKnob.bind(this),
+			onStart: this.draggedKnob.bind(this),
+			onComplete: function(){
+				this.draggedKnob();
+				this.end();
+			}.bind(this)
+		});
+		if (this.options.snap) {
+			this.drag.options.grid = Math.ceil(this.stepWidth);
+			this.drag.options.limit[this.axis][1] = this.full;
+		}
+	},
+
+	set: function(step){
+		if (!((this.range > 0) ^ (step < this.min))) step = this.min;
+		if (!((this.range > 0) ^ (step > this.max))) step = this.max;
+		
+		this.step = Math.round(step);
+		this.checkStep();
+		this.end();
+		this.fireEvent('tick', this.toPosition(this.step));
+		return this;
+	},
+
+	clickedElement: function(event){
+		var dir = this.range < 0 ? -1 : 1;
+		var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
+		position = position.limit(-this.options.offset, this.full -this.options.offset);
+		
+		this.step = Math.round(this.min + dir * this.toStep(position));
+		this.checkStep();
+		this.end();
+		this.fireEvent('tick', position);
+	},
+	
+	scrolledElement: function(event){
+		var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
+		this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
+		event.stop();
+	},
+
+	draggedKnob: function(){
+		var dir = this.range < 0 ? -1 : 1;
+		var position = this.drag.value.now[this.axis];
+		position = position.limit(-this.options.offset, this.full -this.options.offset);
+		this.step = Math.round(this.min + dir * this.toStep(position));
+		this.checkStep();
+	},
+
+	checkStep: function(){
+		if (this.previousChange != this.step){
+			this.previousChange = this.step;
+			this.fireEvent('change', this.step);
+		}
+	},
+
+	end: function(){
+		if (this.previousEnd !== this.step){
+			this.previousEnd = this.step;
+			this.fireEvent('complete', this.step + '');
+		}
+	},
+
+	toStep: function(position){
+		var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
+		return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
+	},
+
+	toPosition: function(step){
+		return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
+	}
+
+});
+
+/*
+Script: Scroller.js
+	Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries.
+
+License:
+	MIT-style license.
+*/
+
+var Scroller = new Class({
+
+	Implements: [Events, Options],
+
+	options: {
+		area: 20,
+		velocity: 1,
+		onChange: function(x, y){
+			this.element.scrollTo(x, y);
+		}
+	},
+
+	initialize: function(element, options){
+		this.setOptions(options);
+		this.element = $(element);
+		this.listener = ($type(this.element) != 'element') ? $(this.element.getDocument().body) : this.element;
+		this.timer = null;
+		this.coord = this.getCoords.bind(this);
+	},
+
+	start: function(){
+		this.listener.addEvent('mousemove', this.coord);
+	},
+
+	stop: function(){
+		this.listener.removeEvent('mousemove', this.coord);
+		this.timer = $clear(this.timer);
+	},
+
+	getCoords: function(event){
+		this.page = (this.listener.get('tag') == 'body') ? event.client : event.page;
+		if (!this.timer) this.timer = this.scroll.periodical(50, this);
+	},
+
+	scroll: function(){
+		var size = this.element.getSize(), scroll = this.element.getScroll(), pos = this.element.getPosition(), change = {'x': 0, 'y': 0};
+		for (var z in this.page){
+			if (this.page[z] < (this.options.area + pos[z]) && scroll[z] != 0)
+				change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
+			else if (this.page[z] + this.options.area > (size[z] + pos[z]) && size[z] + size[z] != scroll[z])
+				change[z] = (this.page[z] - size[z] + this.options.area - pos[z]) * this.options.velocity;
+		}
+		if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]);
+	}
+
+});
+
+/*
+Script: Accordion.js
+	An Fx.Elements extension which allows you to easily create accordion type controls.
+
+License:
+	MIT-style license.
+*/
+
+var Accordion = new Class({
+
+	Extends: Fx.Elements,
+
+	options: {/*
+		onActive: $empty,
+		onBackground: $empty,*/
+		display: 0,
+		show: false,
+		height: true,
+		width: false,
+		opacity: true,
+		fixedHeight: false,
+		fixedWidth: false,
+		wait: false,
+		alwaysHide: false
+	},
+
+	initialize: function(){
+		var params = Array.link(arguments, {'container': Element.type, 'options': Object.type, 'togglers': $defined, 'elements': $defined});
+		this.parent(params.elements, params.options);
+		this.togglers = $$(params.togglers);
+		this.container = $(params.container);
+		this.previous = -1;
+		if (this.options.alwaysHide) this.options.wait = true;
+		if ($chk(this.options.show)){
+			this.options.display = false;
+			this.previous = this.options.show;
+		}
+		if (this.options.start){
+			this.options.display = false;
+			this.options.show = false;
+		}
+		this.effects = {};
+		if (this.options.opacity) this.effects.opacity = 'fullOpacity';
+		if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
+		if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
+		for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
+		this.elements.each(function(el, i){
+			if (this.options.show === i){
+				this.fireEvent('active', [this.togglers[i], el]);
+			} else {
+				for (var fx in this.effects) el.setStyle(fx, 0);
+			}
+		}, this);
+		if ($chk(this.options.display)) this.display(this.options.display);
+	},
+
+	addSection: function(toggler, element, pos){
+		toggler = $(toggler);
+		element = $(element);
+		var test = this.togglers.contains(toggler);
+		var len = this.togglers.length;
+		this.togglers.include(toggler);
+		this.elements.include(element);
+		if (len && (!test || pos)){
+			pos = $pick(pos, len - 1);
+			toggler.inject(this.togglers[pos], 'before');
+			element.inject(toggler, 'after');
+		} else if (this.container && !test){
+			toggler.inject(this.container);
+			element.inject(this.container);
+		}
+		var idx = this.togglers.indexOf(toggler);
+		toggler.addEvent('click', this.display.bind(this, idx));
+		if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
+		if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
+		element.fullOpacity = 1;
+		if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
+		if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
+		element.setStyle('overflow', 'hidden');
+		if (!test){
+			for (var fx in this.effects) element.setStyle(fx, 0);
+		}
+		return this;
+	},
+
+	display: function(index){
+		index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
+		if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
+		this.previous = index;
+		var obj = {};
+		this.elements.each(function(el, i){
+			obj[i] = {};
+			var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));
+			this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
+			for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
+		}, this);
+		return this.start(obj);
+	}
+
+});// $Id: common.js 782 2008-08-26 17:36:11Z pspencer $
+/**
+ * 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
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+ 
+/* firebug console supressor for IE/Safari/Opera */
+window.addEvent('load', function() {
+    if (!("console" in window) || !("firebug" in window.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 */
+(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) {}
+    }    
+})();
+
+/* Setup global namespace
+ * If jxcore is loaded by jx.js, then the namespace and baseURL are
+ * already established
+ */
+if (typeof Jx == 'undefined') {
+    var Jx = {};
+    (function(){
+        var aScripts = document.getElementsByTagName('SCRIPT');
+        for (var i=0; i<aScripts.length; i++) {
+            var s = aScripts[i].src;
+            var matches = /(.*)(js|lib\/)jxlib(.*)/.exec(s);
+            if (matches && matches[0]) {
+                /**
+                 * 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.
+                 *
+                 * Note that this assumes that you are loading Jx
+                 * from a js/ or lib/ folder in parallel to the
+                 * images/ folder that contains the various images
+                 * needed by Jx components.  If you have a different
+                 * folder structure, you can define Jx's base
+                 * by including the following before including
+                 * the jxlib javascript file:
+                 *
+                 * (code)
+                 * Jx = {
+                 *    baseURL: 'some/path'
+                 * }
+                 * (end)
+                 */ 
+                 Jx.aPixel = document.createElement('img');
+                 Jx.aPixel.src = matches[1]+'/images/a_pixel.png';
+                 Jx.baseURL = Jx.aPixel.src.substring(0,
+                     Jx.aPixel.src.indexOf('images/a_pixel.png'));
+                
+            }
+        }
+    })();
+} 
+
+/**
+ * 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.
+ *
+ * Parameters:
+ * obj - {Object} an object containing an element and src
+ * property, where element is the element to update and src
+ * is the url to the image.
+ */
+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.element.src = obj.src;
+    } else {
+        //otherwise stick it in the 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() {
+    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.element.onload = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
+        obj.element.onerror = function(){--Jx.imagesLoading; Jx.checkImgQueue();};
+        obj.element.src = obj.src;
+    }
+};
+
+/**
+ * Method: createIframeShim
+ * Creates a new iframe element that is intended to fill a container
+ * to mask out other operating system controls (scrollbars, inputs, 
+ * buttons, etc) when HTML elements are supposed to be above them.
+ */
+Jx.createIframeShim = function() {
+    return new Element('iframe', {
+        'class':'jxIframeShim',
+        'scrolling':'no',
+        'frameborder':0
+    });
+};
+
+/**
+ * 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 = new Class({
+    /**
+     * 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 = [];
+    },
+    /**
+     * 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: Element
+ *
+ * Element is a global object provided by the mootools library.  The
+ * functions documented here are extensions to the Element object provided
+ * by Jx to make cross-browser compatibility easier to achieve.
+ */
+Element.implement({
+    /**
+     * 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.
+     *
+     * Returns:
+     * {String} the box sizing of the element.
+     */
+    getBoxSizing : function() {
+      var result = 'content-box';
+      if (Browser.Engine.trident || Browser.Engine.presto) { 
+          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 = this.getStyle("-moz-box-sizing");
+          if (!sizing) { 
+              sizing = this.getStyle("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.
+     *
+     * Returns:
+     * {Object} an object with two properties, width and height, that
+     * are the size of the content area of the measured element.
+     */
+    getContentBoxSize : function() {
+      var w = this.offsetWidth;
+      var h = this.offsetHeight;
+      var padding = this.getPaddingSize();
+      var border = this.getBorderSize();
+      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.
+     *
+     * Returns:
+     * {Object} an object with two properties, width and height, that
+     * are the size of the border area of the measured element.
+     */
+    getBorderBoxSize: function() {
+      var w = this.offsetWidth;
+      var h = this.offsetHeight;
+      return {width: w, height: h}; 
+    },
+    
+    /**
+     * Method: getMarginBoxSize
+     *
+     * return the size of the margin area of an element.  This is the size of
+     * the element plus margins.
+     *
+     * Parameters: 
+     *
+     * elem - {Object} the element to get the margin sizing of.
+     *
+     * Returns:
+     * {Object} an object with two properties, width and height, that
+     * are the size of the margin area of the measured element.
+     */
+    getMarginBoxSize: function() {
+        var margins = this.getMarginSize();
+        var w = this.offsetWidth + margins.left + margins.right;
+        var h = this.offsetHeight + margins.top + margins.bottom;
+        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(size) {
+        if (this.getBoxSizing() == 'border-box') {
+            var padding = this.getPaddingSize();
+            var border = this.getBorderSize();
+            if (typeof size.width != 'undefined') {
+                var width = (size.width + padding.left + padding.right + border.left + border.right);
+                if (width < 0) {
+                    width = 0;
+                }
+                this.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;
+                }
+                this.style.height = height + 'px';
+            }
+        } else {
+            if (typeof size.width != 'undefined') {
+                this.style.width = size.width + 'px';
+            }
+            if (typeof size.height != 'undefined') {
+                this.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(size) {
+      if (this.getBoxSizing() == 'content-box') {
+        var padding = this.getPaddingSize();
+        var border = this.getBorderSize();
+        var margin = this.getMarginSize();
+        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;
+          }
+          this.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;
+          }
+          this.style.height = height + 'px';
+        }
+      } else {
+        if (typeof size.width != 'undefined' && size.width >= 0) {
+          this.style.width = size.width + 'px';
+        }
+        if (typeof size.height != 'undefined' && size.height >= 0) {
+          this.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.
+     *
+     * Returns:
+     * {Object} an object with properties left, top, right and bottom
+     * that contain the associated padding values.
+     */
+    getPaddingSize : function () {
+      var l = this.getNumber(this.getStyle('padding-left'));
+      var t = this.getNumber(this.getStyle('padding-top'));
+      var r = this.getNumber(this.getStyle('padding-right'));
+      var b = this.getNumber(this.getStyle('padding-bottom'));
+      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.
+     *
+     * Returns:
+     * {Object} an object with properties left, top, right and bottom
+     * that contain the associated border values.
+     */
+    getBorderSize : function() {
+      var l = this.getNumber(this.getStyle('border-left-width'));
+      var t = this.getNumber(this.getStyle('border-top-width'));
+      var r = this.getNumber(this.getStyle('border-right-width'));
+      var b = this.getNumber(this.getStyle('border-bottom-width'));
+      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.
+     *
+     * Returns:
+     *: {Object} an object with properties left, top, right and bottom
+     * that contain the associated margin values.
+     */
+    getMarginSize : function() {
+      var l = this.getNumber(this.getStyle('margin-left'));
+      var t = this.getNumber(this.getStyle('margin-top'));
+      var r = this.getNumber(this.getStyle('margin-right'));
+      var b = this.getNumber(this.getStyle('margin-bottom'));
+      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.
+     *
+     * Returns:
+     * {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.
+     *
+     * Returns:
+     * {Object} an object containing a width and height property 
+     * that represent the width and height of the browser client area.
+     */
+    getPageDimensions: function() {
+        return {width: window.getWidth(), height: window.getHeight()};
+    },
+    
+    descendantOf: function(node) {
+        var parent = $(this.parentNode);
+        if (parent == node) {
+            return true;
+        } else if (!parent || !parent.parentNode) {
+            return null;
+        } else if (parent.parentNode === parent) {
+            return null;
+        } else {
+            return parent.descendantOf(node);
+        }
+    },
+    
+    findElement: function(type) {
+        if (this.tagName == type) {
+            return this;
+        }
+        var parent = $(this.parentNode);
+        if (parent) {
+            if (parent.tagName == type) {
+                return parent;
+            } else if (!parent.parentNode || parent.parentNode == parent) {
+                return null;
+            } else {
+                return parent.findElement(type);
+            }
+        } else {
+            return 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 = new Class ({
+    /**
+     * Property: contentIsLoaded
+     *
+     * tracks the load state of the content, specifically useful
+     * in the case of remote content.
+     */ 
+    contentIsLoaded: 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() { 
+        this.contentIsLoaded = true;
+        this.fireEvent('contentLoaded', this);
+    },
+    /**
+     * 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(r) {
+        // we aren't waiting for content any more.
+        this.contentIsLoaded = true;
+        this.fireEvent('contentLoadFailed', this);
+    },
+    /**
+     * Method: loadContent
+     *
+     * triggers loading of content based on options set for the current
+     * object.
+     *
+     * Parameters: 
+     * element - {Object} the element to insert the content into
+     *
+     * Options:
+     * content - {Mixed} content may be an HTML element reference, the
+     *     id of an HTML element already in the DOM, or an HTML
+     *     string that becomes the inner HTML of the element.
+     * contentURL - {String} the URL to load content from
+     *
+     * Events:
+     *
+     * ContentLoader adds the following events to an object.  You can
+     * register for these events using the addEvent method or by providing
+     * callback functions via the on{EventName} properties in the options 
+     * object
+     *
+     * contentLoaded - called when the content has been loaded.  If the content
+     *     is not asynchronous then this is called before loadContent returns.
+     * contentLoadFailed - called if the content fails to load, primarily
+     *     useful when using the contentURL method of loading content.
+     */     
+    loadContent: function(element) {
+        element = $(element);
+        if (this.options.content) {
+            var c;
+            if (this.options.content.domObj) {
+                c = $(this.options.content.domObj);
+            } else {
+                c = $(this.options.content);
+            }
+            if (c) {
+                element.appendChild(c);
+                this.contentIsLoaded = true;                
+            } else {
+                element.innerHTML = this.options.content;
+                this.contentIsLoaded = true;
+            }
+        } else if (this.options.contentURL) {
+            this.contentIsLoaded = false;
+            new Request.HTML({
+                url: this.options.contentURL, 
+                method:'get',
+                update: element,
+                onSuccess:this.contentLoaded.bind(this), 
+                onFailure: this.contentLoadFailed.bind(this),
+                headers: {'If-Modified-Since': 'Sat, 1 Jan 2000 00:00:00 GMT'}
+            }).send();
+        } else {
+            this.contentIsLoaded = true;
+        }
+        if (this.contentIsLoaded) {
+            this.fireEvent('contentLoaded', this);
+        }
+    },
+    
+    processContent: function(element) {
+        $A(element.childNodes).each(function(node){
+            if (node.tagName == 'INPUT' || node.tagName == 'SELECT' || node.tagName == 'TEXTAREA') {
+                if (node.type == 'button') {
+                    node.addEvent('click', function(){
+                        this.fireEvent('click', this, node);
+                    });
+                } else {
+                    node.addEvent('change', function(){
+                        this.fireEvent('change',node);
+                    });
+                }
+            } else {
+                if (node.childNodes) {
+                    this.processContent(node);
+                }
+            }
+        }, this);
+    }
+});
+
+/**
+ * Class: Jx.AutoPosition
+ * Mix-in class that provides a method for positioning
+ * elements relative to other elements.
+ */
+Jx.AutoPosition = new Class({
+    /**
+     * Method: position
+     * positions an element relative to another element
+     * based on the provided options
+     *
+     * Parameters:
+     * element - the element to position
+     * relative - the element to position relative to
+     * options - the positioning options, see list below.
+     *
+     * Options:
+     * horizontal
+     * vertical
+     * offsets
+     */
+    position: function(element, relative, options) {
+        element = $(element);
+        relative = $(relative);
+        var hor = $splat(options.horizontal || ['center center']);
+        var ver = $splat(options.vertical || ['center center']);
+        var offsets = $merge({top:0,right:0,bottom:0,left:0}, options.offsets || {});
+        
+        var page;
+        if (!$(element.parentNode) || element.parentNode ==  document.body) {
+            page = Element.getPageDimensions();
+        } else {
+            page = $(element.parentNode).getContentBoxSize(); //width, height
+        }
+        var coords = relative.getCoordinates(); //top, left, width, height
+        var size = element.getMarginBoxSize(); //width, height
+        var left;
+        var right;
+        var top;
+        var bottom;
+        if (!hor.some(function(opt) {
+            var parts = opt.split(' ');
+            if (parts.length != 2) {
+                return false;
+            }
+            if (!isNaN(parseInt(parts[0]))) {
+                left = parseInt(parts[0]);
+            } else {
+                switch(parts[0]) {
+                    case 'right':
+                        left = coords.left + coords.width;
+                        break;
+                    case 'center':
+                        left = coords.left + Math.round(coords.width/2);
+                        break;
+                    case 'left':
+                    default:
+                        left = coords.left;
+                }                
+            }
+            switch(parts[1]) {
+                case 'left':
+                    left -= offsets.left;
+                    right = left + size.width;
+                    break;
+                case 'right':
+                    left += offsets.right;
+                    right = left;
+                    left = left - size.width;
+                    break;
+                case 'center':
+                default:
+                    left = left - Math.round(size.width/2);
+                    right = left + size.width;
+            }
+            return (left >= 0 && right <= page.width);
+        })) {
+            // all failed, snap the last position onto the page as best
+            // we can - can't do anything if the element is wider than the
+            // space available.
+            if (right > page.width) {
+                left = page.width - size.width;
+            }
+            if (left < 0) {
+                left = 0;
+            }
+        }
+        element.setStyle('left', left);
+        
+        if (!ver.some(function(opt) {
+                var parts = opt.split(' ');
+                if (parts.length != 2) {
+                    return false;
+                }
+                if (!isNaN(parseInt(parts[0]))) {
+                    top = parseInt(parts[0]);
+                } else {
+                    switch(parts[0]) {
+                        case 'bottom':
+                            top = coords.top + coords.height;
+                            break;
+                        case 'center':
+                            top = coords.top + Math.round(coords.height/2);
+                            break;
+                        case 'top':
+                        default:
+                            top = coords.top;
+                    }
+                }
+                switch(parts[1]) {
+                    case 'top':
+                        top -= offsets.top;
+                        bottom = top + size.height;
+                        break;
+                    case 'bottom':
+                        top += offsets.bottom;
+                        bottom = top;
+                        top = top - size.height;
+                        break;
+                    case 'center':
+                    default:
+                        top = top - Math.round(size.height/2);
+                        bottom = top + size.height;
+                }
+                return (top >= 0 && bottom <= page.height);
+            })) {
+                // all failed, snap the last position onto the page as best
+                // we can - can't do anything if the element is higher than the
+                // space available.
+                if (bottom > page.height) {
+                    top = page.height - size.height;
+                }
+                if (top < 0) {
+                    top = 0;
+                }
+            }    
+            element.setStyle('top', top);
+            
+            /* update the jx layout if necessary */
+            var jxl = element.retrieve('jxLayout');
+            if (jxl) {
+                jxl.options.left = left;
+                jxl.options.top = top;
+            }
+        }
+});
+
+/**
+ * Class: Jx.Chrome
+ * A mix-in class that provides chrome helper functions.  Chrome is the
+ * extraneous visual element that provides the look and feel to some elements
+ * i.e. dialogs.  Chrome is added inside the element specified but may
+ * bleed outside the element to provide drop shadows etc.  This is done by
+ * absolutely positioning the chrome objects in the container based on
+ * calculations using the margins, borders, and padding of the jxChrome
+ * class and the element it is added to.
+ *
+ * Chrome can consist of either pure CSS border and background colors, or
+ * a background-image on the jxChrome class.  Using a background-image on
+ * the jxChrome class creates four images inside the chrome container that
+ * are positioned in the top-left, top-right, bottom-left and bottom-right
+ * corners of the chrome container and are sized to fill 50% of the width
+ * and height.  The images are positioned and clipped such that the 
+ * appropriate corners of the chrome image are displayed in those locations.
+ */
+Jx.Chrome = new Class({
+    /**
+     * Property: chrome
+     * the DOM element that contains the chrome
+     */
+    chrome: null,
+    
+    /**
+     * Method: makeChrome
+     * create chrome on an element.
+     *
+     * Parameters:
+     * element - {HTMLElement} the element to put the chrome on.
+     */
+    makeChrome: function(element) {
+        var c = new Element('div', {
+            'class':'jxChrome'      
+        });
+        
+        /* add to element so we can get the background image style */
+        element.adopt(c);
+        
+        /* pick up any offset because of chrome, set
+         * through padding on the chrome object.  Other code can then
+         * make use of these offset values to fix positioning.
+         */
+        this.chromeOffsets = c.getPaddingSize();
+        c.setStyle('padding', 0);
+        
+        /* get the chrome image from the background image of the element */
+        var src = c.getStyle('backgroundImage');
+        if (!src.contains('http://')) {
+            src = null;
+        } else {
+            src = src.slice(4,-1);
+            /* this only seems to be IE and Opera, but they add quotes
+             * around the url - yuck
+             */
+            if (src.charAt(0) == '"') {
+                src = src.slice(1,-1);
+            }
+
+            /* and remove the background image */
+            c.setStyle('backgroundImage', 'none');
+
+            /* make chrome */
+            ['TL','TR','BL','BR'].each(function(s){
+                c.adopt(
+                    new Element('div',{
+                        'class':'jxChrome'+s
+                    }).adopt(
+                    new Element('img',{
+                        src:src
+                    }))
+                );
+            }, this);
+        }
+        if (!window.opera) {
+            c.adopt(Jx.createIframeShim());
+        }
+        
+        /* remove from DOM so the other resizing logic works as expected */
+        c.dispose();    
+        this.chrome = c;
+    },
+    /**
+     * Method: showChrome
+     * show the chrome on an element.  This creates the chrome if necessary.
+     * If the chrome has been previously created and not removed, you can
+     * call this without an element and it will just resize the chrome within
+     * its existing element.  You can also pass in a different element from
+     * which the chrome was previously attached to and it will move the chrome
+     * to the new element.
+     *
+     * Parameters:
+     * element - {HTMLElement} the element to show the chrome on.
+     */
+    showChrome: function(element) {
+        element = $(element);
+        var jxl;
+        if (!this.chromeResizeHandler) {
+            this.chromeResizeHandler = this.showChrome.bind(this);
+        }
+        if (!this.chrome) {
+            this.makeChrome(element);
+        }
+        if (element && this.chrome.parentNode !== element) {
+            var p = $(this.chrome.parentNode);
+            if (p) {
+                jxl = p.retrieve('jxLayout');
+                if (jxl) {
+                    jxl.removeEvent('sizeChange', this.chromeResizeHandler);
+                }
+            }
+            element.adopt(this.chrome);
+            jxl = element.retrieve('jxLayout');
+            if (jxl) {
+                jxl.addEvent('sizeChange', this.chromeResizeHandler);
+            }
+        }
+        this.resizeChrome();
+    },
+    /**
+     * Method: resizeChrome
+     * resizes the chrome to fit around its parent, should be called
+     * automatically if the parent is controlled by <Jx.Layout>, 
+     * otherwise you will need to call this yourself if your chromed
+     * element changes size.
+     */
+    resizeChrome: function() {
+        // if (this.chrome && this.chrome.parentNode) {
+        //     var p = $(this.chrome.parentNode);
+        //     var padding = this.chrome.getPaddingSize();
+        //     var chromeBorder = this.chrome.getBorderSize();
+        //     var margin = p.getMarginSize();
+        //     var border = p.getBorderSize();
+        //     var size = p.getMarginBoxSize();
+        //     this.chrome.setStyles({
+        //          left: -(padding.left + chromeBorder.left + border.left + margin.left),
+        //          top: -(padding.top +  chromeBorder.top + border.top + margin.top)
+        //     });
+        //     this.chrome.setContentBoxSize(size);
+        // }        
+    },
+    /**
+     * Method: hideChrome
+     * removes the chrome from the DOM.  If you do this, you can't
+     * call showChrome with no arguments.
+     */
+    hideChrome: function() {
+        if (this.chrome) {
+            if (this.chrome.parentNode) {
+                var jxl = this.chrome.parentNode.retrieve('jxLayout');
+                if (jxl) {
+                    jxl.removeEvent('sizeChange', this.chromeResizeHandler);
+                }            
+            }
+            this.chrome.dispose();
+        }
+    }
+});// $Id: button.js 777 2008-08-25 15:20:23Z pspencer $
+/**
+ * Class: Jx.Button
+ * Jx.Button creates a clickable element that can be added to a web page.
+ * When the button is clicked, it fires a 'click' event.
+ *
+ * The CSS styling for a button is controlled by several classes related
+ * to the various objects in the button's HTML structure:
+ *
+ * (code)
+ * <div class="jxButtonContainer">
+ *  <a class="jxButton">
+ *   <span class="jxButtonContent">
+ *    <img class="jxButtonIcon" src="image_url">
+ *    <span class="jxButtonLabel">button label</span>
+ *   </span>
+ *  </a>
+ * </div>
+ * (end)
+ *
+ * The CSS classes will change depending on the type option passed to the
+ * constructor of the button.  The default type is Button.  Passing another
+ * value such as Tab will cause all the CSS classes to change from jxButton
+ * to jxTab.  For example:
+ *
+ * (code)
+ * <div class="jxTabContainer">
+ *  <a class="jxTab">
+ *   <span class="jxTabContent">
+ *    <img class="jxTabIcon" src="image_url">
+ *    <span class="jxTabLabel">tab label</span>
+ *   </span>
+ *  </a>
+ * </div>
+ * (end)
+ *
+ * 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 web page.  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 addTo method to append or insert the button into the 
+ * page.  
+ *
+ * There are two types of buttons, normal and toggle.  A toggle button
+ * has an active state analogous to a checkbox.  A toggle button generates
+ * different events (down and up) from a normal button (click).  To create
+ * a toggle button, pass type: 'toggle' to the Jx.Button constructor.
+ *
+ * To use a Jx.Button in an application, you need to register for the 'click'
+ * event.  You can pass a function in the 'onClick' option when constructing
+ * a button or you can call the addEvent('click', myFunction) method.  The
+ * addEvent method can be called several times, allowing more than one function
+ * to be called when a button is clicked.  You can use the 
+ * removeEvent('click', myFunction) method to stop receiving click events.
+ *
+ * Example:
+ *
+ * (code)
+ * var button = new Jx.Button(options);
+ * button.addTo('myListItem'); // the id of an LI in the page.
+ * (end)
+ *
+ * (code)
+ * Example:
+ * var options = {
+ *     imgPath: 'images/mybutton.png',
+ *     tooltip: 'click me!',
+ *     label: 'click me',
+ *     onClick: function() {
+ *         alert('you clicked me');
+ *     }
+ * };
+ * var button = new Jx.Button(options);
+ * button.addEvent('click', anotherFunction);
+ *
+ * function anotherFunction() {
+ *   alert('a second alert for a single click');
+ * }
+ * (end)
+ *
+ * Events:
+ * click - the button was pressed and released (only if type is not 'toggle').
+ * down - the button is down (only if type is 'toggle')
+ * up - the button is up (only if the type is 'toggle').
+ *
+ * Implements:
+ * Options - from MooTools Class.Extras
+ * Events - from MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+ 
+Jx.Button = new Class({
+    Implements: [Options,Events],
+    
+    /**
+     * Property: {Object} domObj
+     * the HTML element that is inserted into the DOM for this button.  You
+     * may reference this object to append it to the DOM or remove it from
+     * the DOM if necessary.
+     */
+    domObj: null,
+    
+    /**
+     * Property: {Object} options
+     * default options for a button.
+     */
+    options: {
+        id: '',
+        type: 'Button',
+        image: '',
+        tooltip: '',
+        label: '',
+        enabled: true,
+        toggle: false,
+        halign: 'center',
+        valign: 'middle',
+        isActive: false,
+        container: 'div'
+    },
+    /**
+     * Constructor: Jx.Button
+     * create a new button.
+     *
+     * Parameters:
+     * options - {Object} an object containing optional properties for this
+     * button as below.
+     *
+     * Options:
+     * id - optional.  A string value to use as the ID of the button
+     *     container.
+     * type - optional.  A string value that indicates what type of button
+     *     this is.  The default value is Button.  The type is used to form
+     *     the CSS class names used for various HTML elements within the
+     *     button.
+     * 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 - {String} optional, default is no label.  A string value
+     *     that is used as a label on the button.
+     * enabled - {Boolean} whether the button is enabled or not.
+     * halign - {String} horizontal alignment of the button label, 'center' by
+     *     default.  Other values are 'left' and 'right'.
+     * valign - {String} vertical alignment of the button label, 'middle' by
+     *     default.  Other values are 'top' and 'bottom'.
+     * isActive - {Boolean} optional, default false.  Controls the initial
+     *     state of toggle buttons.
+     * container - {String} the tag name of the HTML element that should be
+     *     created to contain the button, by default this is 'div'.
+     */
+    initialize : function( options ) {
+        this.setOptions(options);
+        
+        // the main container for the button
+        var d = new Element(this.options.container, {'class': 'jx'+this.options.type+'Container'});
+        if (this.options.toggle) {
+            d.addClass('jx'+this.options.type+'Toggle');
+        }
+        // the clickable part of the button
+        var a = new Element('a', {
+            'class': 'jx'+this.options.type, 
+            href: 'javascript:void(0)', 
+            title: this.options.tooltip, 
+            alt: this.options.tooltip,
+            events: {
+                click: this.clicked.bindWithEvent(this)
+            }
+        });
+        if (this.options.isActive) {
+            a.addClass('jx'+this.options.type+'Active');
+        }
+        d.appendChild(a);
+        
+        var s = new Element('span', {'class': 'jx'+this.options.type+'Content'});
+        a.appendChild(s);
+        
+        if (this.options.image || !this.options.label) {
+            var i = new Element('img', {
+                'class':'jx'+this.options.type+'Icon',
+                'src': Jx.aPixel.src
+            });
+            //if image is not a_pixel, set the background image of the image
+            //otherwise let the default css take over.
+            if (this.options.image.indexOf('a_pixel.png') == -1) {
+                i.setStyle('backgroundImage',"url("+this.options.image+")");
+            }
+            s.appendChild(i);
+        }
+        
+        l = new Element('span', {
+            html: this.options.label
+        });
+        if (this.options.label) {
+            l.addClass('jx'+this.options.type+'Label');
+        }
+        s.appendChild(l);
+        
+        if (this.options.id) {
+            d.id = this.options.id;
+        }
+        if (this.options.halign == 'left') {
+            d.addClass('jx'+this.options.type+'ContentLeft');                
+        }
+
+        if (this.options.valign == 'top') {
+            d.addClass('jx'+this.options.type+'ContentTop');
+        }
+        
+        this.domA = a;
+        this.domLabel = l;
+        this.domObj = d;        
+
+        //update the enabled state
+        this.setEnabled(this.options.enabled);
+    },
+    /**
+     * Method: clicked
+     * triggered when the user clicks the button, processes the
+     * actionPerformed event
+     *
+     * Parameters:
+     * evt - {Event} the user click event
+     */
+    clicked : function(evt) {
+        if (this.options.enabled) {
+            if (this.options.toggle) {
+                this.setActive(!this.options.isActive);
+            } else {
+                this.fireEvent('click', {obj: this, event: evt});
+            }
+        }
+        //return false;
+    },
+    /**
+     * Method: setEnabled
+     * enable or disable the button.
+     *
+     * Parameters:
+     * enabled - {Boolean} the new enabled state of the button
+     */
+    setEnabled: function(enabled) {
+        this.options.enabled = enabled;
+        if (this.options.enabled) {
+            this.domObj.removeClass('jx'+this.options.type+'Disabled');
+        } else {
+            this.domObj.addClass('jx'+this.options.type+'Disabled');
+        }
+    },
+    /**
+     * Method: isActive
+     * For toggle buttons, this returns true if the toggle button is
+     * currently active and false otherwise.
+     *
+     * Returns:
+     * {Boolean} the active state of a toggle button
+     */
+    isActive: function() { 
+        return this.options.isActive; 
+    },
+    /**
+     * Method: setActive
+     * Set the active state of the button
+     */
+    setActive: function(isActive) {
+        if (this.options.isActive == isActive) {
+            return;
+        }
+        this.options.isActive = isActive;
+        if (this.options.isActive) {
+            this.domA.addClass('jx'+this.options.type+'Active');
+            this.fireEvent('down', this);
+        } else {
+            this.domA.removeClass('jx'+this.options.type+'Active');
+            this.fireEvent('up', this);
+        }
+    },
+    /**
+     * 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.set('src', path);
+        }
+    },
+    /**
+     * Method: setLabel
+     * 
+     * sets the text of the button.  Only works if a label was supplied
+     * when the button was constructed
+     *
+     * Parameters: 
+     *
+     * label - {String} the new label for the button
+     */
+    setLabel: function(label) {
+        if (this.domLabel) {
+            this.domLabel.set('html', label);
+        }
+    },
+    /**
+     * Method: setTooltip
+     * sets the tooltip displayed by the button
+     *
+     * Parameters: 
+     * tooltip - {String} the new tooltip
+     */
+    setTooltip: function(tooltip) {
+        if (this.domImg) {
+            this.domImg.set({
+                'title':tooltip,
+                'alt':tooltip
+            });
+        }
+    },
+    /**
+     * Method: addTo
+     * adds the button to a DOM element using appendChild if sibling
+     * is not specified or sibling's parent is not the specified parent,
+     * otherwise uses insertBefore.    
+     *
+     * Parameters:
+     * parent - {Object} the DOM element or id of a DOM element
+     * to append the button to.
+     * sibling - {Object} the DOM element or id of a DOM element
+     * to insert the button before.  If not specified, then the
+     * button is appended to the parent.
+     */
+    addTo: function(parent, sibling) {
+        parent = $(parent);
+        sibling = sibling ? $(sibling) : null;
+        if (sibling && sibling.parentNode == parent) {
+            parent.insertBefore(this.domObj, sibling);
+        } else {
+            parent.appendChild(this.domObj);            
+        }
+    }
+});// $Id: button.flyout.js 782 2008-08-26 17:36:11Z pspencer $
+/**
+ * Class: Jx.Button.Flyout
+ * Flyout buttons expose a panel when the user clicks the button.  The
+ * panel can have arbitrary content.  You must provide any necessary 
+ * code to hook up elements in the panel to your application.
+ *
+ * When the panel is opened, the 'open' event is fired.  When the panel is
+ * closed, the 'close' event is fired.  You can register functions to handle
+ * these events in the options passed to the constructor (onOpen, onClose).
+ * 
+ * The user can close the flyout panel by clicking the button again, by
+ * clicking anywhere outside the panel and other buttons, or by pressing the
+ * 'esc' key.
+ *
+ * A flyout is structure the same way as a normal <Jx.Button> except that an
+ * extra div is appended to the jxButtonContainer element and given a class
+ * of jxFlyout.
+ *
+ * Flyout buttons implement <Jx.ContentLoader> which provides the hooks to
+ * insert content into the jxFlyout element.  Note that the jxFlyout element
+ * is not appended to the DOM until the first time it is opened.
+ *
+ * It is generally best to specify a width and height for your flyout content
+ * area through CSS to ensure that it works correctly across all browsers.
+ * To do this, make sure to provide a unique 'id' in the options when
+ * constructing your button and then provide some CSS:
+ *
+ * (code)
+ * #myFlyout .jxFlyout {
+ *   width: 200px;
+ *   height: 100px;
+ * }
+ * (end)
+ *
+ * A flyout closes other flyouts when it is opened.  It is possible to embed
+ * flyout buttons inside the content area of another flyout button.  In this
+ * case, opening the inner flyout will not close the outer flyout but it will
+ * close any other flyouts that are siblings.
+ *
+ * Example:
+ * (code)
+ * var flyout = new Jx.Button.Flyout({
+ *      label: 'flyout',
+ *      content: 'flyoutContent',
+ *      onOpen: function(flyout) {
+ *          console.log('flyout opened');
+ *      },
+ *      onClose: function(flyout) {
+ *          console.log('flyout closed');
+ *      }
+ * });
+ * (end)
+ *
+ * Events:
+ * open - this event is triggered when the flyout is opened.
+ * close - this event is triggered when the flyout is closed.
+ *
+ * Extends:
+ * <Jx.Button>
+ * 
+ * Implements:
+ * <Jx.ContentLoader>
+ * <Jx.AutoPosition>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Button.Flyout = new Class({
+    Extends: Jx.Button,
+    Implements: [Jx.ContentLoader, Jx.AutoPosition, Jx.Chrome],
+    
+    /**
+     * Property: content
+     * the HTML element that contains the flyout content
+     */
+    content: null,
+    /**
+     * Constructor: initialize
+     *
+     * 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: {Object} options
+     *
+     * an options object used to initialize the button
+     */
+    initialize: function(options) {
+        if (!Jx.Button.Flyout.Stack) {
+            Jx.Button.Flyout.Stack = [];
+        }
+        this.parent(options);
+        this.domA.addClass('jx'+this.options.type+'Flyout');
+        
+        this.contentContainer = new Element('div',{
+            'class':'jxFlyout'
+        });
+        
+        this.content = new Element('div', {
+            'class': 'jxFlyoutContent'
+        });
+        this.contentContainer.adopt(this.content);
+        
+        this.content.store('jxFlyout', this);
+        this.loadContent(this.content);
+        this.keypressWatcher = this.keypressHandler.bindWithEvent(this);
+        this.hideWatcher = this.clickHandler.bindWithEvent(this);
+    },
+    /**
+     * Method: clicked
+     * Override <Jx.Button::clicked> to hide/show the content area of the
+     * flyout.
+     *
+     * Parameters:
+     * e - {Event} the user event
+     */ 
+    clicked: function(e) {
+        /* find out what we are contained by if we don't already know */
+        if (!this.owner) {
+            this.owner = document.body;
+            var node = $(this.domObj.parentNode);
+            while (node != document.body && this.owner == document.body) {
+                var flyout = node.retrieve('jxFlyout');
+                if (flyout) {
+                    this.owner = flyout;
+                    break;
+                } else {
+                    node = $(node.parentNode);
+                }
+            }
+        }
+        if (Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length - 1] == this) {
+            this.hide();
+            return;
+        } else if (this.owner != document.body) {
+            /* if we are part of another flyout, close any open flyouts
+             * inside the parent and register this as the current flyout
+             */
+            if (this.owner.currentFlyout == this) {
+                /* if the flyout to close is this flyout,
+                 * hide this and return */
+                this.hide();
+                return;
+            } else if (this.owner.currentFlyout) {
+                this.owner.currentFlyout.hide();
+            }
+            this.owner.currentFlyout = this;                
+        } else {
+            /* if we are at the top level, close the entire stack before
+             * we open
+             */
+            while (Jx.Button.Flyout.Stack.length) {
+                Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length - 1].hide();
+            }
+        }
+        // now we go on the stack.
+        Jx.Button.Flyout.Stack.push(this);
+
+        this.options.isActive = true;
+        this.domA.addClass('jx'+this.options.type+'Active');
+        this.contentContainer.setStyle('visibility','hidden');
+        document.body.adopt(this.contentContainer);
+        this.showChrome(this.contentContainer);
+        
+        this.position(this.contentContainer, this.domObj, {
+            horizontal: ['left left', 'right right'],
+            vertical: ['bottom top', 'top bottom'],
+            offsets: this.chromeOffsets
+        });
+        this.contentContainer.setStyle('visibility','');
+        
+        window.addEvent('keypress', this.keypressWatcher);
+        document.addEvent('click', this.hideWatcher);
+        this.fireEvent('open', this);
+    },
+    /**
+     * Method: hide
+     * Closes the flyout if open
+     */
+    hide: function() {
+        if (this.owner != document.body) {
+            this.owner.currentFlyout = null;            
+        }
+        Jx.Button.Flyout.Stack.pop();
+        this.setActive(false);
+        this.contentContainer.dispose();
+        window.removeEvent('keypress', this.keypressWatcher);    
+        document.removeEvent('click', this.hideWatcher);
+        this.fireEvent('close', this);
+    },
+    /* hide flyout if the user clicks outside of the flyout */
+    clickHandler: function(e) {
+        e = new Event(e);
+        var elm = $(e.target);
+        var flyout = Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length - 1];
+        if (!elm.descendantOf(flyout.content) &&
+            !elm.descendantOf(flyout.domObj)) {
+            flyout.hide();
+        }
+    },
+    /* hide flyout if the user presses the ESC key */
+    keypressHandler: function(e) {
+        e = new Event(e);
+        if (e.key == 'esc') {
+            Jx.Button.Flyout.Stack[Jx.Button.Flyout.Stack.length - 1].hide();
+        }
+    }
+});// $Id: button.multi.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * 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 method.
+ *
+ * This is not really a button, but rather a container for buttons.  The
+ * button structure is a div containing two buttons, a normal button and
+ * a flyout button.  The flyout contains a toolbar into which all the 
+ * added buttons are placed.  The main button content is cloned from the
+ * last button clicked (or first button added).
+ *
+ * The Multi button does not trigger any events itself, only the contained
+ * buttons trigger events.
+ *
+ * Example:
+ * (code)
+ * var b1 = new Jx.Button({
+ *     label: 'b1',
+ *     onClick: function(button) {
+ *         console.log('b1 clicked');
+ *     }
+ * });
+ * var b2 = new Jx.Button({
+ *     label: 'b2',
+ *     onClick: function(button) {
+ *         console.log('b2 clicked');
+ *     }
+ * });
+ * var b3 = new Jx.Button({
+ *     label: 'b3',
+ *     onClick: function(button) {
+ *         console.log('b3 clicked');
+ *     }
+ * });
+ * var multiButton = new Jx.Button.Multi();
+ * multiButton.add(b1, b2, b3);
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Button.Multi = new Class({
+    /**
+     * Property: {<Jx.Button>} activeButton
+     * the currently selected button
+     */
+    activeButton: null,
+    /**
+     * Property: buttons
+     * {Array} the buttons added to this multi button
+     */
+    buttons: null,
+    /**
+     * Constructor: Jx.Button.Multi
+     * construct a new instance of Jx.Button.Multi.
+     */
+    initialize: function() {
+        this.buttons = [];
+        var d = new Element('div');
+        this.tb = new Jx.Toolbar({parent: d, position:'right'});
+        this.flyout = new Jx.Button.Flyout({content: d});
+        this.flyout.domObj.firstChild.addClass('jxButtonMulti');
+        this.domObj = new Element('div', {'class': 'jxButtonMultiContainer'});
+        this.domObj.grab(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() {
+        $A(arguments).each(function(theButton){
+            if (!theButton instanceof Jx.Button) {
+                return;
+            }
+            this.buttons.push(theButton);
+            var button = new Jx.Button($merge(
+                theButton.options, 
+                {onClick: this.setButton.bind(this, theButton)}
+            ));
+            theButton.multiButton = button;
+            this.tb.add(button);
+            if (!this.activeButton) {
+                this.domObj.grab(theButton.domObj, 'top');
+                this.activeButton = theButton;
+            }
+        }, this);
+    },
+    /**
+     * Method: remove
+     * remove a button from a multi button
+     *
+     * Parameters:
+     * button - {<Jx.Button>} the button to remove
+     */
+    remove: function(button) {
+        if (!button || !button.multiButton) {
+            return;
+        }
+        // the toolbar will only remove the li.toolItem, which is
+        // the parent node of the multiButton's domObj.
+        if (this.tb.remove(button.multiButton)) {
+            button.multiButton = null;
+            if (this.activeButton == button) {
+                // if any buttons are left that are not this button
+                // then set the first one to be the active button
+                // otherwise set the active button to nothing
+                if (!this.buttons.some(function(b) {
+                    if (b != button) {
+                        this.setActiveButton(b);
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }, this)) {
+                    this.setActiveButton(null);
+                };
+            }
+            /* force the flyout to recalculate its size */
+            this.flyout.content.style.height = '';
+            this.flyout.content.style.width = '';
+            this.buttons.erase(button);
+        }
+    },
+    /**
+     * Method: addTo
+     * adds the button to a DOM element using appendChild if sibling
+     * is not specified or sibling's parent is not the specified parent,
+     * otherwise uses insertBefore.    
+     *
+     * Parameters:
+     * parent - {Object} the DOM element or id of a DOM element
+     * to append the button to.
+     * sibling - {Object} the DOM element or id of a DOM element
+     * to insert the button before.  If not specified, then the
+     * button is appended to the parent.
+     */
+    addTo: function(parent, sibling) {
+        parent = $(parent);
+        sibling = sibling ? $(sibling) : null;
+        if (sibling && sibling.parentNode == parent) {
+            parent.grab(this.domObj, 'top');
+        } else {
+            parent.adopt(this.domObj);            
+        }
+    },
+    /**
+     * 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) {
+        if (this.activeButton) {
+            this.activeButton.domObj.dispose();
+        }
+        if (button && button.domObj) {
+            this.domObj.grab(button.domObj, 'top');            
+        }
+        this.activeButton = button;
+    },
+    /**
+     * 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.clicked();
+        this.flyout.hide();
+    }
+});// $Id: colorpalette.js 763 2008-08-21 13:18:11Z pspencer $
+/**
+ * Class: Jx.ColorPalette
+ * A Jx.ColorPalette 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.ColorPalette can be embedded anywhere in a web page by appending its
+ * <Jx.ColorPalette.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 changed event.  To
+ * be notified of changes in a Jx.ColorPalette, use the addEvent method.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * change - triggered when the color changes.
+ * click - the user clicked on a color swatch (emitted after a change event)
+ *
+ * Implements:
+ * Options - MooTools Class.Extras
+ * Events - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+
+Jx.ColorPalette = new Class({
+    Implements: [Options, Events],
+    /**
+     * Property: {HTMLElement} domObj
+     * the HTML element representing the color panel
+     */
+    domObj: null,
+    options: {
+        color: '#000000',
+        alpha: 1
+    },
+    /**
+     * 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.ColorPalette
+     * initialize a new instance of Jx.ColorPalette
+     *
+     * 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) {
+        this.setOptions(options);
+
+        this.domObj = new Element('div', {
+            id: this.options.id,
+            'class':'jxColorPalette'
+        });
+
+        var top = new Element('div', {'class':'jxColorBar'});
+        var d = new Element('div', {'class':'jxColorPreview'});
+
+        this.selectedSwatch = new Element('div', {'class':'jxColorSelected'});
+        this.previewSwatch = new Element('div', {'class':'jxColorHover'});
+        d.adopt(this.selectedSwatch);
+        d.adopt(this.previewSwatch);
+        
+        top.adopt(d);
+
+        this.colorInputLabel = new Element('label', {'class':'jxColorLabel', html:'#'});
+        top.adopt(this.colorInputLabel);
+
+        var cc = this.changed.bind(this);
+        this.colorInput = new Element('input', {
+            'class':'jxHexInput',
+            'type':'text',
+            'maxLength':6,
+            events: {
+                'keyup':cc,
+                'blur':cc,
+                'change':cc
+            }
+        });
+
+        top.adopt(this.colorInput);
+
+        this.alphaLabel = new Element('label', {'class':'jxAlphaLabel', 'html':'alpha (%)'});
+        top.adopt(this.alphaLabel);
+
+        this.alphaInput = new Element('input', {
+            'class':'jxAlphaInput',
+            'type':'text',
+            'maxLength':3,
+            events: {
+                'keyup': this.alphaChanged.bind(this)
+            }
+        });
+        top.adopt(this.alphaInput);
+
+        this.domObj.adopt(top);
+
+        d = new Element('div', {'class':'jxClearer'});
+        this.domObj.adopt(d);
+
+        var swatchClick = this.swatchClick.bindWithEvent(this);
+        var swatchOver = this.swatchOver.bindWithEvent(this);
+
+        var table = new Element('table', {'class':'jxColorGrid'});
+        var tbody = new Element('tbody');
+        table.adopt(tbody);
+        for (var i=0; i<12; i++) {
+            var tr = new Element('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 = new Element('td');
+                if (!bSkip) {
+                    td.setStyle('backgroundColor', bgColor);
+
+                    var a = new Element('a', {
+                        'class': 'colorSwatch ' + (((r > 2 && g > 2) || (r > 2 && b > 2) || (g > 2 && b > 2)) ? 'borderBlack': 'borderWhite'),
+                        'href':'#',
+                        'title':bgColor,
+                        'alt':bgColor,
+                        events: {
+                            'mouseover': swatchOver,
+                            'click': swatchClick
+                        }
+                    });
+                    a.store('swatchColor', bgColor);
+                    td.adopt(a);
+                } else {
+                    var span = new Element('span', {'class':'emptyCell'});
+                    td.adopt(span);
+                }
+                tr.adopt(td);
+            }
+            tbody.adopt(tr);
+        }
+        this.domObj.adopt(table);
+        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 = e.target;
+
+        this.previewSwatch.setStyle('backgroundColor', a.retrieve('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 = e.target;
+
+        this.options.color = a.retrieve('swatchColor');
+        this.updateSelected();
+        this.fireEvent('click', this);
+    },
+
+    /**
+     * Method: changed
+     * handle the user entering a new colour value manually by updating the
+     * selected colour if the entered value is valid HEX.
+     */
+    changed: function() {
+        var color = this.colorInput.value;
+        if (color.substring(0,1) == '#') {
+            color = color.substring(1);
+        }
+        if (color.toLowerCase().match(/^[0-9a-f]{6}$/)) {
+            this.options.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.options.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.changed();
+    },
+
+    /**
+     * 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() {
+        var styles = {'backgroundColor':this.options.color};
+
+        this.colorInput.value = this.options.color.substring(1);
+
+        this.alphaInput.value = parseInt(this.options.alpha*100);
+        if (this.options.alpha < 1) {
+            styles.opacity = this.options.alpha;
+            styles.filter = 'Alpha(opacity='+(this.options.alpha*100)+')';
+        } else {
+            styles.opacity = '';
+            styles.filter = '';
+        }
+        this.selectedSwatch.setStyles(styles);
+        this.previewSwatch.setStyles(styles);
+        this.fireEvent('change', this);
+    }
+});
+
+// $Id: button.color.js 763 2008-08-21 13:18:11Z pspencer $ 
+/**
+ * Class: Jx.Button.Color
+ * A <Jx.ColorPalette> wrapped up in a Jx.Button.  The button includes a
+ * preview of the currently selected color.  Clicking the button opens
+ * the color panel.
+ *
+ * A color button is essentially a <Jx.Button.Flyout> where the content
+ * of the flyout is a <Jx.ColorPalette>.
+ *
+ * Example:
+ * (code)
+ * var colorButton = new Jx.Button.Color({
+ *     onChange: function(button) {
+ *         console.log('color:' + button.options.color + ' alpha: ' + button.options.alpha);     
+ *     }
+ * });
+ * (end)
+ *
+ * Events:
+ * change - fired when the color is changed.
+ *
+ * Extends:
+ * <Jx.Button.Flyout>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Button.Color = new Class({
+    Extends: Jx.Button.Flyout,
+    /**
+     * Property: {HTMLElement} swatch
+     * a div used to represent the current colour in the button.
+     */
+    swatch: null,
+    options: {
+        color: '#000000',
+        alpha: 100
+    },
+    /**
+     * 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) {
+       // this.parent($merge({label:'&nbsp;'},options));
+
+        if (!Jx.Button.Color.ColorPalette) {
+            Jx.Button.Color.ColorPalette = new Jx.ColorPalette(this.options);
+        }
+        var d = new Element('span', {'class':'jxButtonSwatch'});
+
+        this.selectedSwatch = new Element('span');
+        d.appendChild(this.selectedSwatch);
+
+        this.colorChangeFn = this.changed.bind(this);
+        this.hideFn = this.hide.bind(this);
+
+        /* 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]);
+        $(this.domObj.firstChild).addClass('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
+     */
+    clicked: function() {
+        if (Jx.Button.Color.ColorPalette.currentButton) {
+            Jx.Button.Color.ColorPalette.currentButton.hide();
+        }
+        Jx.Button.Color.ColorPalette.currentButton = this;
+        Jx.Button.Color.ColorPalette.addEvent('change', this.colorChangeFn);
+        Jx.Button.Color.ColorPalette.addEvent('click', this.hideFn);
+        this.content.appendChild(Jx.Button.Color.ColorPalette.domObj);
+        Jx.Button.Color.ColorPalette.domObj.setStyle('display', 'block');
+        Jx.Button.Flyout.prototype.clicked.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
+         */
+         
+        Jx.Button.Color.ColorPalette.options.color = this.options.color;
+        Jx.Button.Color.ColorPalette.options.alpha = this.options.alpha/100;
+        Jx.Button.Color.ColorPalette.updateSelected();
+},
+
+    /**
+     * Method: hide
+     * hide the colour panel
+     */
+    hide: function() {
+        this.setActive(false);
+        Jx.Button.Color.ColorPalette.removeEvent('change', this.colorChangeFn);
+        Jx.Button.Color.ColorPalette.removeEvent('click', this.hideFn);
+        Jx.Button.Flyout.prototype.hide.apply(this, arguments);
+        Jx.Button.Color.ColorPalette.currentButton = null;
+    },
+
+    /**
+     * Method: setColor
+     * set the colour represented by this colour panel
+     *
+     * Parameters:
+     * color - {String} the new hex color value
+     */
+    setColor: function(color) {
+        this.options.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.options.alpha = alpha;
+        this.updateSwatch();
+    },
+
+    /**
+     * Method: changed
+     * colorChangeListener callback function when the user changes
+     * the colour in the panel (just update the preview).
+     */
+    changed: function(panel) {
+        var changed = false;
+        if (this.options.color != panel.options.color) {
+            this.options.color = panel.options.color;
+            changed = true;
+        }
+        if (this.options.alpha != panel.options.alpha * 100) {
+            this.options.alpha = panel.options.alpha * 100;
+            changed = true;
+        }
+        if (changed) {
+            this.updateSwatch();
+            this.fireEvent('change',this);
+        }
+    },
+
+    /**
+     * Method: updateSwatch
+     * Update the swatch color for the current color
+     */
+    updateSwatch: function() {
+        var styles = {'backgroundColor':this.options.color};
+        if (this.options.alpha < 100) {
+            styles.filter = 'Alpha(opacity='+(this.options.alpha)+')';
+            styles.opacity = this.options.alpha / 100;
+            
+        } else {
+            styles.opacity = '';
+            styles.filter = '';
+        }
+        this.selectedSwatch.setStyles(styles);
+    }
+});
+// $Id: $
+/**
+ * Class: Jx.ButtonSet
+ * A ButtonSet manages a set of <Jx.Button> instances by ensuring that only one
+ * of the buttons is active.
+ *
+ * Example:
+ * (code)
+ * var toolbar = new Jx.Toolbar('bar');
+ * var buttonSet = new Jx.ButtonSet();
+ * 
+ * var tab1 = new Jx.Button({label: 'b1', toggle:true, contentID: 'content1'});
+ * var tab2 = new Jx.Button({label: 'b2', toggle:true, contentID: 'content2'});
+ * var tab3 = new Jx.Button({label: 'b3', toggle:true, contentID: 'content3'});
+ * var tab4 = new Jx.Button({label: 'b4', toggle:true, contentURL: 'test_content.html'});
+ * 
+ * buttonSet.add(b1,b2,b3,b4);
+ * (end)
+ *
+ * Events:
+ * change - the current button has changed
+ *
+ * Implements:
+ * Events - MooTools Class.Extras
+ * Options - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.ButtonSet = new Class({
+    Implements: [Options,Events],
+    /**
+     * Property: buttons
+     * {Array} array of buttons that are managed by this button set
+     */
+    buttons: null,
+    /**
+     * Constructor: Jx.ButtonSet
+     * Create a new instance of <Jx.ButtonSet>
+     *
+     * Parameters:
+     * options - an options object, only event handlers are supported
+     * as options at this time.
+     */
+    initialize : function(options) {
+        this.setOptions(options);
+        this.buttons = [];
+        this.buttonChangedHandler = this.buttonChanged.bind(this);
+        
+    },
+    
+    /**
+     * Method: add
+     * Add one or more <Jx.Button>s to the ButtonSet.
+     *
+     * Parameters:
+     * button - {<Jx.Button>} an instance of <Jx.Button> to add to the button set.  More
+     * than one button can be added by passing extra parameters to this method.
+     */
+    add : function() {
+        $A(arguments).each(function(button) {
+            button.domObj.addClass('jx'+button.options.type+'Set');
+            button.addEvent('down',this.buttonChangedHandler);
+            if (!this.activeButton) {
+                button.setActive(true);
+            }
+            this.buttons.push(button);
+        }, this);
+    },
+    /**
+     * Method: remove
+     * Remove a button from this Button.
+     *
+     * Parameters:
+     * button - {<Jx.Button>} the button to remove.
+     */
+    remove : function(button) {
+        this.buttons.erase(button);
+        if (this.activeButton == button) {
+            if (this.buttons.length) {
+                this.buttons[0].setActive(true);
+            }
+            button.removeEvent('down',this.buttonChangedHandler);
+        }
+    },
+    /**
+     * Method: setActiveButton
+     * Set the active button to the one passed to this method
+     *
+     * Parameters:
+     * button - {<Jx.Button>} the button to make active.
+     */
+    setActiveButton: function(button) {
+        if (this.activeButton && this.activeButton != button) {
+            this.activeButton.setActive(false);
+        }
+        this.activeButton = button;
+    },
+    /**
+     * Method: selectionChanged
+     * Handle selection changing on the buttons themselves and activate the
+     * appropriate button in response.
+     *
+     * Parameters:
+     * button - {<Jx.Button>} the button to make active.
+     */
+    buttonChanged: function(button) {
+        this.setActiveButton(button);
+        this.fireEvent('change', this);
+    }
+});
+
+
+
+// $Id: grid.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Grid
+ * A tabular control that has fixed scrolling headers on the rows and columns
+ * like a spreadsheet.
+ *
+ * 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.
+ *
+ * Jx.Grid Model Interface:
+ *
+ * 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.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Implements:
+ * Options - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Grid = new Class({
+    Implements: [Options],
+    domObj : null,
+    model : null,
+    options: {
+        alternateRowColors: false,
+        rowHeaders: false,
+        columnHeaders: false,
+        rowSelection: false,
+        cellSelection: false
+    },
+    /**
+     * 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.setOptions(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
+         */
+        var jxl = this.domObj.retrieve('jxLayout');
+        if (jxl) {
+            jxl.addEvent('sizeChange', this.resize.bind(this));
+        }
+        
+        
+        this.rowColObj = new Element('div', {'class':'jxGridContainer'});
+        
+        this.colObj = new Element('div', {'class':'jxGridContainer'});
+        this.colTable = new Element('table', {'class':'jxGridTable'});
+        this.colTableHead = new Element('thead');
+        this.colTable.appendChild(this.colTableHead);
+        this.colTableBody = new Element('tbody');
+        this.colTable.appendChild(this.colTableBody);
+        this.colObj.appendChild(this.colTable);
+        
+        this.rowObj = new Element('div', {'class':'jxGridContainer'});
+        this.rowTable = new Element('table', {'class':'jxGridTable'});
+        this.rowTableHead = new Element('thead');
+        this.rowTable.appendChild(this.rowTableHead);
+        this.rowObj.appendChild(this.rowTable);
+        
+        this.gridObj = new Element('div', {'class':'jxGridContainer',styles:{overflow:'scroll'}});
+        this.gridTable = new Element('table', {'class':'jxGridTable'});
+        this.gridTableBody = new Element('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.gridObj.addEvent('scroll', this.onScroll.bind(this));
+        this.gridObj.addEvent('click', this.onClickGrid.bindWithEvent(this));
+        this.rowObj.addEvent('click', this.onClickRowHeader.bindWithEvent(this));
+        this.colObj.addEvent('click', this.onClickColumnHeader.bindWithEvent(this));
+        this.gridObj.addEvent('mousemove', this.onMouseMoveGrid.bindWithEvent(this));
+        this.rowObj.addEvent('mousemove', this.onMouseMoveRowHeader.bindWithEvent(this));
+        this.colObj.addEvent('mousemove', this.onMouseMoveColumnHeader.bindWithEvent(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: 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.options.columnHeaders ? this.model.getColumnHeaderHeight() : 1;
+        var rowWidth = this.options.rowHeaders ? this.model.getRowHeaderWidth() : 1;
+        
+        var size = Element.getContentBoxSize(this.domObj);
+        
+        /* -1 because of the right/bottom borders */
+        this.rowColObj.setStyles({
+            width: rowWidth-1, 
+            height: colHeight-1
+        });
+        this.rowObj.setStyles({
+            top:colHeight,
+            left:0,
+            width:rowWidth-1,
+            height:size.height-colHeight-1
+        });
+
+        this.colObj.setStyles({
+            top: 0,
+            left: rowWidth,
+            width: size.width - rowWidth - 1,
+            height: colHeight - 1
+        });
+
+        this.gridObj.setStyles({
+            top: colHeight,
+            left: rowWidth,
+            width: size.width - rowWidth - 1,
+            height: size.height - colHeight - 1 
+        });
+    },
+    
+    /**
+     * 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) {
+            if (this.domObj.resize) {
+                this.domObj.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.options.columnHeaders) {
+                var colHeight = model.getColumnHeaderHeight();
+                var trHead = new Element('tr');
+                this.colTableHead.appendChild(trHead);
+                var trBody = new Element('tr');
+                this.colTableBody.appendChild(trBody);
+                
+                var th = new Element('th', {styles:{width:0,height:0}});
+                trHead.appendChild(th);
+                th = th.cloneNode(true);
+                th.setStyle('height',colHeight);
+                trBody.appendChild(th);
+                for (var i=0; i<nColumns; i++) {
+                    var colWidth = model.getColumnWidth(i);
+                    th = new Element('th', {'class':'jxGridColHeadHide',styles:{width:colWidth}});
+                    var p = new Element('p', {styles:{height:0,width:colWidth}});
+                    th.appendChild(p);
+                    trHead.appendChild(th);
+                    th = new Element('th', {
+                        'class':'jxGridColHead', 
+                        html:model.getColumnHeaderHTML(i)
+                    });
+                    trBody.appendChild(th);
+                }
+                /* one extra column at the end for filler */
+                var th = new Element('th',{styles:{width:1000,height:0}});
+                trHead.appendChild(th);
+                th = th.cloneNode(true);
+                th.setStyle('height',colHeight - 1);
+                th.className = 'jxGridColHead';
+                trBody.appendChild(th);
+                
+            }
+            
+            if (this.options.rowHeaders) {
+                var rowWidth = model.getRowHeaderWidth();
+                var tr = new Element('tr');
+                var td = new Element('td', {styles:{width:0,height:0}});
+                tr.appendChild(td);
+                var th = new Element('th', {styles:{width:rowWidth,height:0}});
+                tr.appendChild(th);
+                this.rowTableHead.appendChild(tr);
+                for (var i=0; i<nRows; i++) {
+                    var rowHeight = model.getRowHeight(i);
+                    var tr = new Element('tr');
+                    var td = new Element('td', {'class':'jxGridRowHeadHide', styles:{width:0,height:rowHeight}});
+                    var p = new Element('p', {styles:{width:0,height:rowHeight}});
+                    td.appendChild(p);
+                    tr.appendChild(td);
+                    var th = new Element('th', {'class':'jxGridRowHead', html:model.getRowHeaderHTML(i)});
+                    tr.appendChild(th);
+                    this.rowTableHead.appendChild(tr);
+                }
+                /* one extra row at the end for filler */
+                var tr = new Element('tr');
+                var td = new Element('td',{
+                    styles:{
+                        width:0,
+                        height:1000
+                    }
+                });
+                tr.appendChild(td);
+                var th = new Element('th',{
+                    'class':'jxGridRowHead',
+                    styles:{
+                        width:rowWidth,
+                        height:1000
+                    }
+                });
+                tr.appendChild(th);
+                this.rowTableHead.appendChild(tr);
+            }
+            
+            var colHeight = model.getColumnHeaderHeight();
+            var trBody = new Element('tr');
+            this.gridTableBody.appendChild(trBody);
+            
+            var td = new Element('td', {styles:{width:0,height:0}});
+            trBody.appendChild(td);
+            for (var i=0; i<nColumns; i++) {
+                var colWidth = model.getColumnWidth(i);
+                td = new Element('td', {'class':'jxGridColHeadHide', styles:{width:colWidth}});
+                var p = new Element('p', {styles:{width:colWidth,height:0}});
+                td.appendChild(p);
+                trBody.appendChild(td);
+            }
+            
+            for (var j=0; j<nRows; j++) {
+                var rowHeight = model.getRowHeight(j);
+                var actualRowHeight = rowHeight;
+                var tr = new Element('tr');
+                this.gridTableBody.appendChild(tr);
+                
+                var td = new Element('td', {
+                    'class':'jxGridRowHeadHide',
+                    styles: {
+                        width: 0,
+                        height:rowHeight
+                    }
+                });
+                var p = new Element('p',{styles:{height:rowHeight}});
+                td.appendChild(p);
+                tr.appendChild(td);
+                for (var i=0; i<nColumns; i++) {
+                    var colWidth = model.getColumnWidth(i);
+                    td = new Element('td', {'class':'jxGridCell'});
+                    td.innerHTML = model.getValueAt(j,i);
+                    tr.appendChild(td);
+                    var tdSize = td.getSize();
+                    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.options.rowHeaders) {
+                    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.options.alternateRowColors) {
+                    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) {
+                this.prelitRowHeader.removeClass('jxGridRowHeaderPrelight');
+            }
+            this.prelitRowHeader = cell;
+            if (this.prelitRowHeader) {
+                this.prelitRowHeader.addClass('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) {
+                this.prelitColumnHeader.removeClass('jxGridColumnHeaderPrelight');
+            }
+            this.prelitColumnHeader = cell;
+            if (this.prelitColumnHeader) {
+                this.prelitColumnHeader.addClass('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) {
+                this.prelitRow.removeClass('jxGridRowPrelight');
+            }
+            this.prelitRow = tr;
+            if (this.prelitRow && !this.prelitRow.hasClass('jxGridRowSelected')) {
+                this.prelightRowHeader(row);
+                this.prelitRow.addClass('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) {
+                this.prelitCell.removeClass('jxGridCellPrelight');
+            }
+            this.prelitCell = td;
+            if (this.prelitCell) {
+                this.prelitCell.addClass('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) {
+             this.selectedCell.addClass('jxGridCellSelected');
+         } else {
+             this.selectedCell.removeClass('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) {
+            cell.addClass('jxGridRowHeaderSelected');
+        } else {
+            cell.removeClass('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) {
+                tr.addClass('jxGridRowSelected');
+            } else {
+                tr.removeClass('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) {
+            cell.addClass('jxGridColumnHeaderSelected');
+        } else {
+            cell.removeClass('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++) {
+                    this.gridTable.rows[i].cells[this.selectedColumn + 1].removeClass('jxGridColumnSelected');
+                }
+            } else {
+                for (var i=0; i<this.gridTable.rows.length; i++) {
+                    this.gridTable.rows[i].cells[col+1].addClass('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 = e.target;
+        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: layout.js 746 2008-08-16 00:30:25Z pspencer $
+/**
+ * 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.
+ *
+ * Example:
+ * (code)
+ * var myContainer = new Jx.Layout('myDiv', options);
+ * (end)
+ *
+ * Events:
+ * sizeChange - fired when the size of the container changes
+ *
+ * Implements:
+ * Options - MooTools Class.Extras
+ * Events - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+ 
+Jx.Layout = new Class({
+    Implements: [Options,Events],
+    
+    options: {
+        propagate: true,
+        position: 'absolute',
+        left: 0,
+        right: 0,
+        top: 0,
+        bottom: 0,
+        width: null,
+        height: null,
+        minWidth: 0,
+        minHeight: 0,
+        maxWidth: -1,
+        maxHeight: -1
+    },
+    /**
+     * 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:
+     * propagate - boolean, controls propogation of resize to child nodes.
+     *    True by default. If set to false, changes in size will not be
+     *    propogated to child nodes.
+     * 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) {
+        this.setOptions(options);
+        this.domObj = $(domObj);
+        this.domObj.resize = this.resize.bind(this);
+        this.domObj.setStyle('position', this.options.position);
+        this.domObj.store('jxLayout', this);
+
+        if (document.body == this.domObj.parentNode) {
+            window.addEvent('resize', this.windowResize.bindWithEvent(this));
+            window.addEvent('load', this.resize.bind(this));                
+        }
+        //this.resize();
+    },
+    
+    /**
+     * 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) {
+             $clear(this.resizeTimer);
+             this.resizeTimer = null;
+         }
+         this.resizeTimer = this.resize.delay(100, this);
+    },
+    
+    /**
+     * Method: resize
+     * resize the element controlled by this Jx.Layout object.
+     *
+     * Parameters:
+     * options - new options to apply, see <Jx.Layout::Jx.Layout>
+     */
+    resize: function(options) {
+         /* this looks like a really big function but actually not
+          * much code gets executed in the two big if statements
+          */
+        this.resizeTimer = null;
+        var needsResize = false;
+        if (options) {
+            for (var i in options) {
+                //prevent forceResize: false from causing a resize
+                if (i == 'forceResize') {
+                    continue;
+                }
+                if (this.options[i] != options[i]) {
+                    needsResize = true;
+                    this.options[i] = options[i];
+                }
+            }
+            if (options.forceResize) {
+                needsResize = true;
+            }
+        }
+        if (!$(this.domObj.parentNode)) {
+            return;
+        }
+        
+        var parentSize;
+        if (this.domObj.parentNode.tagName == 'BODY') {
+            parentSize = Element.getPageDimensions();
+        } else {
+            parentSize = $(this.domObj.parentNode).getContentBoxSize();
+        }
+    
+        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) {
+                    /* 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 {
+                    /* variable right, fixed width
+                     * use width
+                     */
+                    w = this.options.width;
+                }
+            } else {
+                /* fixed right */
+                if (this.options.width == null) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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) {
+                    /* 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 {
+                    /* 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;
+                    }
+                }
+            }
+        }
+        
+        //TODO: check left, top, width, height against current styles
+        // and only apply changes if they are not the same.
+        
+        /* apply the new sizes */
+        var sizeOpts = {width: w};
+        if (this.options.position == 'absolute') {
+            var padding = $(this.domObj.parentNode).getPaddingSize();
+            this.domObj.setStyles({
+                position: this.options.position,
+                left: l+padding.left,
+                top: t+padding.top
+            });
+            sizeOpts.height = h;
+        } else {
+            if (this.options.height) {
+                sizeOpts.height = this.options.height;
+            }
+        }
+        this.domObj.setBorderBoxSize(sizeOpts);
+        
+        if (this.options.propagate) {
+            // propogate changes to children
+            var o = {forceResize: options ? options.forceResize : false};
+            $A(this.domObj.childNodes).each(function(child){
+                if (child.resize && child.getStyle('display') != 'none') {
+                    child.resize(o);                
+                }
+            });
+            
+        }
+
+        this.fireEvent('sizeChange',this);
+    }
+});// $Id: menu.js 782 2008-08-26 17:36:11Z pspencer $
+/**
+ * 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.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Menu = new Class({
+    Implements: [Jx.AutoPosition, Jx.Chrome],
+    /**
+     * Property: domObj
+     * {HTMLElement} The HTML element containing the menu.
+     */
+    domObj : null,
+    /**
+     * Property: button
+     * {<Jx.Button>} The button that represents this menu in a toolbar and
+     * opens the menu.
+     */
+    button : 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,
+    /**
+     * 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) {
+        /* */
+        if (!Jx.Menu.Menus) {
+            Jx.Menu.Menus = [];
+        }
+        /* stores menu items and sub menus */
+        this.items = [];
+        
+        this.contentContainer = new Element('div',{
+            'class':'jxMenuContainer'
+        });
+        
+        /* the DOM element that holds the actual menu */
+        this.subDomObj = new Element('ul',{
+            'class':'jxMenu'
+        });
+        
+        this.contentContainer.adopt(this.subDomObj);
+        
+        /* if options are passed, make a button inside an LI so the
+           menu can be embedded inside a toolbar */
+        if (options) {
+            this.domObj = new Element('li',{
+                id: options.id,                
+                events: {
+                    'mouseover': this.onMouseOver.bindWithEvent(this)
+                }
+            });
+            
+            this.button = new Jx.Button($merge(options,{
+                onClick:this.show.bind(this)
+            }));
+            this.button.domA.addClass('jxButtonMenu');
+            
+            this.domObj.adopt(this.button.domObj);
+
+        }
+        
+        /* pre-bind the hide function for efficiency */
+        this.hideWatcher = this.hide.bindWithEvent(this);
+        this.keypressWatcher = this.keypressHandler.bindWithEvent(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() {
+        $A(arguments).each(function(item){
+            this.items.push(item);
+            item.setOwner(this);
+            this.subDomObj.adopt(item.domObj);
+        }, this);
+    },
+    /**
+     * 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 (Jx.Menu.Menus[0] && Jx.Menu.Menus[0] != this) {
+            this.show({event:e});
+        }
+    },
+    /**
+     * Method: hide
+     * Hide the menu.
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    hide: function(e) {
+        if (e) {
+            if (e.target.descendantOf(this.domObj) ||
+                e.target.descendantOf(this.subDomObj)) {
+                return;
+            }
+        }
+        if (Jx.Menu.Menus[0] && Jx.Menu.Menus[0] == this) {
+            Jx.Menu.Menus[0] = null;
+        }
+        if (this.domA) {
+            this.domA.removeClass('jx'+this.button.options.type+'Active');            
+        }
+        this.contentContainer.dispose();
+        this.items.each(function(item){item.hide(e);});
+        document.removeEvent('mousedown', this.hideWatcher);
+        document.removeEvent('keyup', this.keypressWatcher);    
+    },
+    /**
+     * Method: show
+     * Show the menu
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    show : function(o) {
+        var e = o.event;
+        if (Jx.Menu.Menus[0] && Jx.Menu.Menus[0] != this) {
+            Jx.Menu.Menus[0].hide(e);
+        }
+        if (this.items.length ==0) {
+            return;
+        }
+        Jx.Menu.Menus[0] = this;
+        
+        this.contentContainer.setStyle('visibility','hidden');
+        document.body.adopt(this.contentContainer);            
+        /* we have to size the container for IE to render the chrome correctly
+         * but just in the menu/sub menu case - there is some horrible peekaboo
+         * bug in IE related to ULs that we just couldn't figure out
+         */
+        this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());
+        this.showChrome(this.contentContainer);
+        
+        this.position(this.contentContainer, this.button.domObj, {
+            horizontal: ['left left'],
+            vertical: ['bottom top', 'top bottom'],
+            offsets: this.chromeOffsets
+        });
+
+        this.contentContainer.setStyle('visibility','');
+        
+        if (this.domA) {
+            this.domA.addClass('jx'+this.button.options.type+'Active');            
+        }
+        if (e) {
+            e.stop();
+        }
+        /* fix bug in IE that closes the menu as it opens because of bubbling */
+        document.addEvent('mousedown', this.hideWatcher);
+        document.addEvent('keyup', this.keypressWatcher);
+        
+    },
+    /**
+     * 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();
+        }
+    },
+
+    /* hide flyout if the user presses the ESC key */
+    keypressHandler: function(e) {
+        e = new Event(e);
+        if (e.key == 'esc') {
+            this.hide();
+        }
+    }
+});
+
+// $Id: menu.item.js 777 2008-08-25 15:20:23Z pspencer $
+/**
+ * Class: Jx.Menu.Item
+ * 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 emits an event.
+ *
+ * Jx.Menu.Item is represented by a <Jx.Button> with type MenuItem and the
+ * associated CSS changes noted in <Jx.Button>.  The container of a MenuItem
+ * is an 'li' element.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * click - fired when the menu item is clicked.
+ *
+ * Implements:
+ * Options - MooTools Class.Extras
+ * Events - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Menu.Item = new Class({
+    Implements: [Options, Events],
+    Extends: Jx.Button,
+    /**
+     * Property: owner
+     * {<Jx.SubMenu> or <Jx.Menu>} the menu that contains the menu item.
+     */
+    owner: null,
+    /**
+     * Property: button
+     * {<Jx.Button>} the clickable part of the menu item is managed as a
+     * <Jx.Button>
+     */
+    button: null,
+    options: {
+        enabled: true,
+        image: Jx.baseURL + 'images/a_pixel.png',
+        label: '&nbsp;'
+    },
+    /**
+     * Constructor: Jx.Menu.Item
+     * Create a new instance of Jx.Menu.Item
+     *
+     * Parameters:
+     * options - {Object} an object containing options as below.
+     * 
+     * Options:
+     * enabled - {Boolean} whether the menu item starts enabled or not (default true)
+     *
+     * See <Jx.Button> for other options
+     */
+    initialize: function(options) {
+        this.parent($merge(options, {
+            container:'li',
+            type:'MenuItem'
+        }));
+        this.domObj.addEvent('mouseover', this.onMouseOver.bindWithEvent(this));
+        if (!this.options.enabled) {
+            this.domObj.addClass('jxMenuItemDisabled');
+        }
+    },
+    /**
+     * Method: setOwner
+     * Set the owner of this menu item
+     *
+     * Parameters:
+     * obj - {Object} the new owner
+     */
+    setOwner: function(obj) {
+        this.owner = obj;
+    },
+    /**
+     * Method: hide
+     * Hide the menu item.
+     */
+    hide: $empty,
+    /**
+     * Method: show
+     * Show the menu item
+     */
+    show: $empty,
+    clicked: function(o) {
+        if (this.options.enabled) {
+            if (this.options.toggle) {
+                this.setActive(!this.options.isActive);
+            }
+            this.fireEvent('click', this);
+            if (this.owner && this.owner.deactivate) {
+                this.owner.deactivate(o.event);
+            }
+        }
+    },
+    /**
+     * 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.options.enabled = obj.isEnabled();
+        if (this.options.enabled) {
+            this.domObj.removeClass('jxMenuItemDisabled' );
+        } else {
+            if (!this.domObj.hadClass('jxMenuItemDisabled')) {
+                this.domObj.addClass('jxMenuItemDisabled' );                
+            }
+        }
+    },
+    /**
+     * Method: onmouseover
+     * handle the mouse moving over the menu item
+     *
+     * Parameters:
+     * e - {Event} the mousemove event
+     */
+    onMouseOver: function(e) {
+        if (this.owner && this.owner.setVisibleItem) {
+            this.owner.setVisibleItem(this);
+        }
+        this.show(e);
+    }
+});
+
+// $Id: menu.separator.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Menu.Separator
+ * A convenience class to create a visual separator in a menu.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Menu.Separator = new Class({
+    /**
+     * Property: domObj
+     * {HTMLElement} the HTML element that the separator is contained
+     * within
+     */
+    domObj: null,
+    /**
+     * Property: owner
+     * {<Jx.Menu>, <Jx.Menu.SubMenu>} the menu that the separator is in.
+     */
+    owner: null,
+    /**
+     * Constructor: Jx.Menu.Separator
+     * Create a new instance of a menu separator
+     */
+    initialize: function() {
+        this.domObj = new Element('li',{'class':'jxMenuItem'});
+        var span = new Element('span', {'class':'jxMenuSeparator','html':'&nbsp;'});
+        this.domObj.appendChild(span);
+    },
+    /**
+     * Method: setOwner
+     * Set the ownder of this menu item
+     *
+     * Parameters:
+     * obj - {Object} the new owner
+     */
+    setOwner: function(obj) {
+        this.owner = obj;
+    },
+    /**
+     * Method: hide
+     * Hide the menu item.
+     */
+    hide: $empty,
+    /**
+     * Method: show
+     * Show the menu item
+     */
+    show: $empty
+});// $Id: menu.submenu.js 782 2008-08-26 17:36:11Z pspencer $
+/**
+ * Class: Jx.Menu.SubMenu
+ * A sub menu contains menu items within a main menu or another
+ * sub menu.
+ *
+ * The structure of a SubMenu is the same as a <Jx.Menu.Item> with
+ * an additional unordered list element appended to the container.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Extends:
+ * <Jx.Menu.Item>
+ *
+ * Implements:
+ * Options - MooTools Class.Extra
+ * Events - MooTools Class.Extra
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Menu.SubMenu = new Class({
+    Extends: Jx.Menu.Item,
+    Implements: [Options, Events, Jx.AutoPosition, Jx.Chrome],
+    /**
+     * Property: subDomObj
+     * {HTMLElement} the HTML container for the sub menu.
+     */
+    subDomObj: null,
+    /**
+     * Property: owner
+     * {<Jx.Menu> or <Jx.SubMenu>} the menu or sub menu that this sub menu
+     * belongs
+     */
+    owner: 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.parent(options);
+        this.domA.addClass('jxButtonSubMenu');
+        
+        this.contentContainer = new Element('div', {
+            'class': 'jxMenuContainer'
+        });
+        this.subDomObj = new Element('ul', {
+            'class':'jxSubMenu'
+        });
+        this.contentContainer.adopt(this.subDomObj);
+    },
+    /**
+     * Method: setOwner
+     * Set the owner of this sub menu
+     *
+     * Parameters:
+     * obj - {Object} the owner
+     */
+    setOwner: function(obj) {
+        this.owner = obj;
+    },
+    /**
+     * Method: show
+     * Show the sub menu
+     */
+    show: function() {
+        if (this.open || this.items.length == 0) {
+            return;
+        }
+        
+        this.contentContainer.setStyle('visibility','hidden');
+        document.body.adopt(this.contentContainer);            
+        /* we have to size the container for IE to render the chrome correctly
+         * but just in the menu/sub menu case - there is some horrible peekaboo
+         * bug in IE related to ULs that we just couldn't figure out
+         */
+        this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());
+        this.showChrome(this.contentContainer);
+        
+        this.position(this.contentContainer, this.domObj, {
+            horizontal: ['right left', 'left right'],
+            vertical: ['top top'],
+            offsets: this.chromeOffsets
+        });
+        
+        this.open = true;
+        this.contentContainer.setStyle('visibility','');
+        
+        this.setActive(true);
+    },
+    /**
+     * Method: hide
+     * Hide the sub menu
+     */
+    hide: function() {
+        if (!this.open) {
+            return;
+        }
+        this.open = false;
+        this.items.each(function(item){item.hide();});
+        this.contentContainer.dispose();
+        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 */
+        var that = this;
+        $A(arguments).each(function(item){
+            that.items.push(item);
+            item.setOwner(that);
+            that.subDomObj.adopt(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 owner by showing or hiding
+     * the sub menu.
+     */
+    processActionEvent: function(e) { 
+        if (this.open) { 
+            this.hide(); 
+        } else { 
+            this.show();
+        }
+        if (e && e.event) {
+            e.event.stop();
+        }
+    },
+    /**
+     * Method: deactivate
+     * Deactivate the sub menu
+     *
+     * Parameters:
+     * e - {Event} the event that triggered the menu being
+     * deactivated.
+     */
+    deactivate: function(e) {
+        if (this.owner) {
+            this.owner.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.owner) {
+            return this.owner.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.owner && this.owner.setActive) {
+            this.owner.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();
+        }
+    }
+});// $Id: menu.context.js 788 2008-08-27 15:07:01Z pspencer $
+/**
+ * Class: Jx.Menu.Context
+ * A <Jx.Menu> that has no button but can be opened at a specific 
+ * browser location to implement context menus (for instance).
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * TODO - add open/close events?
+ *
+ * Extends:
+ * <Jx.Menu>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Menu.Context = new Class({
+    Extends: Jx.Menu,
+    /**
+     * 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) {
+        this.parent();
+        if ($(id)) {
+            $(id).addEvent('contextmenu', this.show.bindWithEvent(this));
+        }
+    },
+    /**
+     * Method: show
+     * Show the context menu at the location of the mouse click
+     *
+     * Parameters:
+     * e - {Event} the mouse event
+     */
+    show : function(e) {
+        if (this.items.length ==0) {
+            return;
+        }
+        
+        this.contentContainer.setStyle('visibility','hidden');
+        document.body.adopt(this.contentContainer);            
+        /* we have to size the container for IE to render the chrome correctly
+         * but just in the menu/sub menu case - there is some horrible peekaboo
+         * bug in IE related to ULs that we just couldn't figure out
+         */
+        this.contentContainer.setContentBoxSize(this.subDomObj.getMarginBoxSize());
+        
+        this.position(this.contentContainer, document.body, {
+            horizontal: [e.page.x + ' left'],
+            vertical: [e.page.y + ' top', e.page.y + ' bottom'],
+            offsets: this.chromeOffsets
+        });
+
+        this.contentContainer.setStyle('visibility','');
+        this.showChrome(this.contentContainer);
+                
+        document.addEvent('mousedown', this.hideWatcher);
+        document.addEvent('keyup', this.keypressWatcher);
+
+        e.stop();
+    }    
+});// $Id: panel.js 780 2008-08-26 14:54:47Z pspencer $
+/**
+ * Class: Jx.Panel
+ * A panel is a fundamental container object that has a content
+ * area and optional toolbars around the content area.  It also
+ * has a title bar area that contains an optional label and
+ * some user controls as determined by the options passed to the
+ * constructor.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * close - fired when the panel is closed
+ * collapse - fired when the panel is collapsed
+ * expand - fired when the panel is opened
+ *
+ * Implements:
+ * * <Jx.UniqueId>
+ * * <Jx.ContentLoader>
+ * * Options
+ * * Events
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Panel = new Class({
+    Implements: [Options, Events, Jx.UniqueId, Jx.ContentLoader],
+    
+    toolbarContainers: {
+        top: null,
+        right: null,
+        bottom: null,
+        left: null
+    },
+    
+    options: {
+        label: '&nbsp;',
+        imageBaseUrl: Jx.baseURL + 'images/',
+        position: 'absolute',
+        height: null,
+        collapse: true,
+        detach: false,
+        close: false,
+        closed: false,
+        hideTitle: false,
+        type: 'Panel'
+    },
+    
+    /** 
+     * Constructor: Jx.Panel
+     * Initialize a new Jx.Panel instance
+     *
+     * Options:
+     *
+     * id - String, an id to assign to the panel's container
+     * label - String, the title of the Jx Panel
+     * hideTitle - Boolean, hide the title bar if true.  False by default.
+     * toolbars - array of Jx.Toolbar objects to put in the panel.  The position
+     *     of each toolbar is used to position the toolbar within the panel.
+     * 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
+     * collapse - boolean, determine if the panel can be collapsed and expanded
+     *     by the user.  This puts a control into the title bar for the user
+     *     to control the state of the panel.
+     * detach - boolean, determine if the panel can be turned into a dialog 
+     *     by the user.  If a panel is floated as a dialog, it can be docked back
+     *     to where it came from.  This option puts a control in the title bar
+     *     of the panel.
+     * close - boolean, determine if the panel can be closed (hidden) by the user.
+     *     The application needs to provide a way to re-open the panel after it is
+     *     closed.  The closeable property extends to dialogs created by floating
+     *     panels.  This option puts a control in the title bar of the panel.
+     * closed - boolean, initial state of the panel (true to start the panel
+           closed), default is false
+     * content options - See <Jx.ContentLoader::loadContent> for content related
+     *     options.
+     * layout options - See <Jx.Layout::Jx.Layout> for layout related options.
+     *     The default layout is to use height: null which causes the panel to
+     *     fill its container (and resize if the container is a <Jx.Layout>
+     *     controlled object).  If you specify a height then the panel will
+     *     occupy only that much space vertically and will fill the 
+     *     container's width (using the relative option in <Jx.Layout>).
+     *
+     * Inherits From:
+     * <Jx.UniqueId>, <Jx.ContentLoader>
+     */
+    initialize : function(options){
+        this.toolbars = options.toolbars || [];
+        this.setOptions(options);
+        if ($defined(this.options.height) && !$defined(options.position)) {
+            this.options.position = 'relative';
+        }
+        this.initUniqueId();
+        
+        /* set up the title object */
+        this.title = new Element('div', {
+            'class': 'jx'+this.options.type+'Title'
+        });
+        
+        this.labelObj = new Element('span', {
+            'class': 'jx'+this.options.type+'Label',
+            html: this.options.label
+        });
+        this.title.adopt(this.labelObj);
+        
+        var controls = new Element('div', {
+            'class': 'jx'+this.options.type+'Controls'
+        });
+        var tbDiv = new Element('div');
+        controls.adopt(tbDiv);
+        this.toolbar = new Jx.Toolbar({parent:tbDiv});
+        this.title.adopt(controls);
+        
+        var that = this;
+        
+        if (this.options.menu) {
+            this.menu = new Jx.Menu({
+                image: Jx.baseURL + 'images/panel_controls.png'
+            });
+            this.menu.domObj.addClass('jx'+this.options.type+'Menu');
+            this.menu.domObj.addClass('jxButtonContentLeft');
+            this.toolbar.add(this.menu);
+        }
+        
+        if (this.options.collapse) {
+            var b = new Jx.Button({
+                image: Jx.baseURL + 'images/panel_controls.png',
+                tooltip: 'Collapse/Expand Panel',
+                onClick: function() {
+                    that.toggleCollapse();
+                }
+            });
+            b.domObj.addClass('jx'+this.options.type+'Collapse');
+            this.toolbar.add(b);
+            if (this.menu) {
+                var item = new Jx.Menu.Item({
+                    label: 'Collapse',
+                    onClick: function() { that.toggleCollapse(); }
+                });
+                var button = item.button;
+                this.addEvent('collapse', function() {
+                    if (that.options.closed) {
+                        button.setLabel('Expand');
+                    } else {
+                        button.setLabel('Collapse');
+                    }
+                });
+                this.menu.add(item);
+            }
+        }
+        
+        if (this.options.maximize) {
+            var b = new Jx.Button({
+                image: Jx.baseURL + 'images/panel_controls.png',
+                tooltip: 'Maximize Panel',
+                onClick: function() {
+                    that.maximize();
+                }
+            });
+            b.domObj.addClass('jx'+this.options.type+'Maximize');
+            this.toolbar.add(b);
+            if (this.menu) {
+                var item = new Jx.Menu.Item({
+                    label: 'Maximize',
+                    onClick: function() { that.maximize(); }
+                });
+                this.menu.add(item);
+            }
+        }
+        
+        if (this.options.close) {
+            var b = new Jx.Button({
+                image: Jx.baseURL + 'images/panel_controls.png',
+                tooltip: 'Close Panel',
+                onClick: function() {
+                    that.close();
+                }
+            });
+            b.domObj.addClass('jx'+this.options.type+'Close');
+            this.toolbar.add(b);
+            if (this.menu) {
+                var item = new Jx.Menu.Item({
+                    label: 'Close',
+                    onClick: function() {
+                        that.close();
+                    }
+                });
+                this.menu.add(item);
+            }
+            
+        }
+        
+        this.title.addEvent('dblclick', function() {
+            that.toggleCollapse();
+        });
+        
+        this.domObj = new Element('div', {
+            'class': 'jx'+this.options.type
+        });
+        if (this.options.id) {
+            this.domObj.id = this.options.id;
+        }
+        if ($(this.options.parent)) {
+            $(this.options.parent).adopt(this.domObj);
+        }
+        var jxl = new Jx.Layout(this.domObj, $merge(this.options, {propagate:false}));
+        var layoutHandler = this.layoutContent.bind(this);
+        jxl.addEvent('sizeChange', layoutHandler);
+        
+        if (!this.options.hideTitle) {
+            this.domObj.adopt(this.title);
+        }
+        
+        this.contentContainer = new Element('div', {
+            'class': 'jx'+this.options.type+'ContentContainer'
+        });
+        this.domObj.adopt(this.contentContainer);
+        
+        for (var i=0; i<this.toolbars.length; i++) {
+            var tb = this.toolbars[i];
+            tb.addEvent('add', layoutHandler);
+            tb.addEvent('remove', layoutHandler);
+            var position = tb.options.position;
+            var tbc = this.toolbarContainers[position];
+            if (!tbc) {
+                var tbc = new Element('div', {
+                    'class':'jxToolbarContainer '+'jxBar'+position.capitalize()
+                });
+                new Jx.Layout(tbc);
+                var clearer = new Element('div', {'class':'jxClearer'});
+                tbc.appendChild(clearer);
+                this.contentContainer.adopt(tbc);
+                this.toolbarContainers[position] = tbc;
+            }
+            var tbObj = tb.domObj;
+            tbc.insertBefore(tbObj, tbc.lastChild);
+        }
+        
+        this.content = new Element('div', {
+            'class': 'jx'+this.options.type+'Content'
+        });
+        
+        new Jx.Layout(this.contentContainer);
+        new Jx.Layout(this.content);
+        this.contentContainer.adopt(this.content);
+        this.loadContent(this.content, options);
+        
+        this.toggleCollapse(this.options.closed);
+    },
+    
+    layoutContent: function() {
+        var titleHeight = 0;
+        var top = 0;
+        var bottom = 0;
+        var left = 0;
+        var right = 0;
+        var tbc;
+        var tb;
+        var position;
+        if (!this.options.hideTitle && this.title.parentNode == this.domObj) {
+            titleHeight = this.title.getMarginBoxSize().height;
+        }
+        var domSize = this.domObj.getContentBoxSize();
+        if (domSize.height > titleHeight) {
+            this.contentContainer.setStyle('display','block');
+            this.options.closed = false;
+            this.contentContainer.resize({top: titleHeight, height: null, bottom: 0});
+            ['left','right'].each(function(position){
+                if (this.toolbarContainers[position]) {
+                    this.toolbarContainers[position].style.width = '';
+                }
+            }, this);
+            ['top','bottom'].each(function(position){
+                if (this.toolbarContainers[position]) {
+                    this.toolbarContainers[position].style.height = '';                
+                }
+            }, this);
+            for (var i=0; i<this.toolbars.length; i++) {
+                tb = this.toolbars[i];
+                position = tb.options.position;
+                tbc = this.toolbarContainers[position];
+                var size = tbc.getBorderBoxSize();
+                switch(position) {
+                    case 'top':
+                        top = size.height;
+                        break;
+                    case 'bottom':
+                        bottom = size.height;
+                        break;
+                    case 'left':
+                        left = size.width;
+                        break;
+                    case 'right':
+                        right = size.width;
+                        break;
+                }
+            
+            }
+            tbc = this.toolbarContainers['top'];
+            if (tbc) {
+                tbc.resize({top: 0, left: left, right: right, bottom: null, height: top, width: null});
+            }
+            tbc = this.toolbarContainers['bottom'];
+            if (tbc) {
+                tbc.resize({top: null, left: left, right: right, bottom: 0, height: bottom, width: null});
+            }
+            tbc = this.toolbarContainers['left'];
+            if (tbc) {
+                tbc.resize({top: top, left: 0, right: null, bottom: bottom, height: null, width: left});
+            }
+            tbc = this.toolbarContainers['right'];
+            if (tbc) {
+                tbc.resize({top: top, left: null, right: 0, bottom: bottom, height: null, width: right});
+            }
+            this.content.resize({top: top, bottom: bottom, left: left, right: right});
+        } else {
+            this.contentContainer.setStyle('display','none');
+            this.options.closed = true;
+        }
+    },
+    
+    /**
+     * 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 Request(url, opts).send();
+    },
+    /**
+     * 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: addTo
+     * adds the panel to a DOM element using appendChild if sibling
+     * is not specified or sibling's parent is not the specified parent,
+     * otherwise uses insertBefore.    
+     *
+     * Parameters:
+     * parent - {Object} the DOM element or id of a DOM element
+     * to append the panel to.
+     * sibling - {Object} the DOM element or id of a DOM element
+     * to insert the panel before.  If not specified, then the
+     * panel is appended to the parent.
+     */
+    addTo: function(parent, sibling) {
+        parent = $(parent);
+        sibling = sibling ? $(sibling) : null;
+        if (sibling && sibling.parentNode == parent) {
+            parent.insertBefore(this.domObj, sibling);
+        } else {
+            parent.appendChild(this.domObj);            
+        }
+        this.domObj.resize();
+    },
+    
+    /**
+     * Method: toggleCollapse
+     * sets or toggles the collapsed state of the panel.  If a
+     * new state is passed, it is used, otherwise the current
+     * state is toggled.    
+     *
+     * Parameters:
+     * state - optional, if passed then the state is used, 
+     * otherwise the state is toggled.
+     */
+    toggleCollapse: function(state) {
+        if ($defined(state)) {
+            this.options.closed = state;
+        } else {
+            this.options.closed = !this.options.closed;
+        }
+        if (this.options.closed) {
+            if (!this.domObj.hasClass('jx'+this.options.type+'Min')) {
+                this.domObj.addClass('jx'+this.options.type+'Min');
+                this.contentContainer.setStyle('display','none');
+                var margin = this.domObj.getMarginSize();
+                var height = margin.top + margin.bottom;
+                if (this.title.parentNode == this.domObj) {
+                    height += this.title.getMarginBoxSize().height;
+                }
+                this.domObj.resize({height: height});
+                this.fireEvent('collapse', this);
+            }
+        } else {
+            if (this.domObj.hasClass('jx'+this.options.type+'Min')) {
+                this.domObj.removeClass('jx'+this.options.type+'Min');
+                this.contentContainer.setStyle('display','block');
+                this.domObj.resize({height: this.options.height});            
+                this.fireEvent('expand', this);
+            }
+        }
+    },
+    
+    /**
+     * Method: close
+     * Closes the panel (completely hiding it).
+     */
+    close: function() {
+        this.domObj.dispose();
+        this.fireEvent('close', this);
+    }
+    
+});// $Id: dialog.js 782 2008-08-26 17:36:11Z pspencer $
+/**
+ * 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 movable (user can drag the title bar to move the dialog
+ * around)
+ *
+ * - dialogs may be a fixed size or allow user resizing.
+ *
+ * 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.
+ *
+ * Example:
+ * (code)
+ * var dialog = new Jx.Dialog();
+ * (end)
+ *
+ * Events:
+ * open - triggered when the dialog is opened
+ * close - triggered when the dialog is closed
+ * change - triggered when the value of an input in the dialog is changed
+ * resize - triggered when the dialog is resized
+ *
+ * Extends:
+ * <Jx.Panel>
+ *
+ * Implements:
+ * <Jx.AutoPosition>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Dialog = new Class({
+    Extends: Jx.Panel,
+    Implements: [Jx.AutoPosition, Jx.Chrome],
+    
+    /**
+     * 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,
+    
+    options: {
+        modal: true,
+        position: 'absolute',
+        width: 250,
+        height: 250,
+        left: 0,
+        top: 0,
+        bottom: null,
+        right: null,
+        label: 'New Dialog',
+        id: '',
+        parent: null,
+        resize: false,
+        move: true,
+        close: true,
+        collapse: true
+    },
+    /**
+     * Constructor: Jx.Dialog
+     * Construct a new instance of Jx.Dialog
+     *
+     * Parameters: 
+     * options - {Object} an object containing options for the dialog.
+     *
+     * Options:
+     * 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.
+     * label - (optional) {String} the title of the dialog box.  "New Dialog"
+     *      is the default value.
+     * content - (optional) {Mixed} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * contentURL - (optional) {String} passed to <Jx.ContentLoader> for loading
+     *      dialog content.
+     * id - (optional) {String} an HTML ID to assign to the dialog, primarily
+     *      used for applying CSS styles to specific dialogs
+     * parent - (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.
+     * resize - (optional) {Boolean} determines whether the dialog is
+     *      resizeable by the user or not.  Default is false.
+     * move - (optional) {Boolean} determines whether the dialog is
+     *      moveable by the user or not.  Default is true.
+     */
+    initialize: function(options) {
+        /* initialize class-wide singleton that holds the current z-order
+         * of all dialogs
+         */
+        if (!Jx.Dialog.Stack) {
+            Jx.Dialog.Stack = [];
+            Jx.Dialog.ZIndex = [100];
+        }
+        
+        this.isOpening = false;
+        
+        /* initialize the panel overriding the type and position */
+        this.parent($merge(
+            {parent:document.body}, // these are defaults that can be overridden
+            options,
+            {type:'Dialog', position: 'absolute'} // these override anything passed to the options
+        ));
+        this.options.parent = $(this.options.parent);
+        
+        if (!window.opera && this.options.modal) {
+            this.blanket = new Element('div',{
+                'class':'jxDialogModal',
+                styles:{
+                    display:'none',
+                    zIndex: -1
+                }
+            });
+        
+            this.options.parent.adopt(this.blanket);
+            (new Jx.Layout(this.blanket)).resize();
+        }
+
+        this.domObj.setStyle('display','none');
+        this.options.parent.adopt(this.domObj);
+        
+        /* the dialog is moveable by its title bar */
+        if (this.options.move) {
+            this.title.addClass('jxDialogMoveable');
+            new Drag(this.domObj, {
+                handle: this.title,
+                onStart: (function() {
+                    this.contentContainer.setStyle('visibility','hidden');
+                }).bind(this),
+                onComplete: (function() {
+                    this.contentContainer.setStyle('visibility','');
+                    this.position(this.domObj, this.options.parent, {
+                        horizontal:[parseInt(this.domObj.style.left)+' left'],
+                        vertical: [parseInt(this.domObj.style.top)+' top']
+                    });
+                    this.options.left = parseInt(this.domObj.style.left);
+                    this.options.top = parseInt(this.domObj.style.top);
+                    if (!this.options.closed) {
+                        this.domObj.resize(this.options);                        
+                    }
+                }).bind(this)
+            });            
+        }
+        
+        /* the dialog is resizeable */
+        if (this.options.resize) {
+            this.resizeHandle = new Element('div', {
+                'class':'jxDialogResize',
+                styles: {
+                    'display':this.options.closed?'none':'block'
+                }
+            });
+            this.domObj.appendChild(this.resizeHandle);
+
+            this.resizeHandleSize = this.resizeHandle.getSize(); 
+            this.resizeHandle.setStyles({
+                bottom: this.resizeHandleSize.height,
+                right: this.resizeHandleSize.width
+            });
+            this.domObj.makeResizable({
+                handle:this.resizeHandle,
+                onStart: (function() {
+                    this.contentContainer.setStyle('visibility','hidden');
+                }).bind(this),
+                onDrag: this.resizeChrome.bind(this),
+                onComplete: (function() {
+                    var size = this.domObj.getMarginBoxSize();
+                    this.options.width = size.width;
+                    this.options.height = size.height;
+                    this.layoutContent();
+                    this.domObj.resize(this.options);
+                    this.contentContainer.setStyle('visibility','');
+                    this.fireEvent('resize');
+                }).bind(this)
+            });
+        }
+        /* this adjusts the z-index of the dialogs when activated */
+        this.domObj.addEvent('mousedown', (function(){
+            Jx.Dialog.Stack.erase(this).push(this);
+            Jx.Dialog.Stack.each(function(d, i) {
+                d.domObj.setStyle('zIndex',101+i);
+            });
+        }).bind(this));
+    },
+    
+    /**
+     * Method: sizeChanged
+     * overload panel
+     */
+    sizeChanged: function() {
+        if (!this.options.closed) {
+            this.layoutContent();
+            this.resizeChrome();
+        }
+    },
+    
+    /**
+     * Method: toggleCollapse
+     * sets or toggles the collapsed state of the panel.  If a
+     * new state is passed, it is used, otherwise the current
+     * state is toggled.    
+     *
+     * Parameters:
+     * state - optional, if passed then the state is used, 
+     * otherwise the state is toggled.
+     */
+    toggleCollapse: function(state) {
+        if ($defined(state)) {
+            this.options.closed = state;
+        } else {
+            this.options.closed = !this.options.closed;
+        }
+        if (this.options.closed) {
+            if (!this.domObj.hasClass('jx'+this.options.type+'Min')) {
+                this.domObj.addClass('jx'+this.options.type+'Min');
+            }
+            this.contentContainer.setStyle('display','none');
+            if (this.resizeHandle) {
+                this.resizeHandle.setStyle('display','none');
+            }
+        } else {
+            if (this.domObj.hasClass('jx'+this.options.type+'Min')) {
+                this.domObj.removeClass('jx'+this.options.type+'Min');
+            }
+            this.contentContainer.setStyle('display','block');
+            if (this.resizeHandle) {
+                this.resizeHandle.setStyle('display','block');
+            }
+        }
+        
+        if (this.options.closed) {
+            var margin = this.domObj.getMarginSize();
+            var size = this.title.getMarginBoxSize();
+            this.domObj.resize({height: margin.top + size.height + margin.bottom});
+            this.fireEvent('collapse');
+        } else {
+            this.domObj.resize(this.options);
+            this.fireEvent('expand');
+        }
+    },
+    
+    /**
+     * 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: show
+     * show the dialog
+     */
+    show : function( ) {
+        
+        /* get the z-index right */
+        Jx.Dialog.Stack.push(this);
+        /* do the modal thing */
+        if (this.options.modal) {
+            this.blanket.setStyles({
+                zIndex: Jx.Dialog.ZIndex[0]++,
+                visibility: 'visible',
+                display: 'block'
+            });
+        }
+        /* display the dialog */
+        this.domObj.setStyles({
+            zIndex: Jx.Dialog.ZIndex[0]++,
+            display: 'block'
+        });
+        if (this.options.closed) {
+            var margin = this.domObj.getMarginSize();
+            var size = this.title.getMarginBoxSize();
+            this.domObj.resize({height: margin.top + size.height + margin.bottom});
+        } else {
+            this.domObj.resize(this.options);            
+        }
+        /* update or create the chrome */
+        this.showChrome(this.domObj);
+        /* put it in the right place using auto-positioning */
+        this.position(this.domObj, this.options.parent, {
+            horizontal: [this.options.left+' left'],
+            vertical: [this.options.top+' top']
+        });
+        this.options.left = parseInt(this.domObj.style.left);
+        this.options.top = parseInt(this.domObj.style.top);
+    },
+    /**
+     * Method: hide
+     * hide the dialog
+     */
+    hide : function() {
+        Jx.Dialog.Stack.erase(this);
+        Jx.Dialog.ZIndex[0]--;
+        this.domObj.setStyle('display','none');
+        if (this.options.modal) {
+            this.blanket.setStyle('visibility', 'hidden');
+            Jx.Dialog.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.isOpening) {
+            this.isOpening = true;
+        }
+        if (this.contentIsLoaded) {
+            this.show();
+            this.fireEvent('open', this);
+            this.isOpening = false;
+        }
+    },
+    /**
+     * Method: close
+     * close the dialog and trigger the onClose callback function
+     * if necessary
+     */
+    close: function() {
+        this.isOpening = false;
+        this.hide();
+        this.fireEvent('close');
+    },
+    /**
+     * Method: onContentLoaded
+     * 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.
+     */
+    onContentLoaded : function() {
+        if (this.isOpening) {
+            this.open();
+        }
+    }
+});
+// $Id: panelset.js 762 2008-08-20 20:59:40Z pspencer $
+/**
+ * Class: Jx.PanelSet
+ *
+ * Example:
+ * A panel set manages a set of panels within a DOM element.  The PanelSet fills
+ * its container by resizing the panels in the set to fill the width and then
+ * distributing the height of the container across all the panels.  Panels
+ * can be resized by dragging their respective title bars to make them taller
+ * or shorter.  The maximize button on the panel title will cause all other
+ * panels to be closed and the target panel to be expanded to fill the remaining
+ * space.  In this respect, PanelSet works like a traditional Accordion control.
+ *
+ * When creating panels for use within a panel set, it is important to use the
+ * proper options.  You must override the collapse option and set it to false
+ * and add a maximize option set to true.  You must also not include options
+ * for menu and close.
+ *
+ * (code)
+ * var p1 = new Jx.Panel({collapse: false, maximize: true, content: 'content1'});
+ * var p2 = new Jx.Panel({collapse: false, maximize: true, content: 'content2'});
+ * var p3 = new Jx.Panel({collapse: false, maximize: true, content: 'content3'});
+ * var panelSet = new Jx.PanelSet('panels', [p1,p2,p3]);
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.PanelSet = new Class({
+    /**
+     * Property: panels
+     * {Array} the panels being managed by the set
+     */
+    panels: null,
+    /**
+     * Property: height
+     * {Integer} the height of the container, cached for speed
+     */
+    height: null,
+    /**
+     * Property: firstLayout
+     * {Boolean} true until the panel set has first been resized
+     */
+    firstLayout: true,
+    /**
+     * Constructor: Jx.PanelSet
+     * Create a new instance of Jx.PanelSet.
+     *
+     * Parameters:
+     * domObj - {HTMLElement} the HTML element that will contain the panels
+     * panels - {Array} the panels to go into the PanelSet
+     *
+     * TODO: Jx.PanelSet.initialize
+     * Remove the panels parameter in favour of an add method.
+     */
+    initialize: function(domObj, panels) {
+        this.domObj = $(domObj);
+        this.panels = panels;
+        var d = new Element('div', {styles:{position:'absolute'}});
+        new Jx.Layout(d, {minHeight:0,maxHeight:0,height:0});
+        var elements = [d];
+        panels.each(function(panel){
+            elements.push(panel.domObj);
+            panel.options.hideTitle = true;
+            panel.contentContainer.resize({top:0});
+            panel.addEvent('expand', this.maximizePanel.bind(this, panel));
+            panel.domObj.store('Jx.Panel', panel);
+        }, this);
+        
+        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 set */
+        for (var i=0; i<this.panels.length; i++) {
+            var panel = this.panels[i];
+            var bar = this.splitter.bars[i];
+            panel.title.setStyle('visibility', 'hidden');
+            document.body.adopt(panel.title);
+            var size = panel.title.getBorderBoxSize();
+            bar.adopt(panel.title);
+            panel.title.setStyle('visibility','');
+            bar.setStyle('height', size.height);
+            bar.removeClass('jxSplitterBar');
+            bar.addClass('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 (this.panels[0].title.getBorderBoxSize().height != 0) {
+                for (var i=0; i<this.splitter.bars.length; i++) {
+                    var panel = this.panels[i];
+                    this.splitter.bars[i].style.height = panel.title.getBorderBoxSize().height + 'px';
+                    this.splitter.bars[i].store('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 = this.domObj.getContentBoxSize().height;
+        
+        var t = 0;
+        for (var i=1; i<this.splitter.elements.length; i++) {
+            var p = this.splitter.elements[i];
+            t += p.retrieve('leftBar').getBorderBoxSize().height;
+            if (p !== panel.domObj) {
+                var thePanel = p.retrieve('Jx.Panel');
+                var o = p.retrieve('jxLayout').options;
+                p.resize({top: t, height: o.minHeight, bottom: null});
+                t += o.minHeight;
+                p.retrieve('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) {
+                var o = p.retrieve('jxLayout').options;
+                b -= o.minHeight;
+                p.resize({top: b, height: o.minHeight, bottom: null});
+                b -= p.retrieve('leftBar').getBorderBoxSize().height;
+                p.retrieve('leftBar').style.top = b + 'px';
+                
+            } else {
+                break;
+            }
+        }
+        panel.domObj.resize({top: t, height:b - t, bottom: null});
+    }
+});// $Id: combo.js 751 2008-08-16 13:15:37Z pspencer $
+/**
+ * Class: Jx.Combo
+ * A drop down list of selectable items that can be any HTML.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * changed - the main item has changed
+ *
+ * Implements:
+ * * Options
+ * * Events
+ * * <Jx.AutoPosition>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Combo = new Class({
+    Implements: [Options,Events,Jx.AutoPosition],
+    /** 
+     * 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,
+    
+    /** 
+     * Constructor: Jx.Combo
+     * create a new instance of Jx.Combo
+     *
+     * Options:
+     * editable - {Boolean} defaults to false.  If true, then the selected item
+     * is editable.
+     */
+    initialize: function(options) {
+        this.setOptions(options);
+        
+        this.domObj = new Element('div',{
+            'class':'jxCombo'
+        });
+        if (this.options.id) {
+            this.domObj.id = this.options.id;
+        }
+        
+        if (this.options.editable) {
+            this.domInput = new Element('input',{
+                'class':'jxComboInput',
+                type:'text',
+                events:{
+                    change: this.valueChanged.bindWithEvent(this),
+                    keydown: this.onKeyPress.bindWithEvent(this)
+                }
+            });
+        } else {
+            this.domInput = new Element('span', {
+                'class':'jxComboInput'
+            });
+        }
+        
+        this.domObj.appendChild(this.domInput);
+        
+        this.domA = new Element('a',{
+            'class':'jxComboDiscloser',
+            href: 'javascript:void(0)',
+            events:{
+                click: this.toggle.bind(this)
+            }
+        });
+        
+        this.domButton = new Element('img', {
+            'class':'png24',
+            src: Jx.baseURL + 'images/disclose2.png'
+        });
+        this.domA.appendChild(this.domButton);
+        this.domObj.appendChild(this.domA);
+        
+        if (!window.opera) {
+            //insert iframeShim for IE to cover other controls in the page.
+            this.domObj.appendChild(Jx.createIframeShim());
+        }
+        
+        this.domListDiv = new Element('div',{
+            'class':'jxComboOptions'
+        });
+        this.domList = new Element('ul');
+        this.domListDiv.appendChild(this.domList);
+        
+        this.keypressHandler = this.keypress.bindWithEvent(this);
+        this.clickHandler = this.click.bindWithEvent(this);
+    },
+    
+    /**
+     * 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) {
+        if (e.key == 'enter') {
+            this.valueChanged();
+        }
+    },
+    
+    /**
+     * Method: valueChanged
+     * When the value is changed, propogate the change to the selection 
+     * listeners
+     */
+    valueChanged: function() {
+        this.fireEvent('changed', 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 = new Element('li');
+        var a = new Element('a', {
+            href: 'javascript:void(0)',
+            events: {
+                click: this.pick.bindWithEvent(this)
+            }
+        });
+        
+        if ($type(domObj) == 'string') {
+            a.innerHTML = domObj;
+        } else {
+            a.appendChild(domObj);
+        }
+        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 = e.target;
+        if (target.tagName == 'A') {
+            this.currentSelection = target;
+            this.setValue(this.currentSelection.childNodes[0]);
+            this.valueChanged();
+        }
+        this.close();
+    },
+    /**
+     * Method: setValue
+     * set the value of the Combo
+     *
+     * Parameters:
+     * value - {Object} the new value.  May be a string, a text node, or
+     * another DOM element.
+     */
+    setValue: function(value) {
+        if (this.options.editable) {
+            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 (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.options.editable) {
+            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 Combo
+     */
+    toggle: function() {
+        if (this.domListDiv.style.display == 'block') {
+            this.close();
+        } else {
+            this.open();
+        }
+    },
+    
+    /**
+     * Method: open
+     * Open the pick list
+     */
+    open: function() {
+        this.position(this.domListDiv, this.domObj, {
+            horizontal: ['left left', 'right right'],
+            vertical: ['bottom top', 'top bottom']
+        });
+        this.domListDiv.width = '';
+        this.domListDiv.setStyle('visibility','hidden');
+        document.body.adopt(this.domListDiv);
+        this.domListDiv.setBorderBoxSize({width: Math.max(this.domListDiv.getSize().x, this.domObj.getSize().x)});
+        this.domListDiv.setStyle('visibility','');
+        document.addEvents({
+            keydown:  this.keypressHandler,
+            click: this.clickHandler
+        });
+    },
+    /**
+     * 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) {
+        if (e.key == 'esc') {
+            this.close();
+        }
+    },
+    /**
+     * Method: click
+     * Handle the user clicking on the page, close the picker if it is not
+     * us that was clicked on
+     */
+    click: function(e) {
+        if (!e.target.descendantOf(this.domListDiv) && 
+            !e.target.descendantOf(this.domObj)) {
+            this.close();
+        }
+    },
+    /**
+     * Method: close
+     * Close the Combo.
+     */
+    close: function() {
+        this.domListDiv.dispose();
+        document.removeEvents({
+            keydown: this.keypressHandler,
+            click: this.clickHandler
+        });
+    },
+    /**
+     * Method: getSelection
+     * return the current selection
+     *
+     * Returns:
+     * {Object} the current selection or an empty string.
+     */
+    getSelection: function() {
+        return this.currentSelection ? this.currentSelection.name : '';
+    }
+});// $Id: splitter.js 775 2008-08-22 14:27:26Z pspencer $
+/**
+ * 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.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+ 
+Jx.Splitter = new Class({
+    Implements: [Options],
+    /**
+     * 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,
+    options: {
+        useChildren: false,
+        splitInto: 2,
+        elements: null,
+        containerOptions: [],
+        barOptions: [],
+        layout: 'horizontal',
+        snaps: []
+    },
+    /**
+     * 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:
+     * useChildren - {Boolean} if set to true, then the children of the
+     * element to be split are used as the elements.  The default value is
+     * false.  If this is set, then the elements and splitInto options
+     * are ignored.
+     * 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.
+     * barOptions - {Array} an array of object that provide options for the bars,
+     *      this array should be one less than the number of elements in the
+     *      splitter.  The barOptions objects can contain a snap property indicating
+     *      that a default snap object should be created in the bar and the value
+     *      of 'before' or 'after' indicates which element it snaps open/shut.
+     * layout - {String} either 'horizontal' or 'vertical', indicating the
+     *      direction in which the domObj is to be split.
+     * snaps - {Array} an array of objects which can be used to snap
+     *      elements open or closed.
+     */
+    initialize: function(domObj, options) {
+        this.setOptions(options);  
+        
+        this.domObj = $(domObj);
+        this.domObj.addClass('jxSplitContainer');
+        this.domObj.setStyle('overflow', 'hidden')
+        var jxLayout = this.domObj.retrieve('jxLayout');
+        if (jxLayout) {
+            jxLayout.addEvent('sizeChange', this.sizeChanged.bind(this));
+        }
+       
+        this.elements = [];
+        this.bars = [];
+        
+        var nSplits = 2;
+        if (this.options.useChildren) {
+            this.elements = this.domObj.getChildren();
+            nSplits = this.elements.length;
+        } else {
+            nSplits = this.options.elements ? 
+                            this.options.elements.length : 
+                            this.options.splitInto;
+            for (var i=0; i<nSplits; i++) {
+                var el;
+                if (this.options.elements && this.options.elements[i]) {
+                    el = $(this.options.elements[i]);
+                    if (!el) {
+                        el = this.prepareElement();
+                        el.id = this.options.elements[i];
+                    }
+                } else {
+                    el = this.prepareElement();
+                }
+                this.elements[i] = el;
+                this.domObj.adopt(this.elements[i]);
+            }
+        }
+        this.elements.each(function(el) { el.addClass('jxSplitArea'); });
+        for (var i=0; i<nSplits; i++) {
+            if (!this.elements[i].retrieve('jxLayout')) {
+                new Jx.Layout(this.elements[i], this.options.containerOptions[i]);
+            }
+        }
+        
+        for (var i=1; i<nSplits; i++) {
+            this.bars[i-1] = this.prepareBar();
+            this.bars[i-1].store('leftSide',this.elements[i-1]);
+            this.bars[i-1].store('rightSide', this.elements[i]);
+            this.elements[i-1].store('rightBar', this.bars[i-1]);
+            this.elements[i].store('leftBar', this.bars[i-1]);
+            this.domObj.adopt(this.bars[i-1]);
+        }
+
+        this.establishConstraints();
+        
+        for (var i=0; i<this.options.barOptions.length; i++) {
+            if (!this.bars[i]) {
+                continue;
+            }
+            var opt = this.options.barOptions[i];
+            if (opt && opt.snap && (opt.snap == 'before' || opt.snap == 'after')) {
+                var element;
+                if (opt.snap == 'before') {
+                    element = this.bars[i].retrieve('leftSide');
+                } else if (opt.snap == 'after') {
+                    element = this.bars[i].retrieve('rightSide');
+                }
+                var snap = new Element('a',{
+                    'class':'jxSnap'+this.options.layout.capitalize()+opt.snap.capitalize(),
+                    'href':'javascript:void(0)'
+                });
+                this.bars[i].adopt(snap);
+                new Jx.Splitter.Snap(snap, element, this);
+            }
+        }
+        
+        for (var i=0; i<this.options.snaps.length; i++) {
+            if (this.options.snaps[i]) {
+                new Jx.Splitter.Snap(this.options.snaps[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 = new Element('div', {styles:{position:'absolute'}});
+        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 = new Element('div', {
+            'class': 'jxSplitBar'+this.options.layout.capitalize(),
+            'title': 'drag this bar to resize'
+        });
+        o.store('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() {
+        var limit = {};
+        var fn;
+        if (this.options.layout == 'horizontal') {
+            limit.y = [0,0];
+            fn = this.dragHorizontal;
+        } else {
+            limit.x = [0,0];
+            fn = this.dragVertical;
+        }
+        this.bars.each(function(bar){
+            new Drag(bar, {
+                limit: limit,
+                onSnap : function(obj) {
+                    obj.addClass('jxSplitBarDrag');
+                },
+                onComplete : (function(obj) {
+                    obj.removeClass('jxSplitBarDrag');
+                    if (obj.retrieve('splitterObj') != this) {
+                        return;
+                    }
+                    fn.apply(this,[obj]);
+                }).bind(this)
+            });
+        }, this);
+    },
+    
+    /**
+     * 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:
+     * obj - {HTMLElement} the bar that was dragged
+     */
+    dragHorizontal: function(obj) {
+        var leftEdge = parseInt(obj.style.left);
+        var leftSide = obj.retrieve('leftSide');
+        var rightSide = obj.retrieve('rightSide');
+        var leftJxl = leftSide.retrieve('jxLayout');
+        var rightJxl = rightSide.retrieve('jxLayout');
+        
+        var paddingLeft = this.domObj.getPaddingSize().left;
+        
+        /* process right side first */
+        var rsLeft, rsWidth, rsRight;
+        
+        var size = obj.retrieve('size');
+        if (!size) {
+            size = obj.getBorderBoxSize();
+            obj.store('size',size);
+        }
+        rsLeft = leftEdge + size.width - paddingLeft;
+        
+        var parentSize = this.domObj.getContentBoxSize();
+        
+        if (rightJxl.options.width != null) {
+            rsWidth = rightJxl.options.width + rightJxl.options.left - rsLeft;
+            rsRight = parentSize.width - rsLeft - rsWidth;
+        } else {
+            rsWidth = parentSize.width - rightJxl.options.right - rsLeft;
+            rsRight = rightJxl.options.right;
+        }
+        
+        /* enforce constraints on right side */
+        if (rsWidth < 0) {
+            rsWidth = 0;
+        }
+        
+        if (rsWidth < rightJxl.options.minWidth) {
+            rsWidth = rightJxl.options.minWidth;
+        }
+        if (rightJxl.options.maxWidth >= 0 && rsWidth > rightJxl.options.maxWidth) {
+            rsWidth = rightJxl.options.maxWidth;
+        }
+                
+        rsLeft = parentSize.width - rsRight - rsWidth;
+        leftEdge = rsLeft - size.width;
+        
+        /* process left side */
+        var lsLeft, lsWidth;
+        lsLeft = leftJxl.options.left;
+        lsWidth = leftEdge - lsLeft;
+        
+        /* enforce constraints on left */
+        if (lsWidth < 0) {
+            lsWidth = 0;
+        }
+        if (lsWidth < leftJxl.options.minWidth) {
+            lsWidth = leftJxl.options.minWidth;
+        }
+        if (leftJxl.options.maxWidth >= 0 && 
+            lsWidth > leftJxl.options.maxWidth) {
+            lsWidth = leftJxl.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 + size.width - rsLeft;
+            rsLeft += delta;
+            rsWidth -= delta; 
+        }
+        
+        /* put bar in its final location based on constraints */
+        obj.style.left = paddingLeft + leftEdge + 'px';
+        
+        /* update leftSide positions */
+        if (leftJxl.options.width == null) {
+            var parentSize = this.domObj.getContentBoxSize();
+            leftSide.resize({right: parentSize.width - lsLeft-lsWidth});
+        } else {
+            leftSide.resize({width: lsWidth});
+        }
+        
+        /* update rightSide position */
+        if (rightJxl.options.width == null) {
+            rightSide.resize({left:rsLeft});
+        } else {
+            rightSide.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:
+     * obj - {HTMLElement} the bar that was dragged
+     */
+    dragVertical: function(obj) {
+        /* top edge of the bar */
+        var topEdge = parseInt(obj.style.top);
+        
+        /* the containers on either side of the bar */
+        var topSide = obj.retrieve('leftSide');
+        var bottomSide = obj.retrieve('rightSide');
+        var topJxl = topSide.retrieve('jxLayout');
+        var bottomJxl = bottomSide.retrieve('jxLayout');
+        
+        var paddingTop = this.domObj.getPaddingSize().top;
+        
+        /* measure the bar and parent container for later use */
+        var size = obj.retrieve('size');
+        if (!size) {
+            size = obj.getBorderBoxSize();
+            obj.store('size', size);
+        }
+        var parentSize = this.domObj.getContentBoxSize();
+
+        /* 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 + size.height - paddingTop;
+        
+        if (bottomJxl.options.height != null) {
+            /* bottom side height is fixed */
+            bsHeight = bottomJxl.options.height + bottomJxl.options.top - bsTop;
+            bsBottom = parentSize.height - bsTop - bsHeight;
+        } else {
+            /* bottom side height is not fixed. */
+            bsHeight = parentSize.height - bottomJxl.options.bottom - bsTop;
+            bsBottom = bottomJxl.options.bottom;
+        }
+        
+        /* enforce constraints on bottom side */
+        if (bsHeight < 0) {
+            bsHeight = 0;
+        }
+        
+        if (bsHeight < bottomJxl.options.minHeight) {
+            bsHeight = bottomJxl.options.minHeight;
+        }
+        
+        if (bottomJxl.options.maxHeight >= 0 && bsHeight > bottomJxl.options.maxHeight) {
+            bsHeight = bottomJxl.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 - size.height;
+                
+        /* process left side */
+        var tsTop, tsHeight;
+        tsTop = topJxl.options.top;
+        tsHeight = topEdge - tsTop;
+                        
+        /* enforce constraints on left */
+        if (tsHeight < 0) {
+            tsHeight = 0;
+        }
+        if (tsHeight < topJxl.options.minHeight) {
+            tsHeight = topJxl.options.minHeight;
+        }
+        if (topJxl.options.maxHeight >= 0 && 
+            tsHeight > topJxl.options.maxHeight) {
+            tsHeight = topJxl.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 + size.height - bsTop;
+            bsTop += delta;
+            bsHeight -= delta; 
+        }
+        
+        /* put bar in its final location based on constraints */
+        obj.style.top = paddingTop + topEdge + 'px';
+        
+        /* update topSide positions */
+        if (topJxl.options.height == null) {
+            topSide.resize({bottom: parentSize.height - tsTop-tsHeight});
+        } else {
+            topSide.resize({height: tsHeight});
+        }
+        
+        /* update bottomSide position */
+        if (bottomJxl.options.height == null) {
+            bottomSide.resize({top:bsTop});
+        } else {
+            bottomSide.resize({top: bsTop, height: bsHeight});
+        }
+    },
+    
+    /**
+     * Method: sizeChanged
+     * handle the size of the container being changed.
+     */
+    sizeChanged: function() {
+        if (this.options.layout == 'horizontal') {
+            this.horizontalResize();
+        } else {
+            this.verticalResize();
+        }
+    },
+    
+    /**
+     * Method: horizontalResize
+     * Resize a horizontally layed-out container
+     */
+    horizontalResize: function() {
+        var availableSpace = this.domObj.getContentBoxSize().width;
+        var overallWidth = availableSpace;
+
+        for (var i=0; i<this.bars.length; i++) {
+            var bar = this.bars[i];
+            var size = bar.retrieve('size');
+            if (!size || size.width == 0) {
+                size = bar.getBorderBoxSize();
+                bar.store('size',size);
+            }
+            availableSpace -= size.width;
+        }
+
+        var nVariable = 0;
+        var jxo;
+        for (var i=0; i<this.elements.length; i++) {
+            var e = this.elements[i];
+            jxo = e.retrieve('jxLayout').options;
+            if (jxo.width != null) {
+                availableSpace -= parseInt(jxo.width);
+            } else {
+                var w = 0;
+                if (jxo.right != 0 || 
+                    jxo.left != 0) {
+                    w = e.getBorderBoxSize().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 leftPadding = this.domObj.getPaddingSize().left;
+
+        var currentPosition = 0;
+
+        for (var i=0; i<this.elements.length; i++) {
+             var e = this.elements[i];
+             var jxl = e.retrieve('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 = e.getBorderBoxSize().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;
+             }
+             var rightBar = e.retrieve('rightBar');
+             if (rightBar) {
+                 rightBar.setStyle('left', leftPadding + currentPosition);
+                 currentPosition += rightBar.retrieve('size').width;
+             }
+         }
+    },
+    
+    /**
+     * Method: verticalResize
+     * Resize a vertically layed out container.
+     */
+    verticalResize: function() { 
+        var availableSpace = this.domObj.getContentBoxSize().height;
+        var overallHeight = availableSpace;
+
+        for (var i=0; i<this.bars.length; i++) {
+            var bar = this.bars[i];
+            var size = bar.retrieve('size');
+            if (!size || size.height == 0) {
+                size = bar.getBorderBoxSize();
+                bar.store('size', size);
+            }
+            availableSpace -= size.height;
+        }
+
+        var nVariable = 0;
+        
+        var jxo;
+        for (var i=0; i<this.elements.length; i++) {
+            var e = this.elements[i];
+            jxo = e.retrieve('jxLayout').options;
+            if (jxo.height != null) {
+                availableSpace -= parseInt(jxo.height);
+            } else {
+                var h = 0;
+                if (jxo.bottom != 0 || jxo.top != 0) {
+                    h = e.getBorderBoxSize().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 paddingTop = this.domObj.getPaddingSize().top;
+        
+        var currentPosition = 0;
+
+        for (var i=0; i<this.elements.length; i++) {
+             var e = this.elements[i];
+             var jxl = e.retrieve('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 = e.getBorderBoxSize().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;
+             }
+             var rightBar = e.retrieve('rightBar');
+             if (rightBar) {
+                 rightBar.style.top = paddingTop + currentPosition + 'px';
+                 currentPosition += rightBar.retrieve('size').height;
+             }
+         }
+    }
+});// $Id: splitter.snap.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Splitter.Snap
+ * A helper class to create an element that can snap a split panel open or
+ * closed.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Splitter.Snap = new Class({
+    /**
+     * Property: snap
+     * {HTMLElement} the DOM element of the snap (the thing that gets
+     * clicked).
+     */
+    snap: null,
+    /**
+     * Property: element
+     * {HTMLElement} An element of the <Jx.Splitter> that gets controlled
+     * by this snap
+     */
+    element: null,
+    /**
+     * Property: splitter
+     * {<Jx.Splitter>} the splitter that this snap is associated with.
+     */
+    splitter: null,
+    /**
+     * Property: layout
+     * {String} track the layout of the splitter for convenience.
+     */
+    layout: 'vertical',
+    /**
+     * Constructor: Jx.Splitter.Snap
+     * Create a new Jx.Splitter.Snap
+     *
+     * Parameters:
+     * snap - {HTMLElement} the clickable thing that snaps the element
+     *           open and closed
+     * element - {HTMLElement} the element that gets controlled by the snap
+     * splitter - {<Jx.Splitter>} the splitter that this all happens inside of.
+     */
+    initialize: function(snap, element, splitter) {
+        this.snap = snap;
+        this.element = element;
+        var jxl = element.retrieve('jxLayout');
+        jxl.addEvent('sizeChange', this.sizeChange.bind(this));
+        this.splitter = splitter;
+        this.layout = splitter.options.layout; 
+        var jxo = jxl.options;
+        var size = this.element.getContentBoxSize();
+        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;
+        }
+        snap.addEvent('click', this.toggleElement.bind(this));
+    },
+    
+    /**
+     * Method: toggleElement
+     * Snap the element open or closed.
+     */
+    toggleElement: function() {
+        var size = this.element.getContentBoxSize();
+        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.resize(newSize);
+        this.splitter.sizeChanged();
+    },
+    
+    /**
+     * Method: sizeChanged
+     * Handle the size of the element changing to see if the
+     * toggle state has changed.
+     */
+    sizeChange: function() {
+        var size = this.element.getBorderBoxSize();
+        if (this.layout == 'vertical') {
+            if (size.height == this.minimumSize) {
+                this.snap.addClass('jxSnapClosed');
+                this.snap.removeClass('jxSnapOpened');
+            } else {
+                this.snap.addClass('jxSnapOpened');
+                this.snap.removeClass('jxSnapClosed');
+            }
+        } else {
+            if (size.width == this.minimumSize) {
+                this.snap.addClass('jxSnapClosed');
+                this.snap.removeClass('jxSnapOpened');
+            } else {
+                this.snap.addClass('jxSnapOpened');
+                this.snap.removeClass('jxSnapClosed');
+            }
+        }
+    }
+});// $Id: tabset.js 758 2008-08-19 02:35:50Z pspencer $
+/**
+ * Class: Jx.TabSet
+ * A TabSet manages a set of <Jx.Button.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.Button.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.Button.Tab>s are sized to fit the content area that the TabSet
+ * is managing.
+ *
+ * Example:
+ * (code)
+ * var tabBar = new Jx.Toolbar('tabBar');
+ * var tabSet = new Jx.TabSet('tabArea');
+ * 
+ * var tab1 = new Jx.Button.Tab('tab 1', {contentID: 'content1'});
+ * var tab2 = new Jx.Button.Tab('tab 2', {contentID: 'content2'});
+ * var tab3 = new Jx.Button.Tab('tab 3', {contentID: 'content3'});
+ * var tab4 = new Jx.Button.Tab('tab 4', {contentURL: 'test_content.html'});
+ * 
+ * tabSet.add(t1, t2, t3, t4);
+ * tabBar.add(t1, t2, t3, t4);
+ * (end)
+ *
+ * Events:
+ * tabChange - the current tab has changed
+ *
+ * Implements:
+ * Events - MooTools Class.Extras
+ * Options - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.TabSet = new Class({
+    Implements: [Options,Events],
+    /**
+     * Property: tabs
+     * {Array} array of tabs that are managed by this tab set
+     */
+    tabs: null,
+    /**
+     * 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,
+    /**
+     * 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.
+     * options - an options object, only event handlers are supported
+     * as options at this time.
+     */
+    initialize : function(domObj, options) {
+        this.setOptions(options);
+        this.tabs = [];
+        this.domObj = $(domObj);
+        if (!this.domObj.hasClass('jxTabSetContainer')) {
+            this.domObj.addClass('jxTabSetContainer');
+        }
+        this.selectionChangedFn = this.selectionChanged.bind(this);
+    },
+    /**
+     * 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();
+            }
+        }
+    },
+    
+    /**
+     * Method: add
+     * Add one or more <Jx.Button.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() {
+        $A(arguments).each(function(tab) {
+            if (tab instanceof Jx.Button.Tab) {
+                tab.addEvent('down',this.selectionChangedFn);
+                this.domObj.appendChild(tab.content);
+                if (!this.activeTab) {
+                    tab.setActive(true);
+                }
+                this.tabs.push(tab);
+            }
+        }, this);
+    },
+    /**
+     * Method: remove
+     * Remove a tab from this TabSet.  Note that it is the caller's responsibility
+     * to remove the tab from the <Jx.Toolbar>.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to remove.
+     */
+    remove : function(tab) {
+        if (tab instanceof Jx.Button.Tab && this.tabs.indexOf(tab) != -1) {
+            this.tabs.erase(tab);
+            if (this.activeTab == tab) {
+                if (this.tabs.length) {
+                    this.tabs[0].setActive(true);
+                }
+            }
+            tab.removeEvent('down',this.selectionChangedFn);
+            tab.content.dispose();
+        }
+    },
+    /**
+     * Method: setActiveTab
+     * Set the active tab to the one passed to this method
+     *
+     * Parameters:
+     * tab - {<Jx.Button.Tab>} the tab to make active.
+     */
+    setActiveTab: function(tab) {
+        if (this.activeTab && this.activeTab != tab) {
+            this.activeTab.setActive(false);
+        }
+        this.activeTab = tab;
+        if (this.activeTab.content.resize) {
+          this.activeTab.content.resize();
+        }
+    },
+    /**
+     * Method: selectionChanged
+     * Handle selection changing on the tabs themselves and activate the
+     * appropriate tab in response.
+     *
+     * Parameters:
+     * tab - {<Jx.Button.Tab>} the tab to make active.
+     */
+    selectionChanged: function(tab) {
+        this.setActiveTab(tab);
+        this.fireEvent('tabChange', this, tab);
+    }
+});
+
+
+
+// $Id: tabset.js 758 2008-08-19 02:35:50Z pspencer $
+/**
+ * Class: Jx.TabSet
+ * A TabSet manages a set of <Jx.Button.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.Button.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.Button.Tab>s are sized to fit the content area that the TabSet
+ * is managing.
+ *
+ * Example:
+ * (code)
+ * var tabBar = new Jx.Toolbar('tabBar');
+ * var tabSet = new Jx.TabSet('tabArea');
+ * 
+ * var tab1 = new Jx.Button.Tab('tab 1', {contentID: 'content1'});
+ * var tab2 = new Jx.Button.Tab('tab 2', {contentID: 'content2'});
+ * var tab3 = new Jx.Button.Tab('tab 3', {contentID: 'content3'});
+ * var tab4 = new Jx.Button.Tab('tab 4', {contentURL: 'test_content.html'});
+ * 
+ * tabSet.add(t1, t2, t3, t4);
+ * tabBar.add(t1, t2, t3, t4);
+ * (end)
+ *
+ * Events:
+ * tabChange - the current tab has changed
+ *
+ * Implements:
+ * Events - MooTools Class.Extras
+ * Options - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.TabSet = new Class({
+    Implements: [Options,Events],
+    /**
+     * Property: tabs
+     * {Array} array of tabs that are managed by this tab set
+     */
+    tabs: null,
+    /**
+     * 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,
+    /**
+     * 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.
+     * options - an options object, only event handlers are supported
+     * as options at this time.
+     */
+    initialize : function(domObj, options) {
+        this.setOptions(options);
+        this.tabs = [];
+        this.domObj = $(domObj);
+        if (!this.domObj.hasClass('jxTabSetContainer')) {
+            this.domObj.addClass('jxTabSetContainer');
+        }
+        this.selectionChangedFn = this.selectionChanged.bind(this);
+    },
+    /**
+     * 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();
+            }
+        }
+    },
+    
+    /**
+     * Method: add
+     * Add one or more <Jx.Button.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() {
+        $A(arguments).each(function(tab) {
+            if (tab instanceof Jx.Button.Tab) {
+                tab.addEvent('down',this.selectionChangedFn);
+                this.domObj.appendChild(tab.content);
+                if (!this.activeTab) {
+                    tab.setActive(true);
+                }
+                this.tabs.push(tab);
+            }
+        }, this);
+    },
+    /**
+     * Method: remove
+     * Remove a tab from this TabSet.  Note that it is the caller's responsibility
+     * to remove the tab from the <Jx.Toolbar>.
+     *
+     * Parameters:
+     * tab - {<Jx.Tab>} the tab to remove.
+     */
+    remove : function(tab) {
+        if (tab instanceof Jx.Button.Tab && this.tabs.indexOf(tab) != -1) {
+            this.tabs.erase(tab);
+            if (this.activeTab == tab) {
+                if (this.tabs.length) {
+                    this.tabs[0].setActive(true);
+                }
+            }
+            tab.removeEvent('down',this.selectionChangedFn);
+            tab.content.dispose();
+        }
+    },
+    /**
+     * Method: setActiveTab
+     * Set the active tab to the one passed to this method
+     *
+     * Parameters:
+     * tab - {<Jx.Button.Tab>} the tab to make active.
+     */
+    setActiveTab: function(tab) {
+        if (this.activeTab && this.activeTab != tab) {
+            this.activeTab.setActive(false);
+        }
+        this.activeTab = tab;
+        if (this.activeTab.content.resize) {
+          this.activeTab.content.resize();
+        }
+    },
+    /**
+     * Method: selectionChanged
+     * Handle selection changing on the tabs themselves and activate the
+     * appropriate tab in response.
+     *
+     * Parameters:
+     * tab - {<Jx.Button.Tab>} the tab to make active.
+     */
+    selectionChanged: function(tab) {
+        this.setActiveTab(tab);
+        this.fireEvent('tabChange', this, tab);
+    }
+});
+
+
+
+// $Id: button.tab.js 758 2008-08-19 02:35:50Z pspencer $
+/**
+ * Class: Jx.Button.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.
+ *
+ * A tab is a button of type *toggle* which means that it emits the *up*
+ * and *down* events.
+ *
+ * Example:
+ * (code)
+ * var tab1 = new Jx.Button.Tab({
+ *     label: 'tab 1', 
+ *     content: 'content1',
+ *     onDown: function(tab) {
+ *         console.log('tab became active');
+ *     },
+ *     onUp: function(tab) {
+ *         console.log('tab became inactive');
+ *     }
+ * });
+ * (end)
+ *
+ * Extends:
+ * <Jx.Button>
+ * 
+ * Implements:
+ * Options - MooTools Class.Extras
+ * Events - MooTools Class.Extras
+ * <Jx.ContentLoader> - for loading content into a tab
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Button.Tab = new Class({
+    Extends: Jx.Button,
+    Implements: [Options, Events, Jx.ContentLoader],
+    /**
+     * Property: content
+     * {HTMLElement} The content area that is displayed when the tab is active.
+     */
+    content: null,
+    /**
+     * Constructor: Jx.Button.Tab
+     * Create a new instance of Jx.Button.Tab.
+     *
+     * Parameters:
+     * options - {Object} an object containing options that are used
+     * to control the appearance of the tab.  See <Jx.Button>,
+     * <Jx.ContentLoader::loadContent> and <Jx.Layout::Jx.Layout> for
+     * valid options.
+     */
+    initialize : function( options) {
+        options = $merge(options, {type:'Tab', toggle:true});
+        this.parent(options);
+        this.content = new Element('div', {'class':'tabContent'});
+        this.loadContent(this.content);
+        new Jx.Layout(this.content, options);
+        var that = this;
+        this.addEvent('down', function(){that.content.addClass('tabContentActive');});
+        this.addEvent('up', function(){that.content.removeClass('tabContentActive');});
+    },
+    /**
+     * Method: clicked
+     * triggered when the user clicks the button, processes the
+     * actionPerformed event
+     */
+    clicked : function(evt) {
+        this.setActive(true);
+    }
+});// $Id: toolbar.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * 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.
+ *
+ * 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.
+ *
+ * Example:
+ * 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 myButton = new Jx.Button(buttonOptions);
+ *
+ * var myElement = document.createElement('select');
+ *
+ * myToolbar.add(myButton, new Jx.ToolbarSeparator(), myElement);
+ * (end)
+ *
+ * Events:
+ * add - fired when one or more buttons are added to a toolbar
+ * remove - fired when on eor more buttons are removed from a toolbar
+ *
+ * Implements: 
+ * Options
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Toolbar = new Class({
+    Implements: [Options,Events],
+    /**
+     * 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,
+    options: {
+        position: 'top',
+        parent: null
+    },
+    /**
+     * Constructor: Jx.Toolbar
+     * Create a new instance of Jx.Toolbar.
+     *
+     * Parameters:
+     * options - an options object as documented below
+     *
+     * Options:
+     * parent - {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(options) {
+        this.setOptions(options);
+        
+        this.domObj = new Element('ul', {'class':'jxToolbar'});
+        
+        if (this.options.parent) {
+            var owner = $(this.options.parent);
+            if (!owner.hasClass('jxToolbarContainer')) {
+                owner.addClass('jxToolbarContainer');
+                owner.appendChild(this.domObj);
+                var clearer = new Element('div', {'class':'jxClearer'});
+                owner.appendChild(clearer);                    
+            } else {
+                owner.insertBefore(this.domObj, owner.lastChild);
+            }
+            if (['top','right','bottom','left'].contains(this.options.position)) {
+                owner.addClass('jxBar'+this.options.position.capitalize());            
+            } else {
+                owner.addClass('jxBarTop');
+            }            
+        }
+        this.deactivateWatcher = this.deactivate.bindWithEvent(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 (!thing.hasClass('jxToolItem')) {
+                    thing.addClass('jxToolItem');
+                }
+                this.domObj.appendChild(thing);
+            } else {
+                var item = new Jx.Toolbar.Item(thing);
+                this.domObj.appendChild(item.domObj);
+            }
+        }
+        if (arguments.length > 0) {
+            this.fireEvent('add', this);
+        }
+    },
+    /**
+     * Method: remove
+     * remove an item from a toolbar.  If the item is not in this toolbar
+     * nothing happens
+     *
+     * Parameters:
+     * item - {Object} the object to remove
+     *
+     * Returns:
+     * {Object} the item that was removed, or null if the item was not
+     * removed.
+     */
+    remove: function(item) {
+        if (item.domObj) {
+            item = item.domObj;
+        }
+        var li = item.findElement('LI');
+        if (li && li.parentNode == this.domObj) {
+            item.dispose();
+            this.fireEvent('remove', this);
+        } else {
+            return null;
+        }
+    },
+    /**
+     * Method: deactivate
+     * Deactivate the Toolbar (when it is acting as a menu bar).
+     */
+    deactivate: function() {
+        this.items.each(function(o){o.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) {
+            document.addEvent('click', this.deactivateWatcher);
+            Event.observe(document, 'click', this.deactivateWatcher);
+        } else {
+            document.removeEvent('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();
+        }
+    }
+});
+// $Id: toolbar.item.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Toolbar.Item
+ * A helper class to provide a container for something to go into 
+ * a <Jx.Toolbar>.
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Toolbar.Item = new Class( {
+    /**
+     * Property: domObj
+     * {HTMLElement} an element to contain the thing to be placed in the
+     * toolbar.
+     */
+    domObj: null,
+    /**
+     * Constructor: Jx.Toolbar.Item
+     * Create a new instance of Jx.Toolbar.Item.
+     *
+     * Parameters:
+     * jxThing - {Object} the thing to be contained.
+     */
+    initialize : function( jxThing ) {
+        this.al = [];
+        this.domObj = new Element('li', {'class':'jxToolItem'});
+        if (jxThing) {
+            if (jxThing.domObj) {
+                this.domObj.appendChild(jxThing.domObj);
+                if (jxThing instanceof Jx.Tab) {
+                    this.domObj.addClass('jxTabItem');
+                }
+            } else {
+                this.domObj.appendChild(jxThing);
+                if (jxThing.hasClass('jxTab')) {
+                    this.domObj.addClass('jxTabItem');
+                }
+            }
+        }
+    }
+});// $Id: toolbar.separator.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Toolbar.Separator
+ * A helper class that represents a visual separator in a <Jx.Toolbar>
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Toolbar.Separator = new Class({
+    /**
+     * Property: domObj
+     * {HTMLElement} The DOM element that goes in the <Jx.Toolbar>
+     */
+    domObj: null,
+    /**
+     * Constructor: Jx.Toolbar.Separator
+     * Create a new Jx.Toolbar.Separator
+     */
+    initialize: function() {
+        this.domObj = new Element('li', {'class':'jxToolItem'});
+        this.domSpan = new Element('span', {'class':'separator'});
+        this.domObj.appendChild(this.domSpan);
+    }
+});
+// $Id: treeitem.js 786 2008-08-27 15:03:41Z pspencer $
+/**
+ * Class: Jx.TreeItem 
+ * An item in a tree.  An item is a leaf node that has no children.
+ *
+ * Jx.TreeItem supports selection via the click event.  The application 
+ * is responsible for changing the style of the selected item in the tree
+ * and for tracking selection if that is important.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Events:
+ * click - triggered when the tree item is clicked
+ *
+ * Implements:
+ * Events - MooTools Class.Extras
+ * Options - MooTools Class.Extras
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.TreeItem = new Class ({
+    Implements: [Options,Events],
+    /**
+     * Property: domObj
+     * {HTMLElement} a reference to the HTML element that is the TreeItem
+     * in the DOM
+     */
+    domObj : null,
+    /**
+     * Property: owner
+     * {Object} the folder or tree that this item belongs to
+     */
+    owner: null,
+    options: {
+        label: '',
+        data: null,
+        contextMenu: null,
+        image: null,
+        enabled: true,
+        type: 'Item',
+        imageClass: ''
+    },
+    /**
+     * 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
+     * image - {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.setOptions(options);
+
+        this.domObj = new Element('li', {'class':'jxTree'+this.options.type});
+        if (this.options.id) {
+            this.domObj.id = this.options.id;
+        }
+      
+        this.domNode = new Element('img',{'class': 'jxTreeImage', src: Jx.aPixel.src});
+        this.domObj.appendChild(this.domNode);
+        
+        this.domImg = new Element('img',{'class':'jxTreeIcon', src: Jx.aPixel.src});
+        if (this.options.image) {
+            this.domImg.setStyle('backgroundImage', 'url('+this.options.image+')');
+        }
+        if (this.options.imageClass) {
+            this.domImg.addClass(this.options.imageClass);
+        }
+        this.domA = new Element('a',{
+            href:'javascript:void(0)',
+            html: this.options.label,
+            events: {
+                click: this.selected.bindWithEvent(this),
+                dblclick: this.selected.bindWithEvent(this),
+                contextmenu: this.showMenu.bindWithEvent(this)
+            }
+        });
+        this.domA.store('jxTreeItem', this);
+        this.domA.appendChild(this.domImg);
+        this.domObj.appendChild(this.domA);
+        this.domObj.store('jxTreeItem', this);
+        
+        if (!this.options.enabled) {
+            this.domObj.addClass('jxDisabled');
+        }
+    },
+    /**
+     * 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.domA.removeEvents();
+        this.options = null;
+        this.domObj = null;
+        this.owner = null;
+    },
+    /**
+     * Method: clone
+     * Create a clone of the TreeItem
+     * 
+     * Returns: 
+     * {<Jx.TreeItem>} a copy of the TreeItem
+     */
+    clone : function() {
+        return new Jx.TreeItem(this.options);
+    },
+    /**
+     * 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.owner && this.owner.isLastNode(this));
+        if (isLast) {
+            this.domObj.removeClass('jxTree'+this.options.type);
+            this.domObj.addClass('jxTree'+this.options.type+'Last');
+        } else {
+            this.domObj.removeClass('jxTree'+this.options.type+'Last');
+            this.domObj.addClass('jxTree'+this.options.type);
+        }
+    },
+    /**
+     * 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;
+        this.fireEvent('click', 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;
+        this.fireEvent('click',this);
+        if (this.contextMenu) {
+            this.contextMenu.show(this.lastEvent);
+        }
+        e.stop();;
+    },
+    /**
+     * Method: getName
+     * Get the label associated with a TreeItem
+     *
+     * Returns: 
+     * {String} the name
+     */
+    getName : function() { return this.options.label; },
+    /**
+     * Method: setName
+     * Set the label of a TreeItem
+     *
+     * Parameters:
+     * name - {String} the new label
+     */
+    setName : function(name) { 
+        this.domA.set('html', name); 
+        this.options.label = 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.options.enabled = obj.isEnabled();
+        if (this.options.enabled) {
+            this.domObj.removeClass('jxDisabled');
+        } else {
+            this.domObj.addClass('jxDisabled');
+        }
+    }
+});// $Id: treefolder.js 785 2008-08-26 21:28:39Z pspencer $
+/**
+ * Class: Jx.TreeFolder
+ * A Jx.TreeFolder is an item in a tree that can contain other items.  It is
+ * expandable and collapsible.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Extends:
+ * <Jx.TreeItem>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.TreeFolder = new Class({
+    Extends: Jx.TreeItem,
+    /**
+     * 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,
+    options: {
+        folderCloseImage: Jx.baseURL + 'images/tree_folder.png',
+        folderOpenImage: Jx.baseURL + 'images/tree_folder_open.png'
+    },
+    /**
+     * 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:
+     * openImage - {String} a URL to an image for opening the folder
+     * closeImage - {String} a URL to an image for closing the folder
+     * folderCloseImage - {String} a URL to an image to represent the folder
+     *      when it is closed
+     * folderOpenImage - {String} a URL to an image to represent the folder
+     *      when it is open
+     */
+    initialize : function( options ) {
+        this.parent($merge(options,{type:'Branch'}));
+
+        this.domObj.childNodes[0].addEvent('click', this.clicked.bindWithEvent(this));
+                
+        this.nodes = [];
+        this.subDomObj = new Element('ul', {'class':'jxTree'});
+        this.domObj.appendChild(this.subDomObj);
+        this.subDomObj.className = 'jxTree';
+        if (this.options.isOpen) {
+            this.expand();
+        } else {
+            this.collapse();
+        }
+    },
+    /**
+     * 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].removeEvents();
+        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();
+        }
+        
+    },
+    
+    /**
+     * Method: clone
+     * Create a clone of the TreeFolder
+     * 
+     * Returns: 
+     * {<Jx.TreeFolder>} a copy of the TreeFolder
+     */
+    clone : function() {
+        var node = new Jx.TreeFolder(this.options);
+        this.nodes.each(function(n){node.append(n.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(shouldDescend) {
+        /* avoid update if not attached to tree yet */
+        if (!this.parent) return;
+        var isLast = false;
+        if (arguments.length > 1) {
+            isLast = arguments[1];
+        } else {
+            isLast = (this.owner && this.owner.isLastNode(this));
+        }
+        
+        var c = 'jxTree'+this.options.type;
+        c += isLast ? 'Last' : '';
+        c += this.options.isOpen ? 'Open' : 'Closed';
+        this.domObj.className = c;
+        
+        if (isLast) {
+            this.subDomObj.className = 'jxTree';
+        } else {
+            this.subDomObj.className = 'jxTree jxTreeNest';
+        }
+        
+        if (this.nodes && shouldDescend) {
+            var that = this;
+            this.nodes.each(function(n,i){
+                n.update(false, i==that.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.owner = 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.owner = 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);
+    },
+    /**
+     * Method: remove
+     * remove the specified node from the tree
+     *
+     * Parameters:
+     * node - {Object} the node to remove
+     */
+    remove : function(node) {
+        node.owner = 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);
+    },
+    /**
+     * 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.owner = 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) {
+        if (this.options.isOpen) {
+            this.collapse();
+        } else {
+            this.expand();
+        }
+    },
+    /**
+     * Method: expand
+     * Expands the folder
+     */
+    expand : function() {
+        this.options.isOpen = true;
+        this.subDomObj.setStyle('display', 'block');
+        this.update(true);
+        this.fireEvent('disclosed', this);    
+    },
+    /**
+     * Method: collapse
+     * Collapses the folder
+     */
+    collapse : function() {
+        this.options.isOpen = false;
+        this.subDomObj.setStyle('display', 'none');
+        this.update(true);
+        this.fireEvent('disclosed', this);
+    },
+    /**
+     * 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;
+    }
+});// $Id: tree.js 711 2008-08-13 20:38:33Z pspencer $
+/**
+ * Class: Jx.Tree
+ * Jx.Tree displays hierarchical data in a tree structure of folders and nodes.
+ *
+ * Example:
+ * (code)
+ * (end)
+ *
+ * Extends: <Jx.TreeFolder>
+ *
+ * License: 
+ * Copyright (c) 2008, DM Solutions Group Inc.
+ * 
+ * This file is licensed under an MIT style license
+ */
+Jx.Tree = new Class({
+    Extends: Jx.TreeFolder,
+    /**
+     * 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.parent();
+        this.subDomObj = new Element('ul',{
+            'class':'jxTreeRoot'
+        });
+        $(id).appendChild(this.subDomObj);
+        this.nodes = [];
+        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) {
+                this.subDomObj.removeClass('jxTreeNest');
+            } else {
+                this.subDomObj.addClass('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.owner = this;
+        this.nodes.push(node);
+        this.subDomObj.appendChild( node.domObj );
+        this.update(true);        
+    }
+});
\ No newline at end of file

Added: sandbox/jx2/jx/lib/jxskin_border.css
===================================================================
--- sandbox/jx2/jx/lib/jxskin_border.css	                        (rev 0)
+++ sandbox/jx2/jx/lib/jxskin_border.css	2008-08-28 12:29:20 UTC (rev 1482)
@@ -0,0 +1 @@
+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:'';}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:.4;filter:Alpha(opacity=40);}iframe.jxIframeShim{position:absolute;top:0;left:0;width:100%;height:100%;filter:Alpha(opacity:0);opacity:0;z-index:-1;}div.jxButtonContainer{display:block;position:relative;float:left;margin:1px;padding:0;border:none;}a.jxButton{display:block;position:relative;float:left;margin:0;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;}.jxButtonDisabled a.jxButton:hover,.jxButtonDisabled a.jxButton:active{border:1px solid #d9d9d9;}span.jxButtonContent{display:block;position:relative;float:left;font-size:0;line-height:0;margin:0;padding:0;background-repeat:no-repeat;}span.jxButtonContent span{font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:16px;}img.jxButtonIcon{position:relative;float:left;width:16px;height:16px;background-position:center center;background-repeat:no-repeat;}span.jxButtonContent span.jxButtonLabel{display:block;position:relative;float:left;cursor:pointer;margin:0;padding:0 4px;color:#000;background-position:right center;background-repeat:no-repeat;font-size:11px;}a.jxButtonMenu span.jxButtonContent,a.jxButtonFlyout span.jxButtonContent{background-image:url(../images/menu_item_arrow_d2.png);background-position:right center;background-repeat:no-repeat;}a.jxButtonMenu span.jxButtonContent span,a.jxButtonFlyout span.jxButtonContent span{padding-right:16px;}a.jxButtonMulti span.jxButtonLabel{padding-left:0;padding-right:0;}.jxFlyout{position:absolute;display:block;clear:both;float:none;z-index:100;margin:0;padding:0;border:1px solid #999;background-color:#fff;font-size:12px;line-height:14px;}.jxFlyout .jxBarRight,.jxFlyout .jxBarLeft{float:left;height:auto;width:auto;}.jxChrome{position:absolute;display:block;font-size:0;line-height:0;z-index:0;}.jxChromeTL{position:absolute;overflow:hidden;left:0;top:0;width:50%;height:50%;}.jxChromeTR{position:absolute;overflow:hidden;left:50%;top:0;width:50%;height:50%;}.jxChromeBL{position:absolute;overflow:hidden;left:0;top:50%;width:50%;height:50%;}.jxChromeBR{position:absolute;overflow:hidden;left:50%;top:50%;width:50%;height:50%;}.jxChromeTL img{position:absolute;top:0;left:0;}.jxChromeTR img{position:absolute;top:0;right:0;}.jxChromeBL img{position:absolute;bottom:0;left:0;}.jxChromeBR img{position:absolute;bottom:0;right:0;}.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:0 solid #000;}.jxColorGrid td.emptyCell span{display:block;width:7px;height:7px;line-height:0;font-size:0;border:0 solid #000;padding:1px;margin:0;}.jxColorGrid a.colorSwatch{display:block;width:7px;height:7px;line-height:0;font-size:0;border:0 solid #000;margin:0;padding:1px;}.jxColorGrid a.borderWhite:hover{border:1px solid #fff;padding:0;}.jxColorGrid a.borderBlack:hover{border:1px solid #000;padding:0;}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');}span.jxButtonContent span.jxButtonSwatch{display:block;float:left;width:14px;height:14px;border:1px solid #000;background-image:url('../images/grid.png');padding-right:0!important;}span.jxButtonContent span.jxButtonSwatch span{display:block;width:14px;height:14px;position:absolute;padding-right:0;}div.jxColorPreview img{position:absolute;z-index:0;}div.jxColorPreview div.jxColorSelected{width:20px;height:10px;position:absolute;z-index:1;}div.jxColorPreview div.jxColorHover{width:20px;height:10px;position:absolute;bottom:0;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:0;right:0;width:16px;height:16px;}a.jxColorClose img{width:16px;height:16px;}div.jxCombo{position:relative;display:block;padding:0;padding-right:22px;margin:0;border:0;font-family:Arial,Helvetica,sans-serif;font-size:11px;z-index:1;line-height:24px;float:left;}.jxComboDiscloser{position:absolute;right:3px;top:3px;}.jxComboDiscloser img{width:16px;height:16px;border:0;}.jxComboInput{position:relative;display:block;float:left;line-height:14px;height:14px;padding:5px 10px;border:1px solid #d9d9d9;}div.jxComboOptions{position:absolute;height:auto;background-color:#fff;overflow:auto;border:1px solid #333;color:#000;z-index:1;font-family:Arial,Helvetica,sans-serif;font-size:11px;line-height:24px;}div.jxComboOptions ul{position:relative;display:block;margin:0;padding:0;border:none;list-style-type:none;}div.jxComboOptions li{position:relative;display:block;margin:0;padding:0;border:none;height:20px;}div.jxComboOptions a{position:relative;display:block;text-decoration:none;white-space:nowrap;line-height:20px;height:20px;color:#000;background-position:right top;background-repeat:no-repeat;padding:0 4px;}div.jxComboOptions a:hover{background-color:#E1EDFA;}div.jxComboOptions a.selected{font-weight:bold;background-color:#ffffb3;}.jxDialog .jxChrome{background-color:#000;padding:1px 3px 3px 1px;opacity:.2;}.jxDialog{display:block;z-index:1;border:1px solid #666;}.jxDialogContentContainer{z-index:1;background-color:#ccc;}.jxDialogModal{position:absolute;display:block;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.2;filter:Alpha(opacity=20);}.jxDialogContent{display:block;position:relative;overflow:auto;border-top:1px solid #fff;border-left:1px solid #fff;padding:0;z-index:1;}.jxDialogTitle{display:block;position:relative;text-align:center;background-color:#ccc;border-top:1px solid #fff;border-left:1px solid #fff;border-bottom:1px solid #999;height:22px;margin:0;padding:0;z-index:1;}.jxDialogMoveable{cursor:move;}.jxDialogLabel{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;line-height:21px;color:#000;white-space:nowrap;}.jxDialogResize{position:absolute;bottom:0;right:0;width:22px;height:22px;z-index:2;border:0;cursor:se-resize;background-image:url(../images/dialog_resize.png);z-index:1;}.jxDialogControls{position:absolute;top:3px;right:2px;height:16px;width:80px;}.jxDialogControls img{background-image:url('../images/panel_controls.png');background-repeat:no-repeat;border:0;margin:0;width:16px;height:16px;}.jxDialogClose img{background-position:0 -32px;}.jxDialogMenu img{background-position:0 -48px;}.jxDialogHelp img{background-position:0 -64px;}.jxDialogCollapse img{background-position:0 -16px;}.jxDialogMin .jxDialogCollapse img{background-position:0 0;}.jxDialogMax .jxDialogCollapse img{background-position:0 -16px;}.jxDialogLoading img{border:0;margin:0;width:16px;height:16px;visibility:hidden;position:absolute;top:1px;left:2px;}.jxDialogControls .jxButtonContainer,.jxDialogControls span.jxButtonContent,.jxDialogControls a.jxButton:hover span.jxButtonContent,.jxDialogControls a.jxButton:active span.jxButtonContent,.jxDialogControls a.jxButtonActive span.jxButtonContent,.jxDialogControls a.jxButtonActive:hover span.jxButtonContent,.jxDialogControls a.jxButtonActive:active span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton:hover span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton:active span.jxButtonContent,.jxDialogControls a.jxButton,.jxDialogControls a.jxButton:hover,.jxDialogControls a.jxButton:active,.jxDialogControls a.jxButtonActive,.jxDialogControls a.jxButtonActive:hover,.jxDialogControls a.jxButtonActive:active,.jxDialogControls .jxButtonDisabled a.jxButton,.jxDialogControls .jxButtonDisabled a.jxButton:hover,.jxDialogControls .jxButtonDisabled a.jxButton:active{padding:0;margin:0;border:none;background-color:transparent;background-image:none;}.jxDialogControls a.jxButtonMenu span.jxButtonContent,.jxDialogControls a.jxButtonFlyout span.jxButtonContent{background-image:none;}.jxDialogControls a.jxButtonMenu span.jxButtonContent span,.jxDialogControls a.jxButtonFlyout span.jxButtonContent span{padding-right:0;}.jxDialogControls .jxToolbarContainer{position:absolute;right:0;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxDialogControls ul.jxToolbar{float:right;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxDialogControls .jxBarTop,.jxDialogControls .jxBarBottom,.jxDialogControls .jxBarLeft,.jxDialogControls .jxBarRight{width:auto;height:auto;}.jxDialogControls .jxBarTop ul.jxToolbar,.jxDialogControls .jxBarBottom ul.jxToolbar,.jxDialogControls .jxBarLeft ul.jxToolbar,.jxDialogControls .jxBarRight ul.jxToolbar,.jxDialogControls .jxBarTop li.jxToolItem,.jxDialogControls .jxBarBottom li.jxToolItem,.jxDialogControls .jxBarLeft li.jxToolItem,.jxDialogControls .jxBarRight li.jxToolItem{background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxGridContainer{position:absolute;top:0;left:0;border-left:0 solid #96a7b4;border-top:0 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:0;}.jxGridColHeadHide{height:0;line-height:0;font-size:0;background-color:#fff;white-space:normal;}.jxGridColHeadHide p,.jxGridRowHeadHide p{font-size:0;line-height:0;height:0;margin:0;padding:0;}.jxGridRowHeadHide{width:0;white-space:normal;}.jxGridCell{border-right:1px solid #cecece;border-bottom:1px solid #cecece;overflow:hidden;padding-left:3px;padding-right:3px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.jxGridColHead{border-top:0 solid #96a7b4;border-right:1px solid #96a7b4;border-bottom:1px solid #96a7b4;border-left:0 solid #96a7b4;background-color:#ebebeb;text-align:center;font-weight:bold;color:#45525f;}.jxGridRowHead{border-top:0 solid #96a7b4;border-right:1px solid #96a7b4;border-bottom:1px solid #96a7b4;border-left:0 solid #96a7b4;background-color:#ebebeb;text-align:center;font-weight:bold;color:#45525f;}.jxGridRowAll{background-color:#fff;}.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;}.jxGridRowHeaderPrelight{background-color:#dfdfdf;}.jxGridColumnHeaderPrelight{background-color:#dfdfdf;}.jxGridRowHeaderSelected{background-color:#6d7f8e;color:#fff;}.jxGridColumnHeaderSelected{background-color:#6d7f8e;color:#fff;}a.jxButtonMenu span.jxMenuItemSpan{padding-right:16px;}ul.jxMenu,ul.jxSubMenu{position:absolute;display:block;clear:both;float:none;z-index:100;list-style-type:none;margin:0;padding:0;border:1px solid #999;background-color:#fff;}li.jxMenuItemContainer{display:block;position:relative;margin:0;padding:0;}a.jxMenuItem{display:block;position:relative;text-decoration:none;background-image:none;border:1px solid #fff;font-family:Arial,Helvetica,sans-serif;font-size:11px;text-decoration:none;margin:0;padding:0;color:#000;}a.jxMenuItem:hover{background-image:none;border:1px solid #E1EDFA;background-color:#E1EDFA;}a.jxMenuItem:hover span.jxMenuItemContent{border:1px solid #E1EDFA;}span.jxMenuItemContent{display:block;position:relative;font-family:Arial,Helvetica,sans-serif;font-size:0;line-height:0;white-space:nowrap;padding:0;margin:0;border:1px solid #fff;}a.jxButtonSubMenu span.jxMenuItemContent,a.jxButtonSubMenu:hover span.jxMenuItemContent{background-image:url(../images/menu_item_arrow_r2.png);background-position:right top;background-repeat:no-repeat;padding-right:20px;}img.jxMenuItemIcon{position:absolute;top:0;left:0;display:inline;width:16px;height:16px;background-position:left center;background-repeat:no-repeat;}span.jxMenuItemContent span{display:block;position:relative;cursor:pointer;margin:0;padding:0 0 0 20px;font-size:16px;line-height:16px;}span.jxMenuItemContent span.jxMenuItemLabel{color:#000;font-size:12px;}ul.jxMenu a.jxMenuItemSelected{background-image:url(../images/menu_item_radio.png);background-position:2px top;background-repeat:no-repeat;}li.jxMenuItemDisabled span.jxMenuItemLabel{color:#ccc;}li.jxMenuItemDisabled a.jxMenuItem:hover{background-color:#fff;border:1px solid #fff;}ul.jxMenu span.jxMenuSeparator{display:block;font-size:10px;line-height:10px;background-image:url(../images/toolbar_separator_v.png);background-repeat:repeat-x;background-position:left center;}.jxPanel{display:block;position:relative;}.jxPanelContentContainer{overflow:hidden;}.jxPanelContent{position:relative;display:block;overflow:auto;border-top:1px solid #fff;border-bottom:1px solid #999;margin:0;padding:0;border-top:none;background-color:#fff;}.jxPanelTitle{display:block;position:relative;background-color:#ccc;border-top:1px solid #fff;border-bottom:1px solid #999;height:22px;margin:0;padding:0;}.jxPanelLabel{padding-left:25px;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;line-height:21px;color:#000;white-space:nowrap;}.jxPanelControls{position:absolute;top:3px;right:2px;height:16px;width:80px;}.jxPanelControls img{background-image:url('../images/panel_controls.png');background-repeat:no-repeat;border:0;margin:0;width:16px;height:16px;}.jxPanelClose img{background-position:0 -32px;}.jxPanelMenu img{background-position:0 -48px;}.jxPanelHelp img{background-position:0 -64px;}.jxPanelCollapse img{background-position:0 -16px;}.jxPanelMin .jxPanelCollapse img{background-position:0 0;}.jxPanelMax .jxPanelCollapse img{background-position:0 -16px;}.jxPanelMaximize img{background-position:0 0;}.jxPanelLoading img{border:0;margin:0;width:16px;height:16px;visibility:hidden;position:absolute;top:1px;left:2px;}.jxPanelControls .jxButtonContainer,.jxPanelControls span.jxButtonContent,.jxPanelControls a.jxButton:hover span.jxButtonContent,.jxPanelControls a.jxButton:active span.jxButtonContent,.jxPanelControls a.jxButtonActive span.jxButtonContent,.jxPanelControls a.jxButtonActive:hover span.jxButtonContent,.jxPanelControls a.jxButtonActive:active span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton:hover span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton:active span.jxButtonContent,.jxPanelControls a.jxButton,.jxPanelControls a.jxButton:hover,.jxPanelControls a.jxButton:active,.jxPanelControls a.jxButtonActive,.jxPanelControls a.jxButtonActive:hover,.jxPanelControls a.jxButtonActive:active,.jxPanelControls .jxButtonDisabled a.jxButton,.jxPanelControls .jxButtonDisabled a.jxButton:hover,.jxPanelControls .jxButtonDisabled a.jxButton:active{padding:0;margin:0;border:none;background-color:transparent;background-image:none;}.jxPanelControls a.jxButtonMenu span.jxButtonContent,.jxPanelControls a.jxButtonFlyout span.jxButtonContent{background-image:none;}.jxPanelControls a.jxButtonMenu span.jxButtonContent span,.jxPanelControls a.jxButtonFlyout span.jxButtonContent span{padding-right:0;}.jxPanelControls .jxToolbarContainer{position:absolute;right:0;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxPanelControls ul.jxToolbar{background-image:none;background-color:transparent;margin:0;padding:0;border:none;float:right;}.jxPanelControls .jxBarTop,.jxPanelControls .jxBarBottom,.jxPanelControls .jxBarLeft,.jxPanelControls .jxBarRight{width:auto;height:auto;}.jxPanelControls .jxBarTop ul.jxToolbar,.jxPanelControls .jxBarBottom ul.jxToolbar,.jxPanelControls .jxBarLeft ul.jxToolbar,.jxPanelControls .jxBarRight ul.jxToolbar,.jxPanelControls .jxBarTop li.jxToolItem,.jxPanelControls .jxBarBottom li.jxToolItem,.jxPanelControls .jxBarLeft li.jxToolItem,.jxPanelControls .jxBarRight li.jxToolItem{background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxSplitBarHorizontal{position:absolute;display:block;line-height:1px;width:10px;top:0;height:100%;background-color:#d9d9d9;cursor:col-resize;}.jxSplitBarVertical{position:absolute;display:block;line-height:1px;width:100%;left:0;height:10px;background-color:#d9d9d9;cursor:row-resize;}.jxSplitArea{overflow:hidden;border-top:1px solid #999;border-left:1px solid #999;border-right:1px solid #fff;border-bottom:1px solid #fff;background-color:#eee;}.jxSplitBarDrag{background-color:#c9c9c9;}.jxSnapHorizontalBefore{position:absolute;display:block;top:50%;left:0;margin-top:-25px;width:10px;height:50px;z-index:1;overflow:hidden;background-color:#eee;}.jxSnapHorizontalAfter{position:absolute;display:block;top:50%;left:0;margin-top:-25px;width:10px;height:50px;z-index:1;overflow:hidden;background-color:#eee;}.jxSnapVerticalBefore{position:absolute;display:block;top:0;left:50%;margin-left:-25px;width:50px;height:10px;z-index:1;overflow:hidden;background-color:#eee;}.jxSnapVerticalAfter{position:absolute;display:block;top:0;left:50%;margin-left:-25px;width:50px;height:10px;z-index:1;overflow:hidden;background-color:#eee;}.jxTabSetContainer{position:relative;display:block;width:200px;height:200px;margin:0;padding:0;border:1px solid #999;}.jxTabSetContainer .jxToolbarContainer,.jxTabSetContainer ul.jxToolbar{z-index:auto;border:none;}.tabContent{display:none;position:relative;width:100%;height:100%;overflow:auto;}.tabContentActive{display:block;}.jxTabBoxTop,.jxTabBoxBottom,.jxTabBoxLeft,.jxTabBoxRight{overflow:visible;}.jxTabBoxTop .jxBarTop,.jxTabBoxBottom .jxBarBottom,.jxTabBoxLeft .jxBarLeft,.jxTabBoxRight .jxBarRight{position:absolute;}li.jxTabItem{margin:0;padding:0;}.jxBarTop li.jxTabItem,.jxBarBottom li.jxTabItem{border:none;}.jxBarLeft li.jxTabItem,.jxBarRight li.jxTabItem{border:none;}a.jxTab{display:block;position:relative;margin:0;padding:0;border:1px solid #999;background-repeat:no-repeat;text-decoration:none;color:#000;}a.jxTab:hover{background-color:#ccc;}a.jxTab:active{background-color:#fff;}a.jxTabActive{background-color:#fff;}span.jxTabContent{display:block;font-size:0;line-height:0;margin:0;padding:0;}img.jxTabIcon{position:relative;width:16px;height:16px;background-position:center center;background-repeat:no-repeat;}span.jxTabLabel{display:block;position:relative;cursor:pointer;margin:0;padding:0;color:#000;font-family:Arial,Helvetica,sans-serif;font-size:11px;line-height:16px;}.jxTabBoxTop{margin-top:27px;}.jxTabBoxTop .jxBarTop{top:-27px;}.jxBarTop a.jxTab{float:left;margin:0 1px;padding:4px;}.jxBarTop span.jxTabContent{float:left;}.jxBarTop img.jxTabIcon{float:left;}.jxBarTop span.jxTabLabel{float:left;padding:0 4px 0 4px;}.jxBarTop a.jsTabActive{border-bottom:1px solid #fff;}.jxTabBoxBottom{margin-bottom:27px;}.jxTabBoxBottom .jxBarBottom{bottom:-27px;background-position:top;}.jxBarBottom a.jxTab{float:left;margin:0 1px;padding:4px;}.jxBarTop span.jxTabContent{float:left;}.jxBarTop img.jxTabIcon{float:left;}.jxBarTop span.jxTabLabel{float:left;padding:0 4px 0 4px;}.jxBarBottom a.jxTabActive{border-top:1px solid #fff;}.jxTabBoxLeft{margin-left:27px;}.jxTabBoxLeft .jxBarLeft{left:-27px;}.jxBarLeft a.jxTab{margin:1px 0 1px 2px;padding:4px;}.jxBarLeft a.jxTabActive{border-right:1px solid #fff;}.jxTabBoxRight{margin-right:27px;}.jxTabBoxRight .jxBarRight{right:-27px;background-position:left;}.jxBarRight a.jxTab{margin:1px 2px 1px 0;padding:7px;}.jxBarRight a.jxTabActive{border-left:1px solid #fff;}.jxToolbarContainer{display:block;position:relative;z-index:1;margin:0;padding:0;border:0;background-color:#d9d9d9;}.jxBarTop,.jxBarBottom{width:100%;height:auto;background-repeat:repeat-x;background-position:bottom;}.jxBarLeft,.jxBarRight{width:auto;height:100%;background-repeat:repeat-y;background-position:right;}.toolbarLabel{display:block;position:relative;float:left;margin:0;padding:0;font-family:Arial,Hevetica,sans-serif;font-size:11px;line-height:24px;color:#000;}ul.jxToolbar{display:block;position:relative;float:left;list-style-type:none;margin:0;padding:0;}.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{display:block;position:relative;float:left;font-size:0;line-height:0;padding:0;margin:0;}.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 .separator{display:block;position:relative;float:left;font-size:0;line-height:0;width:8px;height:18px;border:0;margin:0;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);}.jxBarLeft label.toolbarLabel,.jxBarLeft ul.jxToolbar,.jxBarLeft li.jxToolItem,.jxBarRight label.toolbarLabel,.jxBarRight ul.jxToolbar,.jxBarRight li.jxToolItem{clear:both;}.verticalToolbar{width:auto;}.verticalToolbar label.toolbarLabel,.verticalToolbar ul.jxToolbar,.verticalToolbar li.jxToolItem{clear:both;}.jxTree,.jxTreeRoot{position:relative;list-style:none;margin:0;padding:0;}.jxTreeNest{list-style:none;margin:0;padding:0;background-repeat:repeat-y;background-position:left top;}.jxTree li,.jxTreeRoot li{position:relative;margin:0;padding:0;background-repeat:no-repeat;background-position:left top;white-space:nowrap;width:100%;}.jxTree li{margin-left:16px;}.jxTree li.jxDisabled,.jxTreeRoot li.jxDisabled{opacity:.4;-moz-opacity:.4;filter:Alpha(opacity=40);}.jxTree a,.jxTreeRoot a{margin:0;padding:0;padding-left:2px;font-family:Arial,Helvetica,sans-serif;font-size:11px;color:#000;text-decoration:none;line-height:20px;}.jxTree a:hover,.jxTreeRoot a:hover{background-color:#E1EDFA;}.jxTree img,.jxTreeRoot img{border:0;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;font-weight:bold;}.jxTreeCutNode{opacity:.4;-moz-opacity:.4;filter:Alpha(opacity=40);}.jxTreeCutNode a:hover{background-color:#fff;}.jxTreeNode a,.jxTreeNode img,.jxTreeNode input{vertical-align:middle;}.jxTreeNodeLast a,.jxTreeNodeLast img,.jxTreeNodeLast input{vertical-align:middle;}.jxTreeNodeIcon{margin:0;}
\ No newline at end of file

Added: sandbox/jx2/jx/lib/jxskin_delicious.css
===================================================================
--- sandbox/jx2/jx/lib/jxskin_delicious.css	                        (rev 0)
+++ sandbox/jx2/jx/lib/jxskin_delicious.css	2008-08-28 12:29:20 UTC (rev 1482)
@@ -0,0 +1 @@
+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:'';}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:.4;filter:Alpha(opacity=40);}iframe.jxIframeShim{position:absolute;top:0;left:0;width:100%;height:100%;filter:Alpha(opacity:0);opacity:0;z-index:-1;}div.jxButtonContainer{display:block;position:relative;float:left;margin:2px;padding:0;border:none;}a.jxButton{display:block;position:relative;float:left;margin:0;padding:0 0 0 3px;border:none;background-image:url(../images/delicious/button_bg.png);background-position:left -56px;background-repeat:no-repeat;text-decoration:none;}ul.jxToolbar a.jxButton{background-position:left top;}span.jxButtonContent{display:block;position:relative;float:left;font-size:0;line-height:0;margin:0;padding:6px 6px 6px 3px;border:none;background-image:url(../images/delicious/button_bg.png);background-position:right -56px;background-repeat:no-repeat;}ul.jxToolbar span.jxButtonContent{background-position:right top;}a.jxButton:hover{background-position:left -224px;}ul.jxToolbar a.jxButton:hover{background-position:left -56px;}a.jxButton:hover span.jxButtonContent{background-position:right -224px;}ul.jxToolbar a.jxButton:hover span.jxButtonContent{background-position:right -56px;}ul.jxToolbar a.jxButtonActive,a.jxButtonActive{background-position:left -168px;}ul.jxToolbar a.jxButtonActive span.jxButtonContent,a.jxButtonActive span.jxButtonContent{background-position:right -168px;}ul.jxToolbar a.jxButtonActive:hover,a.jxButtonActive:hover{background-position:left -224px;}ul.jxToolbar a.jxButtonActive:hover span.jxButtonContent,a.jxButtonActive:hover span.jxButtonContent{background-position:right -224px;}ul.jxToolbar a.jxButton:active,a.jxButton:active,ul.jxToolbar a.jxButtonActive:active,a.jxButtonActive:active{background-position:left -112px;}ul.jxToolbar a.jxButton:active span.jxButtonContent,a.jxButton:active span.jxButtonContent,ul.jxToolbar a.jxButtonActive:active span.jxButtonContent,a.jxButtonActive:active span.jxButtonContent{background-position:right -112px;}ul.jxToolbar .jxDisabled a.jxButton:hover,ul.jxToolbar .jxDisabled a.jxButton:active,.jxDisabled a.jxButton:hover,.jxDisabled a.jxButton:active{background-position:left top;}ul.jxToolbar .jxDisabled a.jxButton:hover span.jxButtonContent,ul.jxToolbar .jxDisabled a.jxButton:active span.jxButtonContent,.jxDisabled a.jxButton:hover span.jxButtonContent,.jxDisabled a.jxButton:active span.jxButtonContent{background-position:right top;}img.jxButtonIcon{position:relative;float:left;width:16px;height:16px;background-position:center center;background-repeat:no-repeat;}span.jxButtonContent span{font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:16px;}span.jxButtonContent span.jxButtonLabel{display:block;position:relative;float:left;cursor:pointer;margin:0;padding:0 4px 0 4px;color:#000;font-size:11px;}a.jxButtonMenu span.jxButtonContent span,a.jxButtonFlyout span.jxButtonContent span{padding-right:16px;background-image:url(../images/delicious/emblems.png);background-position:right -16px;background-repeat:no-repeat;}a.jxButtonMulti span.jxButtonContent,a.jxButtonFlyout span.jxButtonContent{padding-left:0;padding-right:0;}a.jxButtonMulti span.jxButtonLabel{padding-left:0;padding-right:0;}.jxFlyout .jxChrome{background-image:url(../images/delicious/flyout_chrome.png);padding:5px 5px 7px 6px;}.jxFlyout{position:absolute;display:block;clear:both;float:none;z-index:100;margin:0;padding:0;font-size:12px;line-height:14px;}.jxFlyoutContent{position:relative;display:block;overflow:auto;margin:6px 6px 8px 7px;}.jxFlyout .jxBarRight,.jxFlyout .jxBarLeft{float:left;height:auto;width:auto;}.jxChrome{position:absolute;display:block;font-size:0;line-height:0;z-index:-1;width:100%;height:100%;top:0;left:0;}.jxChromeTL{position:absolute;overflow:hidden;left:0;top:0;width:50%;height:50%;}.jxChromeTR{position:absolute;overflow:hidden;left:50%;top:0;width:50%;height:50%;}.jxChromeBL{position:absolute;overflow:hidden;left:0;top:50%;width:50%;height:50%;}.jxChromeBR{position:absolute;overflow:hidden;left:50%;top:50%;width:50%;height:50%;}.jxChromeTL img{position:absolute;top:0;left:0;}.jxChromeTR img{position:absolute;top:0;right:0;}.jxChromeBL img{position:absolute;bottom:0;left:0;}.jxChromeBR img{position:absolute;bottom:0;right:0;}.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:0 solid #000;}.jxColorGrid td.emptyCell span{display:block;width:7px;height:7px;line-height:0;font-size:0;border:0 solid #000;padding:1px;margin:0;}.jxColorGrid a.colorSwatch{display:block;width:7px;height:7px;line-height:0;font-size:0;border:0 solid #000;margin:0;padding:1px;}.jxColorGrid a.borderWhite:hover{border:1px solid #fff;padding:0;}.jxColorGrid a.borderBlack:hover{border:1px solid #000;padding:0;}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');}span.jxButtonContent span.jxButtonSwatch{display:block;float:left;width:14px;height:14px;border:1px solid #000;background-image:url('../images/grid.png');padding-right:0!important;}span.jxButtonContent span.jxButtonSwatch span{display:block;width:14px;height:14px;position:absolute;padding-right:0;}div.jxColorPreview img{position:absolute;z-index:0;}div.jxColorPreview div.jxColorSelected{width:20px;height:10px;position:absolute;z-index:1;}div.jxColorPreview div.jxColorHover{width:20px;height:10px;position:absolute;bottom:0;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:0;right:0;width:16px;height:16px;}a.jxColorClose img{width:16px;height:16px;}div.jxCombo{position:relative;display:block;padding:0;padding-right:22px;margin:0;border:0;font-family:Arial,Helvetica,sans-serif;font-size:11px;z-index:1;line-height:24px;float:left;}.jxComboDiscloser{position:absolute;right:3px;top:3px;}.jxComboDiscloser img{width:16px;height:16px;border:0;}.jxComboInput{position:relative;display:block;float:left;line-height:14px;height:14px;padding:5px 10px;border:1px solid #f0f0f0;}div.jxComboOptions{position:absolute;height:auto;background-color:#fff;overflow:auto;border:1px solid #333;color:#000;z-index:1;font-family:Arial,Helvetica,sans-serif;font-size:11px;line-height:24px;}div.jxComboOptions ul{position:relative;display:block;margin:0;padding:0;border:none;list-style-type:none;}div.jxComboOptions li{position:relative;display:block;margin:0;padding:0;border:none;height:20px;}div.jxComboOptions a{position:relative;display:block;text-decoration:none;white-space:nowrap;line-height:20px;height:20px;color:#000;background-image:none;border:1px solid #fff;padding:0 4px;}div.jxComboOptions a:hover{background-image:url(../images/graphic/menu_bg.png);background-repeat:repeat-x;border:1px solid #C5E0FF;background-color:#CDE5FF;}div.jxComboOptions a.selected{font-weight:bold;background-color:#ffffb3;}.jxDialog .jxChrome{background-image:url(../images/delicious/dialog_chrome.png);}.jxDialog{display:block;z-index:1;}.jxDialogContentContainer{z-index:1;margin:0 11px 13px 12px;border:1px solid #b7b7b7;background-color:#f0f0f0;}.jxDialogModal{position:absolute;display:block;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.2;filter:Alpha(opacity=20);}.jxDialogContent{display:block;position:relative;overflow:auto;padding:0;z-index:1;}.jxDialogTitle{display:block;position:relative;background-image:url(../images/a_pixel.png);text-align:center;height:24px;line-height:24px;z-index:1;margin:6px 6px 0 7px;}.jxDialogMin .jxDialogTitle{margin-bottom:8px;}.jxDialogMoveable{cursor:move;}.jxDialogLabel{font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;line-height:21px;color:#000;white-space:nowrap;}.jxDialogResize{position:absolute;bottom:7px;right:6px;width:16px;height:16px;z-index:2;border:0;cursor:se-resize;background-image:url(../images/delicious/dialog_resize.png);}.jxDialogControls{position:absolute;top:3px;right:2px;height:16px;width:80px;}.jxDialogControls img{background-image:url('../images/panel_controls.png');background-repeat:no-repeat;border:0;margin:0;width:16px;height:16px;}.jxDialogClose img{background-position:0 -32px;}.jxDialogMenu img{background-position:0 -48px;}.jxDialogHelp img{background-position:0 -64px;}.jxDialogCollapse img{background-position:0 -16px;}.jxDialogMin .jxDialogCollapse img{background-position:0 0;}.jxDialogMax .jxDialogCollapse img{background-position:0 -16px;}.jxDialogLoading img{border:0;margin:0;width:16px;height:16px;visibility:hidden;position:absolute;top:1px;left:2px;}.jxDialogControls .jxButtonContainer,.jxDialogControls span.jxButtonContent,.jxDialogControls a.jxButton:hover span.jxButtonContent,.jxDialogControls a.jxButton:active span.jxButtonContent,.jxDialogControls a.jxButtonActive span.jxButtonContent,.jxDialogControls a.jxButtonActive:hover span.jxButtonContent,.jxDialogControls a.jxButtonActive:active span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton:hover span.jxButtonContent,.jxDialogControls .jxButtonDisabled a.jxButton:active span.jxButtonContent,.jxDialogControls a.jxButton,.jxDialogControls a.jxButton:hover,.jxDialogControls a.jxButton:active,.jxDialogControls a.jxButtonActive,.jxDialogControls a.jxButtonActive:hover,.jxDialogControls a.jxButtonActive:active,.jxDialogControls .jxButtonDisabled a.jxButton,.jxDialogControls .jxButtonDisabled a.jxButton:hover,.jxDialogControls .jxButtonDisabled a.jxButton:active{padding:0;margin:0;border:none;background-color:transparent;background-image:none;}.jxDialogControls a.jxButtonMenu span.jxButtonContent,.jxDialogControls a.jxButtonFlyout span.jxButtonContent{background-image:none;}.jxDialogControls a.jxButtonMenu span.jxButtonContent span,.jxDialogControls a.jxButtonFlyout span.jxButtonContent span{padding-right:0;}.jxDialogControls .jxToolbarContainer{position:absolute;right:0;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxDialogControls ul.jxToolbar{float:right;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxDialogControls .jxBarTop,.jxDialogControls .jxBarBottom,.jxDialogControls .jxBarLeft,.jxDialogControls .jxBarRight{width:auto;height:auto;}.jxDialogControls .jxBarTop ul.jxToolbar,.jxDialogControls .jxBarBottom ul.jxToolbar,.jxDialogControls .jxBarLeft ul.jxToolbar,.jxDialogControls .jxBarRight ul.jxToolbar,.jxDialogControls .jxBarTop li.jxToolItem,.jxDialogControls .jxBarBottom li.jxToolItem,.jxDialogControls .jxBarLeft li.jxToolItem,.jxDialogControls .jxBarRight li.jxToolItem{background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxGridContainer{position:absolute;top:0;left:0;border-left:0 solid #96a7b4;border-top:0 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:0;}.jxGridColHeadHide{height:0;line-height:0;font-size:0;background-color:#fff;white-space:normal;}.jxGridColHeadHide p,.jxGridRowHeadHide p{font-size:0;line-height:0;height:0;margin:0;padding:0;}.jxGridRowHeadHide{width:0;white-space:normal;}.jxGridCell{border-right:1px solid #cecece;border-bottom:1px solid #cecece;overflow:hidden;padding-left:3px;padding-right:3px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.jxGridColHead{border-top:0 solid #96a7b4;border-right:1px solid #96a7b4;border-bottom:1px solid #96a7b4;border-left:0 solid #96a7b4;background-color:#ebebeb;text-align:center;font-weight:bold;color:#45525f;}.jxGridRowHead{border-top:0 solid #96a7b4;border-right:1px solid #96a7b4;border-bottom:1px solid #96a7b4;border-left:0 solid #96a7b4;background-color:#ebebeb;text-align:center;font-weight:bold;color:#45525f;}.jxGridRowAll{background-color:#fff;}.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;}.jxGridRowHeaderPrelight{background-color:#dfdfdf;}.jxGridColumnHeaderPrelight{background-color:#dfdfdf;}.jxGridRowHeaderSelected{background-color:#6d7f8e;color:#fff;}.jxGridColumnHeaderSelected{background-color:#6d7f8e;color:#fff;}.jxMenuContainer .jxChrome{background-image:url(../images/delicious/flyout_chrome.png);padding:5px 5px 7px 6px;}a.jxButtonMenu span.jxMenuItemSpan{padding-right:16px;}.jxMenuContainer{position:absolute;display:block;z-index:200;padding:0;}ul.jxMenu,ul.jxSubMenu{display:block;position:relative;list-style-type:none;margin:0;padding:6px 6px 8px 7px;}li.jxMenuItemContainer{display:block;position:relative;margin:0;padding:0;}a.jxMenuItem{display:block;position:relative;text-decoration:none;border:1px solid #fff;font-family:Arial,Helvetica,sans-serif;font-size:11px;text-decoration:none;margin:2px 2px;padding:0;color:#000;}a.jxMenuItem:hover{background-image:url(../images/graphic/menu_bg.png);border:1px solid #C5E0FF;background-color:#CDE5FF;}a.jxMenuItem:hover span.jxMenuItemContent{border:1px solid #F4F9FF;border-bottom:1px solid #E4F0FF;}span.jxMenuItemContent{display:block;position:relative;font-family:Arial,Helvetica,sans-serif;font-size:0;line-height:0;white-space:nowrap;padding:0;margin:0;border:1px solid #fff;}a.jxButtonSubMenu span.jxMenuItemContent,a.jxButtonSubMenu:hover span.jxMenuItemContent{background-image:url(../images/delicious/emblems.png);background-position:right -48px;background-repeat:no-repeat;padding-right:20px;}img.jxMenuItemIcon{position:absolute;top:0;left:0;display:inline;width:16px;height:16px;background-position:left center;background-repeat:no-repeat;}span.jxMenuItemContent span{display:block;position:relative;cursor:pointer;margin:0;padding:0 0 0 20px;font-size:16px;line-height:16px;}span.jxMenuItemContent span.jxMenuItemLabel{color:#000;font-size:12px;}a.jxMenuItemActive img.jxMenuItemIcon{background-image:url(../images/delicious/emblems.png);background-position:2px -64px;background-repeat:no-repeat;}.jxMenuItemSet a.jxMenuItemActive img.jxMenuItemIcon{background-image:url(../images/delicious/emblems.png);background-position:2px -80px;background-repeat:no-repeat;}li.jxMenuItemDisabled span.jxMenuItemLabel{color:#ccc;}li.jxMenuItemDisabled a.jxMenuItem:hover{background-color:#fff;border:1px solid #fff;}ul.jxMenu span.jxMenuSeparator{display:block;font-size:10px;line-height:10px;background-image:url(../images/toolbar_separator_v.png);background-repeat:repeat-x;background-position:left center;}.jxPanel{display:block;position:relative;}.jxPanelContentContainer{overflow:hidden;background-color:#f0f0f0;}.jxPanelContent{position:relative;display:block;overflow:auto;background-color:#fff;margin:0;padding:0;}.jxPanelTitle{display:block;position:relative;background-image:url(../images/graphic/snap_bg.png);background-repeat:repeat-x;background-position:left top;height:22px;margin:0;padding:0;}.jxPanelLabel{padding-left:25px;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;line-height:21px;color:#000;white-space:nowrap;}.jxPanelControls{position:absolute;top:3px;right:2px;height:16px;width:80px;}.jxPanelControls img{background-image:url('../images/panel_controls.png');background-repeat:no-repeat;border:0;margin:0;width:16px;height:16px;}.jxPanelClose img{background-position:0 -32px;}.jxPanelMenu img{background-position:0 -48px;}.jxPanelHelp img{background-position:0 -64px;}.jxPanelCollapse img{background-position:0 -16px;}.jxPanelMin .jxPanelCollapse img{background-position:0 0;}.jxPanelMax .jxPanelCollapse img{background-position:0 -16px;}.jxPanelMaximize img{background-position:0 0;}.jxPanelLoading img{border:0;margin:0;width:16px;height:16px;visibility:hidden;position:absolute;top:1px;left:2px;}.jxPanelControls .jxButtonContainer,.jxPanelControls span.jxButtonContent,.jxPanelControls a.jxButton:hover span.jxButtonContent,.jxPanelControls a.jxButton:active span.jxButtonContent,.jxPanelControls a.jxButtonActive span.jxButtonContent,.jxPanelControls a.jxButtonActive:hover span.jxButtonContent,.jxPanelControls a.jxButtonActive:active span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton:hover span.jxButtonContent,.jxPanelControls .jxButtonDisabled a.jxButton:active span.jxButtonContent,.jxPanelControls a.jxButton,.jxPanelControls a.jxButton:hover,.jxPanelControls a.jxButton:active,.jxPanelControls a.jxButtonActive,.jxPanelControls a.jxButtonActive:hover,.jxPanelControls a.jxButtonActive:active,.jxPanelControls .jxButtonDisabled a.jxButton,.jxPanelControls .jxButtonDisabled a.jxButton:hover,.jxPanelControls .jxButtonDisabled a.jxButton:active{padding:0;margin:0;border:none;background-color:transparent;background-image:none;}.jxPanelControls a.jxButtonMenu span.jxButtonContent,.jxPanelControls a.jxButtonFlyout span.jxButtonContent{background-image:none;}.jxPanelControls a.jxButtonMenu span.jxButtonContent span,.jxPanelControls a.jxButtonFlyout span.jxButtonContent span{padding-right:0;}.jxPanelControls .jxToolbarContainer{position:absolute;right:0;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxPanelControls ul.jxToolbar{float:right;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxPanelControls .jxBarTop,.jxPanelControls .jxBarBottom,.jxPanelControls .jxBarLeft,.jxPanelControls .jxBarRight{width:auto;height:auto;}.jxPanelControls .jxBarTop ul.jxToolbar,.jxPanelControls .jxBarBottom ul.jxToolbar,.jxPanelControls .jxBarLeft ul.jxToolbar,.jxPanelControls .jxBarRight ul.jxToolbar,.jxPanelControls .jxBarTop li.jxToolItem,.jxPanelControls .jxBarBottom li.jxToolItem,.jxPanelControls .jxBarLeft li.jxToolItem,.jxPanelControls .jxBarRight li.jxToolItem{border:none;background-image:none;background-color:transparent;margin:0;padding:0;border:none;}.jxSplitBarHorizontal{position:absolute;line-height:1px;width:5px;height:100%;cursor:col-resize;background-color:#f0f0f0;}.jxSplitBarVertical{position:absolute;line-height:1px;width:100%;height:5px;cursor:row-resize;background-color:#f0f0f0;}.jxSplitContainer{margin:0;}.jxSplitArea{overflow:hidden;}.jxSplitBarDrag{background-color:#eee;}.jxTabSetContainer{position:relative;display:block;width:200px;height:200px;margin:0;padding:0;border:1px solid #d8d8d8;background-color:#fff;}.jxTabSetContainer .jxToolbarContainer{z-index:auto;}.tabContent{display:none;position:relative;width:100%;height:100%;overflow:auto;}.tabContentActive{display:block;}.jxTabBoxTop,.jxTabBoxBottom,.jxTabBoxLeft,.jxTabBoxRight{overflow:visible;}.jxTabBoxTop .jxBarTop,.jxTabBoxBottom .jxBarBottom,.jxTabBoxLeft .jxBarLeft,.jxTabBoxRight .jxBarRight{position:absolute;}li.jxTabItem{margin:0;padding:0;}.jxBarTop li.jxTabItem,.jxBarBottom li.jxTabItem{border:none;}.jxBarLeft li.jxTabItem,.jxBarRight li.jxTabItem{border:none;}a.jxTab{display:block;position:relative;margin:0;padding:0;border:none;background-repeat:no-repeat;text-decoration:none;color:#000;}a.jxTab:hover,a.jxTab:active,a.jxTabActive,a.jxTabActive:hover,a.jxTabActive:active,.jxDisabled a.jxButton:hover,.jxDisabled a.jxButton:active{border:none;}span.jxTabContent{display:block;font-size:0;line-height:0;margin:0;padding:0;background-repeat:no-repeat;}img.jxTabIcon{position:relative;width:16px;height:16px;background-position:center center;background-repeat:no-repeat;}span.jxTabLabel{display:block;position:relative;cursor:pointer;margin:0;padding:0;color:#000;font-family:Arial,Helvetica,sans-serif;font-size:11px;line-height:16px;}.jxTabBoxTop{margin-top:27px;}.jxTabBoxTop .jxBarTop{top:-27px;}.jxBarTop a.jxTab{float:left;padding-left:6px;background-image:url(../images/graphic/tab_top_bg.png);background-position:left 2px;border-bottom:1px solid #999;}.jxBarTop span.jxTabContent{float:left;padding:6px 6px 6px 0;background-image:url(../images/graphic/tab_top_bg.png);background-position:right 2px;}.jxBarTop img.jxTabIcon{float:left;}.jxBarTop span.jxTabLabel{float:left;padding:0 4px 0 4px;}.jxBarTop a.jxTab:hover{background-position:left top;}.jxBarTop a.jxTab:hover span.jxTabContent{background-position:right top;}.jxBarTop a.jxTabActive{background-position:left -56px;border-bottom:1px solid #fff;}.jxBarTop a.jxTabActive span.jxTabContent{background-position:right -56px;}.jxTabBoxBottom{margin-bottom:27px;}.jxTabBoxBottom .jxBarBottom{bottom:-27px;}.jxBarBottom li.jxTabItem{float:left;}.jxBarBottom a.jxTab{float:left;padding-left:6px;background-image:url(../images/graphic/tab_bottom_bg.png);background-position:left -2px;border-top:1px solid #999;}.jxBarBottom span.jxTabContent{float:left;padding:6px 6px 6px 0;background-image:url(../images/graphic/tab_bottom_bg.png);background-position:right -2px;}.jxBarBottom img.jxTabIcon{float:left;}.jxBarBottom span.jxTabLabel{float:left;padding:0 4px 0 4px;}.jxBarBottom a.jxTab:hover{background-position:left top;}.jxBarBottom a.jxTab:hover span.jxTabContent{background-position:right top;}.jxBarBottom a.jxTabActive{background-position:left -56px;border-top:1px solid #fff;}.jxBarBottom a.jxTabActive span.jxTabContent{background-position:right -56px;}.jxTabBoxLeft{margin-left:27px;}.jxTabBoxLeft .jxBarLeft{left:-27px;}.jxBarLeft a.jxTab{padding-top:6px;background-image:url(../images/graphic/tab_left_bg.png);background-position:2px top;border-right:1px solid #999;}.jxBarLeft span.jxTabContent{padding:0 6px 6px 6px;background-image:url(../images/graphic/tab_left_bg.png);background-position:2px bottom;}.jxBarLeft a.jxTab:hover{background-position:left top;}.jxBarLeft a.jxTab:hover span.jxTabContent{background-position:left bottom;}.jxBarLeft a.jxTabActive{background-position:-56px top;border-right:1px solid #fff;}.jxBarLeft a.jxTabActive span.jxTabContent{background-position:-56px bottom;}.jxTabBoxRight{margin-right:27px;}.jxTabBoxRight .jxBarRight{right:-27px;}.jxBarRight a.jxTab{padding-top:6px;background-image:url(../images/graphic/tab_right_bg.png);background-position:-2px top;border-left:1px solid #999;}.jxBarRight span.jxTabContent{padding:0 6px 6px 6px;background-image:url(../images/graphic/tab_right_bg.png);background-position:-2px bottom;}.jxBarRight a.jxTab:hover{background-position:left top;}.jxBarRight a.jxTab:hover span.jxTabContent{background-position:left bottom;}.jxBarRight a.jxTabActive{background-position:-56px top;border-left:1px solid #fff;}.jxBarRight a.jxTabActive span.jxTabContent{background-position:-56px bottom;}.jxToolbarContainer{display:block;position:relative;z-index:1;margin:0;padding:0;border:0;background-color:#f0f0f0;}.jxBarTop,.jxBarBottom{width:100%;height:auto;background-repeat:repeat-x;background-position:bottom;}.jxBarLeft,.jxBarRight{width:auto;height:100%;background-repeat:repeat-y;background-position:right;}.toolbarLabel{display:block;position:relative;float:left;margin:0;padding:0;font-family:Arial,Hevetica,sans-serif;font-size:11px;line-height:24px;color:#000;}ul.jxToolbar{display:block;position:relative;float:left;list-style-type:none;margin:0;padding:0;}.jxBarTop ul.jxToolbar,.jxBarBottom ul.jxToolbar,.jxBarLeft ul.jxToolbar,.jxBarRight ul.jxToolbar{border:none;}li.jxToolItem{display:block;position:relative;float:left;font-size:0;line-height:0;padding:0;margin:0;}.jxBarTop li.jxToolItem,.jxBarBottom li.jxToolItem,.jxBarLeft li.jxToolItem,.jxBarRight li.jxToolItem{border:none;}li.jxToolItem .separator{display:block;position:relative;float:left;font-size:0;line-height:0;width:8px;height:20px;border:0;margin:0;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);}.jxBarLeft label.toolbarLabel,.jxBarLeft ul.jxToolbar,.jxBarLeft li.jxToolItem,.jxBarRight label.toolbarLabel,.jxBarRight ul.jxToolbar,.jxBarRight li.jxToolItem{clear:both;}.verticalToolbar{width:auto;}.verticalToolbar label.toolbarLabel,.verticalToolbar ul.jxToolbar,.verticalToolbar li.jxToolItem{clear:both;}.jxTree,.jxTreeRoot{position:relative;display:block;list-style:none;margin:0;padding:0;}.jxTreeNest{list-style:none;margin:0;padding:0;background-repeat:repeat-y;background-position:left top;}.jxTree li,.jxTreeRoot li{position:relative;display:block;margin:0;padding:0;background-repeat:no-repeat;background-position:left top;white-space:nowrap;width:100%;font-size:0;line-height:0;}.jxTree li{margin-left:16px;}.jxTree li.jxDisabled,.jxTreeRoot li.jxDisabled{opacity:.4;-moz-opacity:.4;filter:Alpha(opacity=40);}.jxTree a,.jxTreeRoot a{position:relative;display:block;margin:0 0 0 14px;padding:0 0 0 20px;z-index:0;font-family:Arial,Helvetica,sans-serif;font-size:11px;color:#000;text-decoration:none;line-height:20px;height:20px;}.jxTree a:hover,.jxTreeRoot a:hover{background-image:url(../images/graphic/menu_bg.png);background-color:#CDE5FF;}.jxTreeNest{background-image:url(../images/tree_vert_line.png);}.jxTreeImage,.jxTreeIcon{position:absolute;display:inline;left:0;top:0;width:16px;height:20px;z-index:1;background-image:url(../images/delicious/tree.png);background-repeat:no-repeat;border:0;margin:0;}.jxTreeIcon{left:2px;}.jxTreeBranchOpen .jxTreeIcon,.jxTreeBranchLastOpen .jxTreeIcon{background-position:left -40px;}.jxTreeBranchOpen .jxTreeImage{background-position:left -100px;}.jxTreeBranchLastOpen .jxTreeImage{background-position:left -160px;}.jxTreeBranchClosed .jxTreeIcon,.jxTreeBranchLastClosed .jxTreeIcon{background-position:left -20px;}.jxTreeBranchClosed .jxTreeImage{background-position:left -80px;}.jxTreeBranchLastClosed .jxTreeImage{background-position:left -140px;}.jxTreeItem .jxTreeIcon,.jxTreeItemLast .jxTreeIcon{background-position:left 0;}.jxTreeItem .jxTreeImage{background-position:left -60px;}.jxTreeItemLast .jxTreeImage{background-position:left -120px;}.jxTreeItemSelected{background-color:#AFD4FA;font-weight:bold;}.jxTreeItem a,.jxTreeItem img,.jxTreeItem input,.jxTreeItemLast a,.jxTreeItemLast img,.jxTreeItemLast input,.jxTreeBranch a,.jxTreeBranch img,.jxTreeBranch input,.jxTreeBranchLast a,.jxTreeBranchLast img,.jxTreeBranchLast input{vertical-align:middle;}
\ No newline at end of file

Modified: sandbox/jx2/lib/ApplicationDefinition.js
===================================================================
--- sandbox/jx2/lib/ApplicationDefinition.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/lib/ApplicationDefinition.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -703,7 +703,7 @@
         var container;
         if (this.type == 'Toolbar' || this.type == 'Statusbar') {
             if ($(this.name)) {
-                container = new Jx.Toolbar(this.name, this.position);
+                container = new Jx.Toolbar({parent: this.name, position: this.position});
                 $(this.name).container = container;
             }
             this.createWidgets(widgetSet, container);
@@ -860,15 +860,15 @@
                     this.uniqueId[0]++;
                     if (container instanceof Jx.Toolbar) {
                         /* create a button for the widget */
-                        var tbItem = new Jx.ToolbarItem();
+                        var tbItem = new Jx.Toolbar.Item();
                         tbItem.domObj.id = name;
                         container.add(tbItem);
                         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) {
+                               container instanceof Jx.Menu.Context ||
+                               container instanceof Jx.Menu.SubMenu) {
                         var widget = widgetTag.create(widgetSet, '');
                         widget.id = name; 
                         if (widget.oMenu) {   //for widgets that extend MenuBase
@@ -876,11 +876,11 @@
                           widget.oMenu.domObj.widget = widget;
                           container.add(widget.oMenu);
                         } else {
-                          var action = new Jx.Action(OpenLayers.Function.bind(widget.activateTool, widget));
-                          var opt = {};
-                          opt.label = widgetTag.label;
-                          opt.image = widgetTag.imageUrl;
-                          var menuItem = new Jx.MenuItem(action, opt);
+                          var menuItem = new Jx.Menu.Item({
+                              label: widgetTag.label,
+                              image: widgetTag.imageUrl,
+                              onClick: OpenLayers.Function.bind(widget.activateTool, widget)
+                          });
                           menuItem.domObj.id = name;
                           menuItem.domObj.widget = widget;
                           container.add(menuItem);
@@ -894,17 +894,18 @@
             case 'Flyout':
                 /* create a menu */
                 var menu;
-                var opt = {};
-                opt.label = this.flyout.label;
-                opt.tooltip = this.flyout.tooltip;
-                opt.image = this.flyout.imageUrl;
-                opt.imageClass = this.flyout.imageClass;
+                var opt = {
+                    label: this.flyout.label,
+                    tooltip: this.flyout.tooltip,
+                    image: this.flyout.imageUrl,
+                    imageClass: this.flyout.imageClass
+                };
                 if (container instanceof Jx.Toolbar) {
                     menu = new Jx.Menu(opt);
                 } else if (container instanceof Jx.Menu || 
-                           container instanceof Jx.ContextMenu || 
-                           container instanceof Jx.SubMenu) {
-                    menu = new Jx.SubMenu(opt);
+                           container instanceof Jx.Menu.Context || 
+                           container instanceof Jx.Menu.SubMenu) {
+                    menu = new Jx.Menu.SubMenu(opt);
                 }
                 container.add(menu);
                 this.flyout.create(widgetSet, menu);
@@ -912,11 +913,11 @@
                 break;
             case 'Separator':
                 if (container instanceof Jx.Toolbar) {
-                    container.add(new Jx.ToolbarSeparator());
+                    container.add(new Jx.Toolbar.Separator());
                 } else if (container instanceof( Jx.Menu) || 
-                           container instanceof(Jx.SubMenu) ||
-                           container instanceof(Jx.ContextMenu)) {
-                    container.add(new Jx.MenuSeparator());
+                           container instanceof(Jx.Menu.SubMenu) ||
+                           container instanceof(Jx.Menu.Context)) {
+                    container.add(new Jx.Menu.Separator());
                 }
                 break;
         }

Modified: sandbox/jx2/lib/ButtonTool.js
===================================================================
--- sandbox/jx2/lib/ButtonTool.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/lib/ButtonTool.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -31,21 +31,19 @@
 
 Fusion.Tool.Button = OpenLayers.Class({
     bActive: null,
-    sActiveClass: 'jxButtonActive',
-    sDisabledClass: 'jxButtonDisabled',
   
     initialize : function(domObj, widgetTag)  {
         //console.log('Fusion.Tool.Button.initialize');
         var json = widgetTag.extension;
-        
-        this.buttonAction = new Jx.Action(OpenLayers.Function.bind(this.buttonClicked, this));
         if (domObj) {
-            var options = {};
-            options.imgPath = widgetTag.imageUrl;
-            options.imgClass = widgetTag.imageClass;
-            options.tooltip = widgetTag.tooltip;
-            options.label = widgetTag.label;
-            this._oButton = new Jx.Button(this.buttonAction, options);
+            var options = {
+                image: widgetTag.imageUrl,
+                imageClass: widgetTag.imageClass,
+                tooltip: widgetTag.tooltip,
+                label: widgetTag.label,
+                onClick: OpenLayers.Function.bind(this.buttonClicked, this)
+            };
+            this._oButton = new Jx.Button(options);
             domObj.appendChild(this._oButton.domObj);
         }
         this.bActive = false;
@@ -62,22 +60,26 @@
 
     observeEvent : function(sEvent, fnCB) {
         if (this._oButton) {
-             Event.observe(this._oButton.domObj, sEvent, fnCB);
+             OpenLayers.Event.observe(this._oButton.domObj, sEvent, fnCB);
         }
     },
     
     stopObserveEvent : function(sEvent, fnCB) {
         if (this._oButton) {
-             Event.stopObserving(this._oButton.domObj, sEvent, fnCB);
+             OpenLayers.Event.stopObserving(this._oButton.domObj, sEvent, fnCB);
         }
     },
     
     enableTool : function() {
-        this.buttonAction.setEnabled(true);
+        if (this._oButton) {
+            this._oButton.setEnabled(true);
+        }
     },
 
     disableTool : function() {
-        this.buttonAction.setEnabled(false);
+        if (this._oButton) {
+            this._oButton.setEnabled(false);
+        }
     },
 
     activateTool : function() {
@@ -89,9 +91,6 @@
         if (this._sImageURL != null && this._sImageURL.length > 0) {
             this._oButton.setImage(this._sImageURL);
         }
-        if (this.sActiveClass != '') {
-            Element.addClassName(this._oButton.domA, this.sActiveClass);
-        }
     },
 
     deactivateTool :  function() {
@@ -100,9 +99,6 @@
         if (!this._oButton) {
             return;
         }
-        if (this.sActiveClass != '') {
-            Element.removeClassName(this._oButton.domA, this.sActiveClass);
-        }
     },
 
     clickCB : function(e) { this.activateTool(); },

Modified: sandbox/jx2/lib/Map.js
===================================================================
--- sandbox/jx2/lib/Map.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/lib/Map.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -172,7 +172,7 @@
     
     setMenu: function() {  
         if (this.widgetTag.extension.MenuContainer) {
-            var contextMenu = new Jx.ContextMenu();
+            var contextMenu = new Jx.Menu.Context();
             var container = this.widgetSet.getContainerByName(this.widgetTag.extension.MenuContainer[0]);
             if (container) {
                 container.createWidgets(this.widgetSet, contextMenu);
@@ -910,7 +910,7 @@
      onContextMenu: function(e) {
          //console.log('oncontextmenu');
          if (this.oContextMenu && !this.bSupressContextMenu && this.isLoaded()) {
-             this.oContextMenu.show(e);
+             this.oContextMenu.show(new Event(e));
              this.contextMenuPosition = this.getEventPosition(e);
              OpenLayers.Event.stop(e);
          }

Modified: sandbox/jx2/lib/MenuBase.js
===================================================================
--- sandbox/jx2/lib/MenuBase.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/lib/MenuBase.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1,60 +1,61 @@
-/**
- * Fusion.Tool.MenuBase
- *
- * $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.Tool.MenuBase
- *
- * generic base class for implementing widgets that incorporate a menu
- * **********************************************************************/
- 
-Fusion.Tool.MenuBase = OpenLayers.Class({
-    /**
-     * constructor
-     */
-    initialize : function() {
-        //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;
-
-        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() {
-        //TODO: figure out how to enable and disable menu widgets
-        Fusion.Widget.prototype.enable.apply(this,[]);
-    },
-    
-    disable: function() {
-        Fusion.Widget.prototype.disable.apply(this,[]);
-    }
-});
+/**
+ * Fusion.Tool.MenuBase
+ *
+ * $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.Tool.MenuBase
+ *
+ * generic base class for implementing widgets that incorporate a menu
+ * **********************************************************************/
+ 
+Fusion.Tool.MenuBase = OpenLayers.Class({
+    /**
+     * constructor
+     */
+    initialize : function() {
+        //console.log('Fusion.Tool.MenuBase.initialize');
+        var options = {
+            image: this.widgetTag.imageUrl,
+            imageClass: this.widgetTag.imageClass,
+            tooltip: this.widgetTag.tooltip,
+            label: this.widgetTag.label
+        };
+
+        if ( $(this.widgetTag.name) ) { 
+          this.oMenu = new Jx.Menu(options);
+          $(this.widgetTag.name).appendChild(this.oMenu.domObj);
+        } else {
+          this.oMenu = new Jx.Menu.SubMenu(options);
+        }
+    },
+    
+    enable: function() {
+        //TODO: figure out how to enable and disable menu widgets
+        Fusion.Widget.prototype.enable.apply(this,[]);
+    },
+    
+    disable: function() {
+        Fusion.Widget.prototype.disable.apply(this,[]);
+    }
+});

Modified: sandbox/jx2/lib/fusion.js
===================================================================
--- sandbox/jx2/lib/fusion.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/lib/fusion.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1046,9 +1046,10 @@
     /* actual bootstrap execution code follows */
     
     Fusion._singleFile = singleFile;
-    var host = Fusion._getScriptLocation();    
+    var host = Fusion._getScriptLocation();
+    Jx.aPixel = document.createElement('img');
+    Jx.aPixel.src = '../jx/images/a_pixel.png';
     Jx.baseURL = host + 'jx/';
-    Jx.COMBINED_CSS = true;
     
     //determine the language to use and add resource bundles to be loaded to the core scripts
     var locale = navigator.language ?
@@ -1064,12 +1065,12 @@
     if (!Fusion._singleFile) {
         if (useCompressed) {
             var coreScripts = ['lib/OpenLayers/OpenLayers.js',
-                                'jx/lib/jx_compressed.js',
+                                'jx/lib/jxlib.js',
                                 'lib/fusion-compressed.js',
                                 'lib/excanvas/excanvas-compressed.js'];
         } else {
             var coreScripts = ['lib/OpenLayers/OpenLayers.js',
-                                'jx/lib/jx_combined.js',
+                                'jx/lib/jxlib.uncompressed.js',
                                 'lib/excanvas/excanvas-compressed.js',
                                 'lib/EventMgr.js',
                                 'lib/Error.js',

Modified: sandbox/jx2/templates/mapguide/standard/index.html
===================================================================
--- sandbox/jx2/templates/mapguide/standard/index.html	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/templates/mapguide/standard/index.html	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1,157 +1,157 @@
-<!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';
-    }
-    
-    body {
-      overflow: hidden;
-    }
-
-    #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;
-    }
-
-    #Scalebar {
-      position: absolute;
-    	bottom: 5px;
-    	left: 5px;
-    	z-index: 1001;
-    }
-
-
-    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 id="Scalebar"></div>
-      </div>
-    </div>
-  </div>
-
-  <div id="TaskPane"></div>
-  <div id="Statusbar"></div>
-  <div id="MapTip"></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>
+<!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';
+    }
+    
+    body {
+      overflow: hidden;
+    }
+
+    #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;
+    }
+
+    #Scalebar {
+      position: absolute;
+    	bottom: 5px;
+    	left: 5px;
+    	z-index: 1001;
+    }
+
+
+    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.PanelSet('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 id="Scalebar"></div>
+      </div>
+    </div>
+  </div>
+
+  <div id="TaskPane"></div>
+  <div id="Statusbar"></div>
+  <div id="MapTip"></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>

Modified: sandbox/jx2/templates/mapserver/standard/ApplicationDefinition.xml
===================================================================
--- sandbox/jx2/templates/mapserver/standard/ApplicationDefinition.xml	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/templates/mapserver/standard/ApplicationDefinition.xml	2008-08-28 12:29:20 UTC (rev 1482)
@@ -923,11 +923,11 @@
 
 <!-- LEGEND -->
 
-    <Widget xsi:type="WidgetType">
+    <!-- <Widget xsi:type="WidgetType">
       <Name>Legend</Name>
       <Type>Legend</Type>
       <StatusItem/>
-    </Widget>
+    </Widget> -->
 
 <!-- SELECTION -->
 

Modified: sandbox/jx2/templates/mapserver/standard/index.html
===================================================================
--- sandbox/jx2/templates/mapserver/standard/index.html	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/templates/mapserver/standard/index.html	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1,144 +1,138 @@
-<!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>
+<!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/lib/jxskin_delicious.css);
+
+    #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.PanelSet('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').resize({forceResize:true});
+    $('Toolbar').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

Modified: sandbox/jx2/widgets/ColorPicker.js
===================================================================
--- sandbox/jx2/widgets/ColorPicker.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/ColorPicker.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -59,8 +59,13 @@
             this.colorInput.widget = this;
         }
         
-        this.colorButton = new Jx.Button.Color({color: this.color, alpha: this.alpha, label: widgetTag.label, tooltip: widgetTag.tooltip});
-        this.colorButton.addColorChangeListener(this);
+        this.colorButton = new Jx.Button.Color({
+            color: this.color, 
+            alpha: this.alpha, 
+            label: widgetTag.label, 
+            tooltip: widgetTag.tooltip
+        });
+        this.colorButton.addEvent('colorChange', OpenLayers.Function.bind(this.colorChanged, this));
         
         if (this.domObj) {
             this.domObj.appendChild(this.colorButton.domObj);

Modified: sandbox/jx2/widgets/EditableScale.js
===================================================================
--- sandbox/jx2/widgets/EditableScale.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/EditableScale.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -45,7 +45,7 @@
         this.domScale = document.createElement('input');
         this.domScale.className = 'inputEditableScale';
         this.domObj.appendChild(this.domScale);
-        Event.observe(this.domScale, 'keypress', 
+        OpenLayers.Event.observe(this.domScale, 'keypress', 
            OpenLayers.Function.bindAsEventListener(this.keyPressHandler, this));
         this.precision = json.Precision ? parseInt(json.Precision[0]) : this.precision;
         

Modified: sandbox/jx2/widgets/LayerManager.js
===================================================================
--- sandbox/jx2/widgets/LayerManager.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/LayerManager.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -1,272 +1,272 @@
-/**
- * Fusion.Widget.LayerManager
- *
- * $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.LayerManager
- * 
- * Displays a LayerManager of all the layers in the map as a collapsable tree.
- *
- * ShowRootFolder (boolean, optional)
- *
- * This controls whether the tree will have a single root node that
- * contains the name of the map as its label.  By default, the root
- * node does not appear.  Set to "true" or "1" to make the root node
- * appear.
- *
- * RootFolderIcon: (string, optional)
- *
- * The url to an image to use for the root folder.  This only has an
- * affect if ShowRootFolder is set to show the root folder.
- *
- * LayerThemeIcon: (string, optional)
- *
- * The url to an image to use for layers that are currently themed.
- *
- * DisabledLayerIcon: (string, optional)
- *
- * The url to an image to use for layers that are out of scale.
- *
- * **********************************************************************/
-
-Fusion.Widget.LayerManager = OpenLayers.Class(Fusion.Widget,  {
-    currentNode: null,
-    bIsDrawn: false,
-    initialize : function(widgetTag) {
-        //console.log('LayerManager.initialize');
-
-        Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
-         
-        var json = widgetTag.extension;
-        this.delIconSrc = json.DeleteIcon ? json.DeleteIcon[0] : 'images/icons/select-delete.png';
-    
-        Fusion.addWidgetStyleSheet(widgetTag.location + 'LayerManager/LayerManager.css');
-        this.cursorNormal = ["url('images/grab.cur'),move", 'grab', '-moz-grab', 'move'];
-        this.cursorDrag = ["url('images/grabbing.cur'),move", 'grabbing', '-moz-grabbing', 'move'];
-        
-        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapLoaded, this));
-        this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, OpenLayers.Function.bind(this.mapLoaded, this));
-    },
-    
-   
-    mapLoaded: function() {
-        this.draw();
-    },
-    
-   
-   /**
-     * remove the dom objects representing the legend layers and groups
-     */
-    clear: function(node) {
-        while (node.childNodes.length > 0) {
-          this.clear(node.childNodes[0]);
-            node.remove(node.childNodes[0]);
-        }
-    },
-  
-    /**
-     * Draws the layer manager
-     *
-     * @param r Object the reponse xhr object
-     */
-    draw: function(r) {
-      if (this.mapList) {
-        //this.clear(this.mapList);
-        this.mapList.remove();
-        this.mapList = null;
-      }
-       
-      //create the master UL element to hold the list of layers
-      this.mapList = document.createElement('ul');
-      Element.addClassName(this.mapList, 'jxLman');
-      this.domObj.appendChild(this.mapList);
-        
-      //this processes the OL layers
-      var map = this.getMap();
-      for (var i=0; i<map.aMaps.length; ++i) {
-        var mapBlock = document.createElement('li');
-        Element.addClassName(this.mapBlock, 'jxLmanMap');
-        mapBlock.id = 'mapBlock_'+i;
-        
-        //add a handle so the map blocks can be re-arranged
-        var handle = document.createElement('a');
-        handle.innerHTML = map.aMaps[i]._sMapTitle;
-        Element.addClassName(handle, 'jxLmanHandle');
-        mapBlock.appendChild(handle);
-        
-        this.mapList.appendChild(mapBlock);
-        this.processMapBlock(mapBlock, map.aMaps[i]);
-      }
-      
-      if (map.aMaps.length >1) {
-        var options = [];
-        options.onUpdate = OpenLayers.Function.bind(this.updateMapBlock, this, map);
-        options.handle = 'jxLmanHandle';
-        options.scroll = this.domObj.id;
-        Sortable.create(this.mapList.id, options);
-      }
-    },
-
-    processMapBlock: function(blockDom, map) {
-      var mapBlockList = document.createElement('ul');
-      Element.addClassName(mapBlockList, 'jxLmanSet');
-      mapBlockList.id = 'fusionLayerManager_'+map.getMapName();
-      blockDom.appendChild(mapBlockList);
-      map.layerPrefix = 'layer_';   //TODO make this unique for each block
-      
-      //this process all layers within an OL layer
-      var processArray = map.aLayers;
-      if (map.bLayersReversed) {
-        processArray.reverse();
-      }
-      for (var i=0; i<processArray.length; ++i) {
-        var blockItem = document.createElement('li');
-        Element.addClassName(blockItem, 'jxLmanLayer');
-        blockItem.id = map.layerPrefix+i;
-        mapBlockList.appendChild(blockItem);
-        this.createItemHtml(blockItem, processArray[i]);
-        blockItem.layer = processArray[i];
-      }
-      
-      var options = [];
-      options.onUpdate = OpenLayers.Function.bind(this.updateLayer, this, map);
-      options.scroll = this.domObj.id;    //docs for this at: http://wiki.script.aculo.us/scriptaculous/show/Sortable.create
-      Position.includeScrollOffsets = true;
-      Sortable.create(mapBlockList.id, options);
-    },
-   
-  createItemHtml: function(parent, layer) {
-    var delIcon = document.createElement('img');
-    delIcon.src = this.delIconSrc;
-    Event.observe(delIcon, 'click', OpenLayers.Function.bind(this.deleteLayer, this, layer));
-    delIcon.style.visibility = 'hidden';
-    parent.appendChild(delIcon);
-    
-    var visSelect = document.createElement('input');
-    visSelect.type = 'checkbox';
-    Event.observe(visSelect, 'click', OpenLayers.Function.bind(this.visChanged, this, layer));
-    parent.appendChild(visSelect);
-    if (layer.visible) {
-      visSelect.checked = true;
-    } else {
-      visSelect.checked = false;
-    }
-    
-    var label = document.createElement('a');
-    label.innerHTML = layer.legendLabel;
-    Event.observe(label, 'mouseover', OpenLayers.Function.bind(this.setGrabCursor, this));
-    Event.observe(label, 'mousedown', OpenLayers.Function.bind(this.setDragCursor, this));
-    Event.observe(label, 'mouseout', OpenLayers.Function.bind(this.setNormalCursor, this));
-    parent.appendChild(label);
-    
-    Event.observe(parent, 'mouseover', OpenLayers.Function.bind(this.setHandleVis, this, delIcon));
-    Event.observe(parent, 'mouseout', OpenLayers.Function.bind(this.setHandleHide, this, delIcon));
-  },
-  
-  setHandleVis: function(delIcon) {
-    delIcon.style.visibility = 'visible';
-  },
-  
-  setHandleHide: function(delIcon) {
-    delIcon.style.visibility = 'hidden';
-  },
-  
-  setGrabCursor: function(ev) {
-    this.setCursor(this.cursorNormal, Event.element(ev) );
-  },
-  
-  setDragCursor: function(ev) {
-    this.setCursor(this.cursorDrag, Event.element(ev) );
-  },
-  
-  setNormalCursor: function(ev) {
-    this.setCursor('auto', Event.element(ev) );
-  },
-  
-  setCursor : function(cursor, domObj) {
-      this.cursor = cursor;
-      if (cursor && cursor.length && typeof cursor == 'object') {
-          for (var i = 0; i < cursor.length; i++) {
-              domObj.style.cursor = cursor[i];
-              if (domObj.style.cursor == cursor[i]) {
-                  break;
-              }
-          }
-      } else if (typeof cursor == 'string') {
-          domObj.style.cursor = cursor;
-      } else {
-          domObj.style.cursor = 'auto';  
-      }
-  },
-  
-  updateLayer: function(map, ul) {
-    //reorder the layers in the client as well as the session
-    var aLayerIndex = [];
-    var aIds = [];
-    var nLayers = ul.childNodes.length;
-    for (var i=0; i<nLayers; ++i) {
-      aIds[i] = ul.childNodes[i].id.split('_');
-      var index = parseInt(aIds[i].pop());
-      if (map.bLayersReversed) {
-        index = nLayers - (index+1);
-      }
-      aLayerIndex.push(index);
-      ul.childNodes[i].id = '';
-    }
-    
-    //reset the ID's on the LI elements to be in order
-    for (var i=0; i<ul.childNodes.length; ++i) {
-      var node = ul.childNodes[i];
-      aIds[i].push(i);
-      node.id = aIds[i].join('_');
-      node.childNodes[1].checked = node.layer.isVisible()
-    }
-    if (map.bLayersReversed) {
-      aLayerIndex.reverse();
-    }
-    map.reorderLayers(aLayerIndex);
-  },
-   
-  updateMapBlock: function(map, ul) {
-    //reorder the OL layers
-  },
-  
-  deleteLayer: function(layer, ev) {
-    var targetLI = Event.element(ev).parentNode;
-    var ul = targetLI.parentNode;
-    Element.remove(targetLI.id);
-    this.updateLayer(layer.oMap, ul);
-  },
-  
-  visChanged: function(layer2, ev) {
-    var target = Event.element(ev);
-    var layer = target.parentNode.layer;
-    if (target.checked) {
-      layer.show();
-    } else {
-      layer.hide();
-    }
-  }
-
-});
+/**
+ * Fusion.Widget.LayerManager
+ *
+ * $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.LayerManager
+ * 
+ * Displays a LayerManager of all the layers in the map as a collapsable tree.
+ *
+ * ShowRootFolder (boolean, optional)
+ *
+ * This controls whether the tree will have a single root node that
+ * contains the name of the map as its label.  By default, the root
+ * node does not appear.  Set to "true" or "1" to make the root node
+ * appear.
+ *
+ * RootFolderIcon: (string, optional)
+ *
+ * The url to an image to use for the root folder.  This only has an
+ * affect if ShowRootFolder is set to show the root folder.
+ *
+ * LayerThemeIcon: (string, optional)
+ *
+ * The url to an image to use for layers that are currently themed.
+ *
+ * DisabledLayerIcon: (string, optional)
+ *
+ * The url to an image to use for layers that are out of scale.
+ *
+ * **********************************************************************/
+
+Fusion.Widget.LayerManager = OpenLayers.Class(Fusion.Widget,  {
+    currentNode: null,
+    bIsDrawn: false,
+    initialize : function(widgetTag) {
+        //console.log('LayerManager.initialize');
+
+        Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+         
+        var json = widgetTag.extension;
+        this.delIconSrc = json.DeleteIcon ? json.DeleteIcon[0] : 'images/icons/select-delete.png';
+    
+        Fusion.addWidgetStyleSheet(widgetTag.location + 'LayerManager/LayerManager.css');
+        this.cursorNormal = ["url('images/grab.cur'),move", 'grab', '-moz-grab', 'move'];
+        this.cursorDrag = ["url('images/grabbing.cur'),move", 'grabbing', '-moz-grabbing', 'move'];
+        
+        this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapLoaded, this));
+        this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, OpenLayers.Function.bind(this.mapLoaded, this));
+    },
+    
+   
+    mapLoaded: function() {
+        this.draw();
+    },
+    
+   
+   /**
+     * remove the dom objects representing the legend layers and groups
+     */
+    clear: function(node) {
+        while (node.childNodes.length > 0) {
+          this.clear(node.childNodes[0]);
+            node.remove(node.childNodes[0]);
+        }
+    },
+  
+    /**
+     * Draws the layer manager
+     *
+     * @param r Object the reponse xhr object
+     */
+    draw: function(r) {
+      if (this.mapList) {
+        //this.clear(this.mapList);
+        this.mapList.remove();
+        this.mapList = null;
+      }
+       
+      //create the master UL element to hold the list of layers
+      this.mapList = document.createElement('ul');
+      this.mapList.className = 'jxLman';
+      this.domObj.appendChild(this.mapList);
+        
+      //this processes the OL layers
+      var map = this.getMap();
+      for (var i=0; i<map.aMaps.length; ++i) {
+        var mapBlock = document.createElement('li');
+        this.mapBlock.className = 'jxLmanMap';
+        mapBlock.id = 'mapBlock_'+i;
+        
+        //add a handle so the map blocks can be re-arranged
+        var handle = document.createElement('a');
+        handle.innerHTML = map.aMaps[i]._sMapTitle;
+        handle.className = 'jxLmanHandle';
+        mapBlock.appendChild(handle);
+        
+        this.mapList.appendChild(mapBlock);
+        this.processMapBlock(mapBlock, map.aMaps[i]);
+      }
+      
+      if (map.aMaps.length >1) {
+        var options = [];
+        options.onUpdate = OpenLayers.Function.bind(this.updateMapBlock, this, map);
+        options.handle = 'jxLmanHandle';
+        options.scroll = this.domObj.id;
+        Sortable.create(this.mapList.id, options);
+      }
+    },
+
+    processMapBlock: function(blockDom, map) {
+      var mapBlockList = document.createElement('ul');
+      mapBlockList.className = 'jxLmanSet';
+      mapBlockList.id = 'fusionLayerManager_'+map.getMapName();
+      blockDom.appendChild(mapBlockList);
+      map.layerPrefix = 'layer_';   //TODO make this unique for each block
+      
+      //this process all layers within an OL layer
+      var processArray = map.aLayers;
+      if (map.bLayersReversed) {
+        processArray.reverse();
+      }
+      for (var i=0; i<processArray.length; ++i) {
+        var blockItem = document.createElement('li');
+        blockItem.className = 'jxLmanLayer';
+        blockItem.id = map.layerPrefix+i;
+        mapBlockList.appendChild(blockItem);
+        this.createItemHtml(blockItem, processArray[i]);
+        blockItem.layer = processArray[i];
+      }
+      
+      var options = [];
+      options.onUpdate = OpenLayers.Function.bind(this.updateLayer, this, map);
+      options.scroll = this.domObj.id;    //docs for this at: http://wiki.script.aculo.us/scriptaculous/show/Sortable.create
+      Position.includeScrollOffsets = true;
+      Sortable.create(mapBlockList.id, options);
+    },
+   
+  createItemHtml: function(parent, layer) {
+    var delIcon = document.createElement('img');
+    delIcon.src = this.delIconSrc;
+    Event.observe(delIcon, 'click', OpenLayers.Function.bind(this.deleteLayer, this, layer));
+    delIcon.style.visibility = 'hidden';
+    parent.appendChild(delIcon);
+    
+    var visSelect = document.createElement('input');
+    visSelect.type = 'checkbox';
+    Event.observe(visSelect, 'click', OpenLayers.Function.bind(this.visChanged, this, layer));
+    parent.appendChild(visSelect);
+    if (layer.visible) {
+      visSelect.checked = true;
+    } else {
+      visSelect.checked = false;
+    }
+    
+    var label = document.createElement('a');
+    label.innerHTML = layer.legendLabel;
+    Event.observe(label, 'mouseover', OpenLayers.Function.bind(this.setGrabCursor, this));
+    Event.observe(label, 'mousedown', OpenLayers.Function.bind(this.setDragCursor, this));
+    Event.observe(label, 'mouseout', OpenLayers.Function.bind(this.setNormalCursor, this));
+    parent.appendChild(label);
+    
+    Event.observe(parent, 'mouseover', OpenLayers.Function.bind(this.setHandleVis, this, delIcon));
+    Event.observe(parent, 'mouseout', OpenLayers.Function.bind(this.setHandleHide, this, delIcon));
+  },
+  
+  setHandleVis: function(delIcon) {
+    delIcon.style.visibility = 'visible';
+  },
+  
+  setHandleHide: function(delIcon) {
+    delIcon.style.visibility = 'hidden';
+  },
+  
+  setGrabCursor: function(ev) {
+    this.setCursor(this.cursorNormal, Event.element(ev) );
+  },
+  
+  setDragCursor: function(ev) {
+    this.setCursor(this.cursorDrag, Event.element(ev) );
+  },
+  
+  setNormalCursor: function(ev) {
+    this.setCursor('auto', Event.element(ev) );
+  },
+  
+  setCursor : function(cursor, domObj) {
+      this.cursor = cursor;
+      if (cursor && cursor.length && typeof cursor == 'object') {
+          for (var i = 0; i < cursor.length; i++) {
+              domObj.style.cursor = cursor[i];
+              if (domObj.style.cursor == cursor[i]) {
+                  break;
+              }
+          }
+      } else if (typeof cursor == 'string') {
+          domObj.style.cursor = cursor;
+      } else {
+          domObj.style.cursor = 'auto';  
+      }
+  },
+  
+  updateLayer: function(map, ul) {
+    //reorder the layers in the client as well as the session
+    var aLayerIndex = [];
+    var aIds = [];
+    var nLayers = ul.childNodes.length;
+    for (var i=0; i<nLayers; ++i) {
+      aIds[i] = ul.childNodes[i].id.split('_');
+      var index = parseInt(aIds[i].pop());
+      if (map.bLayersReversed) {
+        index = nLayers - (index+1);
+      }
+      aLayerIndex.push(index);
+      ul.childNodes[i].id = '';
+    }
+    
+    //reset the ID's on the LI elements to be in order
+    for (var i=0; i<ul.childNodes.length; ++i) {
+      var node = ul.childNodes[i];
+      aIds[i].push(i);
+      node.id = aIds[i].join('_');
+      node.childNodes[1].checked = node.layer.isVisible()
+    }
+    if (map.bLayersReversed) {
+      aLayerIndex.reverse();
+    }
+    map.reorderLayers(aLayerIndex);
+  },
+   
+  updateMapBlock: function(map, ul) {
+    //reorder the OL layers
+  },
+  
+  deleteLayer: function(layer, ev) {
+    var targetLI = Event.element(ev).parentNode;
+    var ul = targetLI.parentNode;
+    Element.remove(targetLI.id);
+    this.updateLayer(layer.oMap, ul);
+  },
+  
+  visChanged: function(layer2, ev) {
+    var target = Event.element(ev);
+    var layer = target.parentNode.layer;
+    if (target.checked) {
+      layer.show();
+    } else {
+      layer.hide();
+    }
+  }
+
+});

Modified: sandbox/jx2/widgets/Legend.js
===================================================================
--- sandbox/jx2/widgets/Legend.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/Legend.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -242,19 +242,29 @@
        
         this.hideInvisibleLayers = (json.HideInvisibleLayers && json.HideInvisibleLayers[0]) == 'true' ? true : false;
         
-        this.refreshAction = new Jx.Action(OpenLayers.Function.bind(this.update, this));
-        this.refreshItem = new Jx.MenuItem(this.refreshAction, {label: OpenLayers.i18n('refresh')});
-        this.expandAllAction = new Jx.Action(OpenLayers.Function.bind(this.expandAll, this));
-        this.expandAllItem = new Jx.MenuItem(this.expandAllAction, {label: OpenLayers.i18n('expandAll')});
-        this.expandBranchAction = new Jx.Action(OpenLayers.Function.bind(this.expandBranch, this));
-        this.expandBranchItem = new Jx.MenuItem(this.expandBranchAction, {label: OpenLayers.i18n('expand')});
-        this.collapseAllAction = new Jx.Action(OpenLayers.Function.bind(this.collapseAll, this));
-        this.collapseAllItem = new Jx.MenuItem(this.collapseAllAction, {label: OpenLayers.i18n('collapseAll')});
-        this.collapseBranchAction = new Jx.Action(OpenLayers.Function.bind(this.collapseBranch, this));
-        this.collapseBranchItem = new Jx.MenuItem(this.collapseBranchAction, {label: OpenLayers.i18n('collapse')});
+        this.refreshItem = new Jx.Menu.Item({
+            label: OpenLayers.i18n('refresh'),
+            onClick: OpenLayers.Function.bind(this.update, this)
+        });
+        this.expandAllItem = new Jx.Menu.Item({
+            label: OpenLayers.i18n('expandAll'),
+            onClick: OpenLayers.Function.bind(this.expandAll, this)
+        });
+        this.expandBranchItem = new Jx.Menu.Item({
+            label: OpenLayers.i18n('expand'),
+            onClick: OpenLayers.Function.bind(this.expandBranch, this)
+        });
+        this.collapseAllItem = new Jx.Menu.Item({
+            label: OpenLayers.i18n('collapseAll'),
+            onClick: OpenLayers.Function.bind(this.collapseAll, this)
+        });
+        this.collapseBranchItem = new Jx.Menu.Item({
+            label: OpenLayers.i18n('collapse'),
+            onClick: OpenLayers.Function.bind(this.collapseBranch, this)
+        });
         //this.collapseBranchItem.disable();
         
-        this.contextMenu = new Jx.ContextMenu(this.sName);
+        this.contextMenu = new Jx.Menu.Context(this.sName);
         this.contextMenu.add(this.collapseBranchItem, 
                               this.expandBranchItem, 
                               this.refreshItem, 
@@ -263,11 +273,11 @@
         this.showRootFolder = (json.ShowRootFolder && json.ShowRootFolder[0] == 'false') ? false:true;
         this.showMapFolder = (json.ShowMapFolder && json.ShowMapFolder[0] == 'false') ? false:true;
         if (this.showRootFolder) {
-            var opt = {};
-            opt.label = OpenLayers.i18n('defaultMapTitle');
-            opt.data = null;
-            opt.imgTreeFolder = json.RootFolderIcon ? json.RootFolderIcon[0] : this.defRootFolderIcon;
-            opt.imgTreeFolderOpen = opt.imgTreeFolder;
+            var opt = {
+                label: OpenLayers.i18n('defaultMapTitle'),
+                isOpen: true,
+                contextMenu: this.contextMenu
+            };
             opt.isOpen = true;
             opt.contextMenu = this.contextMenu;
             this.oRoot = new Jx.TreeFolder(opt);
@@ -388,11 +398,11 @@
         if (group.displayInLegend) {
             /* make a 'namespace' on the group object to store legend-related info */
             group.legend = {};
-            var opt = {};
-            opt.label = group.legendLabel;
-            opt.data = group;
-            opt.contextMenu = this.contextMenu;
-            opt.isOpen = group.expandInLegend;
+            var opt = {
+                label: group.legendLabel,
+                contextMenu: this.contextMenu,
+                isOpen: group.expandInLegend
+            };
             group.legend.treeItem = new Jx.TreeFolder(opt);
             folder.append(group.legend.treeItem);
             group.legend.checkBox = document.createElement('input');
@@ -471,10 +481,10 @@
     },
     selectionChanged: function(o) {
         if (this.currentNode) {
-            Element.removeClassName(this.currentNode.domObj.childNodes[3], 'jxTreeSelectedNode');
+            $(this.currentNode.domObj.childNodes[3]).addClass('jxTreeSelectedNode');
         }
         this.currentNode = o;
-        Element.addClassName(this.currentNode.domObj.childNodes[3], 'jxTreeSelectedNode');
+        $(this.currentNode.domObj.childNodes[3]).addClass('jxTreeSelectedNode');
        
         if (o.data instanceof Fusion.Widget.Map.Group) {
             this.getMap().setActiveLayer(null);
@@ -571,13 +581,12 @@
     },
     
     createFolderItem: function(layer) {
-        var opt = {};
-        opt.label = layer.legendLabel == '' ? '&nbsp;' : layer.legendLabel;
-        opt.data = layer;
-        opt.isOpen = layer.expandInLegend;
-        opt.contextMenu = this.contextMenu;
-        opt.imgTreeFolderOpen = this.imgLayerThemeIcon;
-        opt.imgTreeFolder = this.imgLayerThemeIcon;
+        var opt = {
+            label: layer.legendLabel == '' ? '&nbsp;' : layer.legendLabel,
+            isOpen: layer.expandInLegend,
+            contextMenu: this.contextMenu,
+            // image overrides
+        };
         var folder = new Jx.TreeFolder(opt);
         folder.domObj.insertBefore(layer.legend.checkBox, folder.domObj.childNodes[1]);
         var layerInfo = layer.oMap.getLayerInfoUrl(layer.layerName);
@@ -605,20 +614,19 @@
         } else {
             opt.label = style.legendLabel == '' ? '&nbsp;' : style.legendLabel;
         }
-        opt.data = layer;
         opt.contextMenu = this.contextMenu;
         if (!style) {
-            opt.imgIcon = this.imgDisabledLayerIcon;
+            opt.image = this.imgDisabledLayerIcon;
             opt.enabled = false;
         } else {
           if (style.staticIcon) {
             if (style.staticIcon == Fusion.Constant.LAYER_DWF_TYPE) {
-              opt.imgIcon = this.imgLayerDWFIcon;
+              opt.image = this.imgLayerDWFIcon;
             } else {
-              opt.imgIcon = this.imgLayerRasterIcon;
+              opt.image = this.imgLayerRasterIcon;
             }
           } else {
-            opt.imgIcon = style.getLegendImageURL(scale, layer);
+            opt.image = style.getLegendImageURL(scale, layer);
           }
         }
        

Modified: sandbox/jx2/widgets/MapMenu.js
===================================================================
--- sandbox/jx2/widgets/MapMenu.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/MapMenu.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -60,11 +60,11 @@
             if (json.Folder) {
                 this.mapGroupData[mapGroup.maps[0].resourceId] = mapGroup; 
             } else {
-                var opt = {};
-                opt.label = mapGroup.mapId;
-                var data = mapGroup;
-                var action = new Jx.Action(this.switchMap.bind(this, data));
-                var menuItem = new Jx.MenuItem(action,opt);
+                var opt = {
+                    label: mapGroup.mapId,
+                    onClick: OpenLayers.Function.bind(this.switchMap, this, data)
+                };
+                var menuItem = new Jx.Menu.Item(opt);
                 this.oMenu.add(menuItem);
             }
         }
@@ -120,8 +120,8 @@
                         return this.initialView;
                     };
                 }
-                var action = new Jx.Action(this.switchMap.bind(this, data));
-                var menuItem = new Jx.MenuItem(action,opt);
+                opt.onClick = OpenLayers.Function.bind(this.switchMap, this, data);
+                var menuItem = new Jx.Menu.Item(opt);
                 
                 if (sPath == '') {
                     this.oMenu.add(menuItem);

Modified: sandbox/jx2/widgets/Measure.js
===================================================================
--- sandbox/jx2/widgets/Measure.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/Measure.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -198,7 +198,7 @@
                 this.totalDistanceMarker.domObj.parentNode != oDomElem) {
                 oDomElem.appendChild(this.totalDistanceMarker.domObj);
             }
-            Element.addClassName(this.totalDistanceMarker.domObj, 'divMeasureTotal');
+            this.totalDistanceMarker.domObj.className = 'divMeasureTotal';
             this.totalDistanceMarker.domObj.style.display = 'none';
             this.registerForEvent(Fusion.Event.MEASURE_CLEAR, OpenLayers.Function.bind(this.clearTotalDistance, this));  
             this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, OpenLayers.Function.bind(this.updateTotalDistance, this));

Modified: sandbox/jx2/widgets/Navigator.js
===================================================================
--- sandbox/jx2/widgets/Navigator.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/Navigator.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -48,7 +48,7 @@
         a.title = OpenLayers.i18n('panEast');
         a.coords = '27,176, 27,177, 40,190, 44,182, 44,159';
         var panEast = OpenLayers.Function.bind(this.pan, this, this.panAmount/100, 0);
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panEast, this));
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panEast, this));
         m.appendChild(a);
 
         var a = document.createElement('area');
@@ -57,7 +57,7 @@
         a.title = OpenLayers.i18n('panWest');
         a.coords = '24,177, 24,176, 7,159, 7,182, 11,190';
         var panWest = OpenLayers.Function.bind(this.pan, this, -this.panAmount/100, 0);
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panWest, this) );
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panWest, this) );
         m.appendChild(a);
 
         var a = document.createElement('area');
@@ -66,7 +66,7 @@
         a.title = OpenLayers.i18n('panSouth');
         a.coords = '25,178, 12,191, 21,197, 30,197, 39,191, 26,178';
         var panSouth = OpenLayers.Function.bind(this.pan, this, 0, -this.panAmount/100 );
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panSouth, this) );
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panSouth, this) );
         m.appendChild(a);
 
         var a = document.createElement('area');
@@ -75,7 +75,7 @@
         a.title = OpenLayers.i18n('panNorth');
         a.coords = '26,175, 43,158, 8,158, 25,175';
         var panNorth = OpenLayers.Function.bind(this.pan, this, 0, this.panAmount/100 );
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panNorth, this) );
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panNorth, this) );
         m.appendChild(a);
 
         var a = document.createElement('area');
@@ -84,7 +84,7 @@
         a.title = OpenLayers.i18n('zoomOut');
         a.coords = '25,142,8';
         var zoomOut = OpenLayers.Function.bind(this.zoom, this, 1/this.zoomOutFactor);
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomOut, this) );
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomOut, this) );
         m.appendChild(a);
 
         var a = document.createElement('area');
@@ -93,7 +93,7 @@
         a.title = OpenLayers.i18n('zoomIn');
         a.coords = '25,34,8';
         var zoomIn = OpenLayers.Function.bind(this.zoom, this, this.zoomInFactor);
-        Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomIn, this) );
+        OpenLayers.Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomIn, this) );
         m.appendChild(a);
 
         this.domObj.appendChild(m);
@@ -153,7 +153,7 @@
         var checkPosition = OpenLayers.Function.bind(this.checkPosition, this);
 
         //set up the navigator as draggable
-        new Draggable(this.domObj, {handle: handleDiv, starteffect: false, endeffect: false});
+        //new Draggable(this.domObj, {handle: handleDiv, starteffect: false, endeffect: false});
         //this observer pins the navigator to the top right after a drag so
         //that it moves if the window is resized
         var observer = {
@@ -163,15 +163,15 @@
         };
         //this should position the nav tool by the right rather than the left,
         //but it is broken in IE
-        Draggables.addObserver(observer);
+        //Draggables.addObserver(observer);
 
         var options = {};
         options.axis = 'vertical';
-        options.range = $R(1, 91);
+        options.range = {}; //$R(1, 91);
         options.sliderValue = 91;
         options.onChange = OpenLayers.Function.bind(this.scaleChanged, this);
-        this.slider = new Control.Slider(sliderHandle,sliderDiv, options);
-        this.slider.setDisabled();
+        //this.slider = new Control.Slider(sliderHandle,sliderDiv, options);
+        //this.slider.setDisabled();
         this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.updateSlider, this));
         this.getMap().registerForEvent(Fusion.Event.MAP_RESIZED, OpenLayers.Function.bind(this.checkPosition, this));
         this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.updateValue, this));
@@ -228,30 +228,30 @@
     updateSlider: function() {
         var olMap = this.getMap().oMapOL;
         if (olMap.baseLayer.singleTile) {
-            this.slider.values = [];
-            this.slider.range = $R(olMap.baseLayer.minResolution,olMap.baseLayer.maxResolution);
+            //this.slider.values = [];
+            //this.slider.range = $R(olMap.baseLayer.minResolution,olMap.baseLayer.maxResolution);
             this.bInternalChange = true;
-            this.slider.setValue(olMap.getResolution());
+            //this.slider.setValue(olMap.getResolution());
             this.bInternalChange = false;
         } else {
             var res = olMap.baseLayer.resolutions;
             var n = res.length;
             var max = res[0];
             var min = res[n-1];
-            this.slider.values = [];
-            this.slider.range = $R(1,91);
+            //this.slider.values = [];
+            //this.slider.range = $R(1,91);
             for (var i=0; i<n; i++) {
                 var r = res[i];
-                this.slider.values.push(parseInt((r/max)*91));
+                //this.slider.values.push(parseInt((r/max)*91));
             }
         }
-        this.slider.setEnabled();
+        //this.slider.setEnabled();
     },
 
     updateValue: function() {
         var olMap = this.getMap().oMapOL;
         this.bInternalChange = true;
-        this.slider.setValue(olMap.getResolution());
+        //this.slider.setValue(olMap.getResolution());
         this.bInternalChange = false;
     },
 

Modified: sandbox/jx2/widgets/Print.js
===================================================================
--- sandbox/jx2/widgets/Print.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/Print.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -83,21 +83,34 @@
         if (!this.dialog) {
 
             var size = Element.getPageDimensions();
+            var toolbar = new Jx.Toolbar({position: 'bottom'});
             var o = {
-                title: OpenLayers.i18n('printTitle'),
+                label: OpenLayers.i18n('printTitle'),
                 id: 'printablePage',
                 contentURL : this.dialogContentURL,
-                onContentLoaded: OpenLayers.Function.bind(this.contentLoaded, this),
+                onContentLoad: OpenLayers.Function.bind(this.contentLoaded, this),
                 imageBaseUrl: this.imageBaseUrl,
                 width: 350,
                 height: 250,
-                resizeable: true,
+                resize: true,
                 top: (size.height-250)/2,
                 left: (size.width-350)/2,
-                buttons: ['generate', 'cancel'],
-                handler: OpenLayers.Function.bind(this.handler, this)
+                toolbars: [toolbar]
             };
-            this.dialog = new Jx.Dialog(o);
+            var d = new Jx.Dialog(o);
+            toolbar.add(
+                new Jx.Button({
+                    label: 'Generate',
+                    onClick: OpenLayers.Function.bind(this.generate, this)
+                }),
+                new Jx.Button({
+                    label: 'Cancel',
+                    onClick: function() {
+                        d.close();
+                    }
+                })
+            );
+            this.dialog = d;
             
         }
         this.dialog.open();
@@ -139,16 +152,12 @@
         
     },
     
-    handler: function(button) {
-        if (button == 'generate') {
-            this.showTitle = this.dialog.getObj('dialogPrintShowtitle').checked;
-            this.pageTitle = this.dialog.getObj('dialogPrintTitle').value;
-            this.showLegend = this.dialog.getObj('dialogPrintShowlegend').checked;
-            this.showNorthArrow = this.dialog.getObj('dialogPrintShowNorthArrow').checked;
-            this.openPrintable();
-            
-        }
-        this.dialog.close();
+    generate: function() {
+        this.showTitle = this.dialog.getObj('dialogPrintShowtitle').checked;
+        this.pageTitle = this.dialog.getObj('dialogPrintTitle').value;
+        this.showLegend = this.dialog.getObj('dialogPrintShowlegend').checked;
+        this.showNorthArrow = this.dialog.getObj('dialogPrintShowNorthArrow').checked;
+        this.openPrintable();
     },
     
     openPrintable: function() {

Modified: sandbox/jx2/widgets/SaveMap.js
===================================================================
--- sandbox/jx2/widgets/SaveMap.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/SaveMap.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -61,8 +61,9 @@
             var layouts = json.PrintLayout;
             for (var i = 0; i < layouts.length; i++) {
                 var layout = layouts[i];
-                var opt = {};
-                opt.label = layout.Name[0];
+                var opt = {
+                    label: layout.Name[0]
+                };
                 var data = {rid:layout.ResourceId[0]};
                 if (layout.PageHeight) {
                     data.pageHeight = layout.PageHeight[0];
@@ -79,23 +80,28 @@
                 var menuItem = null;
                 if (layout.Scale) {
                     //create entries for weblayout specified scales
-                    menuItem = new Jx.SubMenu(opt);
+                    menuItem = new Jx.Menu.SubMenu(opt);
                     data.scales = [];
                     for (var j=0; j < layout.Scale.length; j++) {
                         data.scales.push(layout.Scale[j]);
-                        var scaleAction = new Jx.Action(this.setLayout.bind(this, data, j));
-                        var subMenuItem = new Jx.MenuItem(scaleAction,{label:layout.Scale[j]});
-                        menuItem.add(subMenuItem);
+                        menuItem.add(
+                            new Jx.Menu.Item({
+                                label:layout.Scale[j],
+                                onClick: OpenLayers.Function.bind(this.setLayout, this, data, j)
+                            })
+                        );
                     }
                     //add an entry for current scale
-                    var currentScaleAction = new Jx.Action(this.setLayout.bind(this, data));
-                    var currentScaleItem = new Jx.MenuItem(currentScaleAction,
-                                                         {label:'Current Scale'});
-                    menuItem.add(currentScaleItem);
+                    menuItem.add(
+                        new Jx.Menu.Item({
+                            label:'Current Scale',
+                            onClick: OpenLayers.Function.bind(this.setLayout, this, data)
+                        })
+                    );
                 } else {
                     //if there are no scales, the layout is used with current scale
-                    var action = new Jx.Action(this.setLayout.bind(this, data));
-                    menuItem = new Jx.MenuItem(action,opt);
+                    opt.onClick = OpenLayers.Function.bind(this.setLayout, this, data);
+                    menuItem = new Jx.Menu.Item(opt);
                 };
                 this.oMenu.add(menuItem);
             }

Modified: sandbox/jx2/widgets/SelectionPanel.js
===================================================================
--- sandbox/jx2/widgets/SelectionPanel.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/SelectionPanel.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -288,13 +288,13 @@
         this.layerList = document.createElement('select');
         this.layerList.className = 'layerSelector';
         this.toolbar.appendChild(this.layerList);
-        Event.observe(this.layerList, 'change',
+        OpenLayers.Event.observe(this.layerList, 'change',
                       OpenLayers.Function.bind(this.renderSelectionFeatures, this));
 
         this.featureList = document.createElement('select');
         this.featureList.className = 'featureSelector';
         this.toolbar.appendChild(this.featureList);
-        Event.observe(this.featureList, 'change',
+        OpenLayers.Event.observe(this.featureList, 'change',
                       OpenLayers.Function.bind(this.renderFeature, this));
 
         this.featureDiv = document.createElement('div');
@@ -317,7 +317,7 @@
         this.layerList.options.length = 0;
         this.featureList.options.length = 0;
         this.oSelection = null;
-        Element.addClassName(this.featureDiv, 'noSelection');
+        this.featureDiv.className = 'selectionPanelContent noSelection';
         this.featureDiv.innerHTML = OpenLayers.i18n('noSelection');
     },
 
@@ -334,7 +334,7 @@
         }
  
         //clear the layer list select box of any previous selections
-        Element.removeClassName(this.featureDiv, 'noSelection');
+        this.featureDiv.className = 'selectionPanelContent';
         while (this.layerList.length>0) {
           this.layerList.remove(this.layerList.options[0]);
         }
@@ -400,7 +400,7 @@
         for (var i=0; i<nProperties; i++) {
             var tr = document.createElement('tr');
             if (i%2) {
-                Element.addClassName(tr, 'oddRow');
+                tr.className = 'oddRow';
             }
             var th = document.createElement('th');
             th.innerHTML = aNames[i];
@@ -432,7 +432,7 @@
         var d = document.createElement('div');
         this.featureDiv = document.createElement('div');
         this.featureDiv.innerHTML = 'No Selection';
-        Element.addClassName(this.featureDiv, 'noSelection');
+        this.featureDiv.className = 'selectionPanelContent noSelection';
         d.appendChild(this.featureDiv);
 
         if (this.iResultsPerPage != 0) {
@@ -441,21 +441,20 @@
             this.previousButton.style.position = "absolute";
             this.previousButton.style.left = "0px";
             this.previousButton.style.padding = "3px";
-            Event.observe(this.previousButton, 'click',
+            OpenLayers.Event.observe(this.previousButton, 'click',
                           OpenLayers.Function.bind(this.renderLayers, this, 'prev'));
             this.nextButton = document.createElement('img');
             this.nextButton.src = this.oSelectionPanel.nextIcon;
             this.nextButton.style.position = "absolute";
             this.nextButton.style.right = "0px";
             this.nextButton.style.padding = "3px";
-            Event.observe(this.nextButton, 'click',
+            OpenLayers.Event.observe(this.nextButton, 'click',
                           OpenLayers.Function.bind(this.renderLayers, this, 'next'));
             
             d.appendChild(this.previousButton);
             d.appendChild(this.nextButton);
         }
 
-        Element.addClassName(this.featureDiv, 'selectionPanelContent');
         Fusion.addWidgetStyleSheet(this.oSelectionPanel.getLocation() + 'SelectionPanel/SelectionPanel.css');
         this.oSelectionPanel.domObj.appendChild(d);
     },
@@ -467,7 +466,7 @@
 
     clearSelection: function() {
         this.oSelection = null;
-        Element.addClassName(this.featureDiv, 'noSelection');
+        this.featureDiv.className = 'selectionPanelContent noSelection';
         this.featureDiv.innerHTML = OpenLayers.i18n('noSelection');
     },
     
@@ -540,7 +539,7 @@
         for (var i=0; i<page.length; i++) {
             var tr = document.createElement('tr');
             if (i%2) {
-                Element.addClassName(tr, 'oddRow');
+                tr.className = 'oddRow';
             }
             for (var j=0; j<page[i].length; j++) {
                 var td = document.createElement('td');

Modified: sandbox/jx2/widgets/TaskPane.js
===================================================================
--- sandbox/jx2/widgets/TaskPane.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/TaskPane.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -70,35 +70,34 @@
         tmpDiv.setAttribute('id', divName);
         this.toolbar = new Jx.Toolbar(tmpDiv,{left:0});
 
-        this.homeAction = new Jx.Action(OpenLayers.Function.bind(this.goHome, this));
-        this.toolbar.add(new Jx.Button(this.homeAction, 
-            {
+        this.homeButton = new Jx.Button({
             image: this.defHomeIcon, 
-            tooltip: OpenLayers.i18n('taskHome')
-            }
-        ));
-
-        this.prevAction = new Jx.Action(OpenLayers.Function.bind(this.gotoPrevTask, this));
-        this.toolbar.add(new Jx.Button(this.prevAction, 
-            {
+            tooltip: OpenLayers.i18n('taskHome'),
+            onClick: OpenLayers.Function.bind(this.goHome, this)
+        });
+        this.prevButton = new Jx.Button({
             image: this.defPrevTaskIcon, 
-            tooltip: OpenLayers.i18n('prevTask')
-            }
-        ));
-
-        this.nextAction = new Jx.Action(OpenLayers.Function.bind(this.gotoNextTask, this));
-        this.toolbar.add(new Jx.Button(this.nextAction, 
-            {
+            tooltip: OpenLayers.i18n('prevTask'),
+            onClick: OpenLayers.Function.bind(this.gotoPrevTask, this)
+        });
+        this.nextButton = new Jx.Button({
             image: this.defNextTaskIcon, 
-            tooltip: OpenLayers.i18n('nextTask')
-            }
-        ));
+            tooltip: OpenLayers.i18n('nextTask'),
+            onClick: OpenLayers.Function.bind(this.gotoNextTask, this)
+        });
+        this.toolbar.add(
+            this.homeButton,
+            this.prevButton,
+            this.nextButton
+        );
 
-        this.taskMenu = new Jx.Menu({image: this.defTaskListIcon, 
-                    label: OpenLayers.i18n('taskList'), 
-                    right:0});
-        Element.addClassName(this.taskMenu.domObj, 'taskMenu');
-        Element.addClassName(this.taskMenu.button.domObj, 'jxButtonContentLeft');
+        this.taskMenu = new Jx.Menu({
+            image: this.defTaskListIcon, 
+            label: OpenLayers.i18n('taskList'), 
+            right:0
+        });
+        //Element.addClassName(this.taskMenu.domObj, 'taskMenu');
+        //Element.addClassName(this.taskMenu.button.domObj, 'jxButtonContentLeft');
         this.toolbar.add(this.taskMenu);
         
         var iframeName = this.sName+'_IFRAME';
@@ -108,11 +107,12 @@
         this.iframe.setAttribute('id', iframeName);
         this.iframe.setAttribute('frameborder', 0);
         this.iframe.style.border = '0px solid #fff';
-        this.oTaskPane = new Jx.Panel({toolbar: tmpDiv, 
-                      label: OpenLayers.i18n('taskPane'), 
-                      content: this.iframe
+        this.oTaskPane = new Jx.Panel({
+            toolbar: tmpDiv, 
+            label: OpenLayers.i18n('taskPane'), 
+            content: this.iframe
         });
-        Element.addClassName(this.domObj, 'taskPanePanel');
+        //Element.addClassName(this.domObj, 'taskPanePanel');
         Fusion.addWidgetStyleSheet(widgetTag.location + 'TaskPane/TaskPane.css');
         
         this.domObj.appendChild(this.oTaskPane.domObj);
@@ -125,8 +125,8 @@
     },
     
     updateButtons: function() {
-        this.prevAction.setEnabled(this.nCurrentTask > 0);
-        this.nextAction.setEnabled(this.nCurrentTask < this.aExecutedTasks.length - 1);
+        this.prevButton.setEnabled(this.nCurrentTask > 0);
+        this.nextButton.setEnabled(this.nCurrentTask < this.aExecutedTasks.length - 1);
     },
     
     gotoPrevTask: function() {

Modified: sandbox/jx2/widgets/ViewOptions.js
===================================================================
--- sandbox/jx2/widgets/ViewOptions.js	2008-08-27 18:16:28 UTC (rev 1481)
+++ sandbox/jx2/widgets/ViewOptions.js	2008-08-28 12:29:20 UTC (rev 1482)
@@ -51,9 +51,11 @@
         //set up the root menu
         
         for (var key in this.options) {
-          var action = new Jx.Action(OpenLayers.Function.bind(this.setViewOptions, this, this.options[key]));
-          var menuItem = new Jx.MenuItem(action, {label: OpenLayers.i18n(key)} );
-          this.oMenu.add(menuItem);
+            var menuItem = new Jx.Menu.Item({
+                label: OpenLayers.i18n(key),
+                onClick: OpenLayers.Function.bind(this.setViewOptions, this, this.options[key])
+            });
+            this.oMenu.add(menuItem);
         }
 
         this.displayUnits = json.DisplayUnits ? json.DisplayUnits[0] : false;



More information about the fusion-commits mailing list