r1416 - in xwiki/trunk: core/src/main/java/com/xpn/xwiki/doc core/src/main/java/com/xpn/xwiki/objects/classes core/src/main/java/com/xpn/xwiki/objects/meta src/main/web src/main/web/skins/xwiki10 src/main/web/templates src/main/web/yui src/main/web/yui/calendar src/main/web/yui/calendar/assets src/main/web/yui/treeview src/main/web/yui/treeview/assets src/main/web/yui/yahoo src/test/java/com/xpn/xwiki/test

Ludovic Dubost ludovic at users.forge.objectweb.org
Fri Oct 20 06:34:06 CEST 2006


Author: ludovic
Date: 2006-10-20 06:34:05 +0200 (Fri, 20 Oct 2006)
New Revision: 1416

Added:
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBTreeListClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListItem.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBTreeListMetaClass.java
   xwiki/trunk/src/main/web/templates/treeview.vm
   xwiki/trunk/src/main/web/yui/
   xwiki/trunk/src/main/web/yui/calendar/
   xwiki/trunk/src/main/web/yui/calendar/README
   xwiki/trunk/src/main/web/yui/calendar/assets/
   xwiki/trunk/src/main/web/yui/calendar/assets/calendar.css
   xwiki/trunk/src/main/web/yui/calendar/assets/callt.gif
   xwiki/trunk/src/main/web/yui/calendar/assets/calrt.gif
   xwiki/trunk/src/main/web/yui/calendar/assets/calx.gif
   xwiki/trunk/src/main/web/yui/calendar/calendar-debug.js
   xwiki/trunk/src/main/web/yui/calendar/calendar-min.js
   xwiki/trunk/src/main/web/yui/calendar/calendar.js
   xwiki/trunk/src/main/web/yui/treeview/
   xwiki/trunk/src/main/web/yui/treeview/README
   xwiki/trunk/src/main/web/yui/treeview/assets/
   xwiki/trunk/src/main/web/yui/treeview/assets/check0.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/check1.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/check2.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/lm.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/lmh.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/ln.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/loading.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/lp.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/lph.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tm.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tmh.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tn.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tp.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tph.gif
   xwiki/trunk/src/main/web/yui/treeview/assets/tree.css
   xwiki/trunk/src/main/web/yui/treeview/assets/vline.gif
   xwiki/trunk/src/main/web/yui/treeview/checknode.js
   xwiki/trunk/src/main/web/yui/treeview/treeview-debug.js
   xwiki/trunk/src/main/web/yui/treeview/treeview-min.js
   xwiki/trunk/src/main/web/yui/treeview/treeview.js
   xwiki/trunk/src/main/web/yui/yahoo/
   xwiki/trunk/src/main/web/yui/yahoo/README
   xwiki/trunk/src/main/web/yui/yahoo/yahoo-debug.js
   xwiki/trunk/src/main/web/yui/yahoo/yahoo-min.js
   xwiki/trunk/src/main/web/yui/yahoo/yahoo.js
   xwiki/trunk/src/test/java/com/xpn/xwiki/test/ClassAdvancedTest.java
Modified:
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java
   xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/MetaClass.java
   xwiki/trunk/src/main/web/skins/xwiki10/layoutvars.vm
   xwiki/trunk/src/main/web/templates/viewheader.vm
   xwiki/trunk/src/test/java/com/xpn/xwiki/test/ClassesTest.java
Log:
Added Tree Field in List using Simple Select and using Yahoo Tree component
Commited the yahoo calendar component that will be used for the DateClass
Fix two small bugs in ListClass recently commited


Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -74,10 +74,12 @@
 import java.lang.ref.SoftReference;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.Class;
 import java.net.URL;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.*;
+import java.util.Collection;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
@@ -2119,6 +2121,32 @@
         bobject.setStringValue(fieldName, value);
     }
 
+    public List getListValue(String className, String fieldName) {
+        BaseObject obj = getObject(className);
+        if (obj == null)
+            return new ArrayList();
+        return obj.getListValue(fieldName);
+    }
+
+    public List getListValue(String fieldName) {
+        BaseObject object = getFirstObject(fieldName, null);
+        if (object == null)
+            return new ArrayList();
+
+        return object.getListValue(fieldName);
+    }
+
+    public void setListValue(String className, String fieldName, List value) {
+        BaseObject bobject = getObject(className);
+        if (bobject == null) {
+            bobject = new BaseObject();
+            addObject(className, bobject);
+        }
+        bobject.setName(getFullName());
+        bobject.setClassName(className);
+        bobject.setListValue(fieldName, value);
+    }
+
     public void setLargeStringValue(String className, String fieldName, String value) {
         BaseObject bobject = getObject(className);
         if (bobject == null) {
@@ -2930,4 +2958,27 @@
     public String getValidationScript() {
         return validationScript;
     }
+
+    public BaseObject newObject(String classname, XWikiContext context) throws XWikiException {
+        int nb = createNewObject(classname, context);
+        return getObject(classname, nb);
+    }
+
+    public BaseObject getObject(String classname, boolean create, XWikiContext context) {
+        try {
+            BaseObject obj = getObject(classname);
+
+            if ((obj == null) && create) {
+                return newObject(classname, context);
+            }
+
+            if (obj == null)
+                return null;
+            else
+                return obj;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
 }

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -467,6 +467,7 @@
             list_class.setPrettyName(fieldPrettyName);
             list_class.setSize(size);
             list_class.setMultiSelect(multiSelect);
+            list_class.setRelationalStorage(multiSelect);
             list_class.setSql(sql);
             list_class.setObject(this);
             put(fieldName, list_class);
@@ -475,6 +476,26 @@
         return false;
     }
 
+    public boolean addDBTreeListField(String fieldName, String fieldPrettyName, String sql) {
+        return addDBTreeListField(fieldName, fieldPrettyName, 1, false, sql);
+    }
+
+    public boolean addDBTreeListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String sql) {
+        if (get(fieldName)==null) {
+            DBTreeListClass list_class = new DBTreeListClass();
+            list_class.setName(fieldName);
+            list_class.setPrettyName(fieldPrettyName);
+            list_class.setSize(size);
+            list_class.setMultiSelect(multiSelect);
+            list_class.setRelationalStorage(multiSelect);
+            list_class.setSql(sql);
+            list_class.setObject(this);
+            put(fieldName, list_class);
+            return true;
+        }
+        return false;
+    }
+
     public void setCustomMapping(String customMapping) {
         this.customMapping = customMapping;
     }

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -33,6 +33,11 @@
 import java.util.HashMap;
 
 public class DBListClass extends ListClass {
+
+    public DBListClass(String name, String prettyname, PropertyMetaClass wclass) {
+        super(name, prettyname, wclass);
+    }
+
     public DBListClass(PropertyMetaClass wclass) {
         super("dblist", "DB List", wclass);
     }
@@ -41,21 +46,54 @@
         this(null);
     }
 
-    public List getList(XWikiContext context) {
+    public List makeList(List list) {
+        List list2 = new ArrayList();
+        for (int i=0;i<list.size();i++) {
+            Object result = list.get(i);
+            if (result instanceof String) {
+                list2.add(new ListItem((String) result));
+            } else {
+                Object[] res = (Object[]) result;
+                if (res.length==1)
+                 list2.add(new ListItem(res[0].toString()));
+                else if (res.length==2)
+                 list2.add(new ListItem(res[0].toString(), res[1].toString()));
+                else
+                 list2.add(new ListItem(res[0].toString(), res[1].toString(), res[2].toString()));
+            }
+        }
+        return list2;
+    }
+
+    public List getDBList(XWikiContext context) {
         XWiki xwiki = context.getWiki();
+        String query = getQuery(context);
+
+        if (query==null)
+         return new ArrayList();
+
         try {
-        	if (xwiki.getHibernateStore()!=null)
-        		return xwiki.search(getSql(), context);
+        	if ((xwiki.getHibernateStore()!=null)&&(!query.startsWith("/")))
+        		return makeList(xwiki.search(query, context));
         	else
-        		return ((QueryPlugin)xwiki.getPlugin("query", context)).xpath(getSql()).list();
+        		return makeList(((QueryPlugin)xwiki.getPlugin("query", context)).xpath(query).list());
         } catch (Exception e) {
             e.printStackTrace();
             return new ArrayList();
         }
     }
 
+    public List getList(XWikiContext context) {
+        List dblist = getDBList(context);
+        List list = new ArrayList();
+        for (int i=0;i<dblist.size();i++) {
+            list.add(((ListItem)dblist.get(i)).getId());
+        }
+        return list;
+    }
+
     public Map getMap(XWikiContext context) {
-        List list = getList(context);
+        List list = getDBList(context);
         Map map = new HashMap();
         if ((list==null)||(list.size()==0))
          return map;
@@ -64,16 +102,54 @@
             if (res instanceof String)
              map.put(res, res);
             else {
-                String[] res2 = (String[]) res;
-                if (res2.length==1)
-                    map.put(res2[0], res2[0]);
-                else
-                    map.put(res2[0], res2[1]);
+                ListItem item = (ListItem) res;
+                map.put(item.getId(), item);
             }
         }
         return map;
     }
 
+    public String getQuery(XWikiContext context) {
+        String sql = getSql();
+        if ((sql==null)||(sql.trim().equals(""))) {
+            String classname = getClassname();
+            String idField = getIdField();
+            String valueField = getValueField();
+            if ((valueField==null)||(valueField.trim().equals("")))
+             valueField =  idField;
+            if (context.getWiki().getHibernateStore()!=null) {
+             String select = "select ";
+             String tables = " from XWikiDocument as doc, BaseObject as obj";
+             String where = " where doc.fullName=obj.name and obj.className='" + classname + "'";
+             if (idField.startsWith("doc.")||idField.startsWith("obj."))
+              select += idField + ",";
+             else {
+                 select += "idprop.value,";
+                 tables += ", StringProperty as idprop";
+                 where += " and obj.id=idprop.id.id and idprop.id.name='" + idField + "'";
+             }
+                if (valueField.startsWith("doc.")||valueField.startsWith("obj."))
+                 select += valueField + ",";
+                else {
+                    if (idField.equals(valueField)) {
+                        select += "idprop.value,";
+                    } else {
+                    select += "valueprop.value,";
+                    tables += ", StringProperty as valueprop";
+                    where += " and obj.id=valueprop.id.id and valueprop.id.name='" + valueField + "'";
+                    }
+                }
+                // Let's create the sql
+                sql = select +  tables + where;
+            } else {
+                // TODO: query plugin impl.
+                // We need to generate the right query for the query plugin
+            }
+
+        }
+        return sql;
+    }
+
     public String getSql() {
         return getLargeStringValue("sql");
     }
@@ -81,4 +157,28 @@
     public void setSql(String sql) {
         setLargeStringValue("sql", sql);
     }
+
+    public String getClassname() {
+        return getStringValue("classname");
+    }
+
+    public void setClassname(String classname) {
+        setStringValue("classname", classname);
+    }
+
+    public String getIdField() {
+        return getStringValue("idField");
+    }
+
+    public void setIdField(String idField) {
+        setStringValue("idField", idField);
+    }
+
+    public String getValueField() {
+        return getStringValue("valueField");
+    }
+
+    public void setValueField(String valueField) {
+        setStringValue("valueField", valueField);
+    }
 }

Added: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBTreeListClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBTreeListClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/DBTreeListClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,214 @@
+package com.xpn.xwiki.objects.classes;
+
+import com.xpn.xwiki.objects.meta.PropertyMetaClass;
+import com.xpn.xwiki.objects.BaseCollection;
+import com.xpn.xwiki.objects.BaseProperty;
+import com.xpn.xwiki.objects.ListProperty;
+import com.xpn.xwiki.objects.DBStringListProperty;
+import com.xpn.xwiki.XWikiContext;
+import com.sun.org.apache.bcel.internal.generic.Select;
+
+import java.util.*;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.ecs.xhtml.select;
+import org.apache.ecs.xhtml.option;
+
+public class DBTreeListClass extends DBListClass {
+
+    public DBTreeListClass(PropertyMetaClass wclass) {
+        super("dbtreelist", "DB Tree List", wclass);
+    }
+
+    public DBTreeListClass() {
+        this(null);
+    }
+
+    public String getParentField() {
+        return getStringValue("parentField");
+    }
+
+    public void setParentField(String parentField) {
+        setStringValue("parentField", parentField);
+    }
+
+    public Map getTreeMap(XWikiContext context) {
+        List list = getDBList(context);
+        Map map = new HashMap();
+        if ((list==null)||(list.size()==0))
+         return map;
+        for(int i=0;i<list.size();i++) {
+            Object result = list.get(i);
+            if (result instanceof String) {
+                ListItem item = new ListItem((String)result);
+                map.put(result, item);
+            }
+            else {
+                ListItem item = (ListItem) result;
+                addToList(map, item.getParent(), item);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Gets an ordered list of items in the tree
+     * This is necessary to make sure childs are coming after their parents
+     * @param treemap
+     * @return  list of ListItems
+     */
+    protected List getTreeList(Map treemap) {
+        List list = new ArrayList();
+        addToTreeList(list, treemap, "");
+        return list;
+    }
+
+    protected void addToTreeList(List treelist, Map treemap, String parent) {
+        List list = (List)treemap.get(parent);
+        if (list!=null) {
+            for (int i=0;i<list.size();i++) {
+                ListItem item = (ListItem) list.get(i);
+                treelist.add(item);
+                addToTreeList(treelist, treemap, item.getId());
+            }
+        }
+    }
+
+    protected void addToList(Map map, String key, ListItem item) {
+        List list = (List)map.get(key);
+        if (list==null) {
+            list = new ArrayList();
+            map.put(key, list);
+        }
+        list.add(item);
+    }
+
+    public void displayEdit(StringBuffer buffer, String name, String prefix, BaseCollection object, XWikiContext context) {
+        VelocityContext vcontext = (VelocityContext) context.get("vcontext");
+        List selectlist;
+        BaseProperty prop = (BaseProperty) object.safeget(name);
+        if (prop == null) {
+            selectlist = new ArrayList();
+        } else if ((prop instanceof ListProperty) || (prop instanceof DBStringListProperty)) {
+            selectlist = (List) prop.getValue();
+        } else {
+            selectlist = new ArrayList();
+            selectlist.add(prop.getValue());
+        }
+
+        if (isPicker()) {
+            Map map = getTreeMap(context);
+            vcontext.put("selectlist", selectlist);
+            vcontext.put("fieldname", prefix + name);
+            vcontext.put("tree", map);
+            vcontext.put("treelist", getTreeList(map));
+            String result = context.getWiki().parseTemplate("treeview.vm", context);
+            if (result.equals(""))
+                displayTreeSelectEdit(buffer, name, prefix, object, context);
+            else {
+                displayHidden(buffer, name, prefix, object, context);
+                buffer.append(result);
+            }
+        } else {
+            displayTreeSelectEdit(buffer, name, prefix, object, context);
+        }
+    }
+
+    protected void addToSelect(select select, List selectlist, Map map, Map treemap, String parent, String level, XWikiContext context) {
+        List list = (List)treemap.get(parent);
+        if (list!=null) {
+            for (int i=0;i<list.size();i++) {
+                ListItem item = (ListItem) list.get(i);
+                String display = level + getDisplayValue(item.getId(), map, context);
+                option option = new option(item.getId(), item.getId());
+                option.addElement(display);
+                if (selectlist.contains(item.getId()))
+                    option.setSelected(true);
+                select.addElement(option);
+                addToSelect(select, selectlist, map, treemap, item.getId(), level + "&nbsp;", context);
+            }
+        }
+    }
+
+    protected void displayTreeSelectEdit(StringBuffer buffer, String name, String prefix, BaseCollection object, XWikiContext context) {
+		select select = new select(prefix + name, 1);
+		select.setMultiple(isMultiSelect());
+		select.setSize(getSize());
+		select.setName(prefix + name);
+		select.setID(prefix + name);
+
+        Map map = getMap(context);
+        Map treemap = getTreeMap(context);
+		List selectlist;
+
+		BaseProperty prop = (BaseProperty) object.safeget(name);
+		if (prop == null) {
+			selectlist = new ArrayList();
+		} else if ((prop instanceof ListProperty) || (prop instanceof DBStringListProperty)) {
+			selectlist = (List) prop.getValue();
+		} else {
+			selectlist = new ArrayList();
+			selectlist.add(prop.getValue());
+		}
+
+		// Add options from Set
+        addToSelect(select, selectlist, map, treemap, "", "", context);
+		buffer.append(select.toString());
+	}
+
+    public String getQuery(XWikiContext context) {
+        String sql = getSql();
+        if ((sql==null)||(sql.trim().equals(""))) {
+            String classname = getClassname();
+            String idField = getIdField();
+            String valueField = getValueField();
+            String parentField = getParentField();
+            if ((valueField==null)||(valueField.trim().equals("")))
+             valueField =  idField;
+            if (context.getWiki().getHibernateStore()!=null) {
+             String select = "select ";
+             String tables = " from XWikiDocument as doc, BaseObject as obj";
+             String where = " where doc.fullName=obj.name and obj.className='" + classname + "'";
+                if (idField.startsWith("doc.")||idField.startsWith("obj."))
+                    select += idField + ",";
+                else {
+                    select += "idprop.value,";
+                    tables += ", StringProperty as idprop";
+                    where += " and obj.id=idprop.id.id and idprop.id.name='" + idField + "'";
+                }
+                if (valueField.startsWith("doc.")||valueField.startsWith("obj."))
+                    select += valueField + ",";
+                else {
+                    if (idField.equals(valueField)) {
+                        select += "idprop.value,";
+                    } else {
+                        select += "valueprop.value,";
+                        tables += ", StringProperty as valueprop";
+                        where += " and obj.id=valueprop.id.id and valueprop.id.name='" + valueField + "'";
+                    }
+                }
+
+                if (parentField.startsWith("doc.")||parentField.startsWith("obj."))
+                    select += parentField + ",";
+                else {
+                    if (idField.equals(parentField)) {
+                        select += "idprop.value,";
+                    } else if (valueField.equals(parentField)) {
+                        select += "valueprop.value,";
+                    } else {
+                        select += "parentprop.value,";
+                        tables += ", StringProperty as parentprop";
+                        where += " and obj.id=parentprop.id.id and parentprop.id.name='" + parentField + "'";
+                    }
+                }
+                // Let's create the sql
+                sql = select +  tables + where;
+            } else {
+                // TODO: query plugin impl.
+                // We need to generate the right query for the query plugin
+            }
+
+        }
+        return sql;
+    }
+}

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -92,6 +92,14 @@
 		setIntValue("relationalStorage", storage ? 1 : 0);
 	}
 
+    public boolean isPicker() {
+        return (getIntValue("picker") == 1);
+    }
+
+    public void setPicker(boolean picker) {
+        setIntValue("picker", picker ? 1 : 0);
+    }
+
     public static List getListFromString(String value) {
         return getListFromString(value, "|", true);
     }
@@ -131,10 +139,10 @@
             String element = StringUtils.replace(result[i], "%PIPE%", "|");
             if (element.indexOf('=')!=-1) {
                 String[] data = StringUtils.split(element,"=");
-                map.put(data[0], data[1]);
+                map.put(data[0], new ListItem(data[0], data[1]));
             }
             else
-              map.put(element, element);
+              map.put(element, new ListItem(element, element));
         }
         return map;
     }
@@ -167,15 +175,19 @@
 
 	public BaseProperty fromStringArray(String[] strings) {
         BaseProperty prop = newProperty();
+        if (prop instanceof StringProperty)
+            return fromString(strings[0]);
+
         List list = new ArrayList();
         ((ListProperty) prop).setList(list);
-		if (strings.length==0)
+
+        if (strings.length==0)
          return prop;
 
         if (!isMultiSelect())
 			return fromString(strings[0]);
 
-        if ((strings.length==1)&&getDisplayType().equals("input")) {
+        if ((strings.length==1)&&(getDisplayType().equals("input")||isMultiSelect())) {
             ((ListProperty) prop).setList(getListFromString(strings[0], getSeparators(), false));
             return prop;
         }
@@ -209,16 +221,19 @@
 	}
 
     protected String getDisplayValue(String value, Map map, XWikiContext context) {
-        String result = (String) map.get(value);
-        if (result==null)
-         result = value;
+        ListItem item = (ListItem) map.get(value);
+        String displayValue;
+        if (item==null)
+         displayValue = value;
+        else
+         displayValue = item.getValue();
         if ((context==null)||(context.getWiki()==null))
-         return result;
+         return displayValue;
         else {
-            String msgname = getFieldFullName() + "_" + result;
+            String msgname = getFieldFullName() + "_" + displayValue;
             String newresult = context.getWiki().getMessage(msgname, context);
             if (msgname.equals(newresult))
-             return result;
+             return displayValue;
             else
              return newresult;
         }

Added: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListItem.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListItem.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/ListItem.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,53 @@
+package com.xpn.xwiki.objects.classes;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ldubost
+ * Date: 19 oct. 2006
+ * Time: 15:23:56
+ * To change this template use File | Settings | File Templates.
+ */
+public class ListItem {
+    private String id = "";
+    private String value = "";
+    private String parent = "";
+
+    public ListItem(String id) {
+        this.setId(id);
+        this.setValue(id);
+    }
+
+    public ListItem(String id, String value) {
+        this(id);
+        this.setValue(value);
+    }
+    public ListItem(String id, String value, String parent) {
+        this(id, value);
+        this.setParent(parent);
+    }
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getParent() {
+        return parent;
+    }
+
+    public void setParent(String parent) {
+        this.parent = parent;
+    }
+}

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -81,7 +81,10 @@
     }
 
     public String getFieldFullName() {
-        return getObject().getName() + "_" + getName();
+        if (getObject()==null)
+         return getName();
+        else
+         return getObject().getName() + "_" + getName();
     }
     
     public int getId() {

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -26,6 +26,7 @@
 import com.xpn.xwiki.objects.BaseCollection;
 import com.xpn.xwiki.objects.classes.DBListClass;
 import com.xpn.xwiki.objects.classes.TextAreaClass;
+import com.xpn.xwiki.objects.classes.StringClass;
 
 public class DBListMetaClass extends ListMetaClass {
 
@@ -40,6 +41,24 @@
         sql_class.setSize(80);
         sql_class.setRows(5);
         safeput("sql", sql_class);
+
+        StringClass classname_class = new StringClass(this);
+        classname_class.setName("classname");
+        classname_class.setPrettyName("XWiki Class Name");
+        classname_class.setSize(20);
+        safeput("classname", classname_class);
+
+        StringClass idfield_class = new StringClass(this);
+        idfield_class.setName("idField");
+        idfield_class.setPrettyName("Id Field Name");
+        idfield_class.setSize(20);
+        safeput("idField", idfield_class);
+
+        StringClass valuefield_class = new StringClass(this);
+        valuefield_class.setName("valueField");
+        valuefield_class.setPrettyName("Value Field Name");
+        valuefield_class.setSize(20);
+        safeput("valueField", valuefield_class);
     }
 
     public BaseCollection newObject(XWikiContext context) {

Added: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBTreeListMetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBTreeListMetaClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/DBTreeListMetaClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,27 @@
+package com.xpn.xwiki.objects.meta;
+
+import com.xpn.xwiki.objects.classes.DBListClass;
+import com.xpn.xwiki.objects.classes.TextAreaClass;
+import com.xpn.xwiki.objects.classes.DBTreeListClass;
+import com.xpn.xwiki.objects.classes.StringClass;
+import com.xpn.xwiki.objects.BaseCollection;
+import com.xpn.xwiki.XWikiContext;
+
+public class DBTreeListMetaClass extends DBListMetaClass {
+
+    public DBTreeListMetaClass() {
+        super();
+        setPrettyName("Database Tree List Class");
+        setName(DBTreeListClass.class.getName());
+
+        StringClass parentfield_class = new StringClass(this);
+        parentfield_class.setName("parentField");
+        parentfield_class.setPrettyName("Parent Field Name");
+        parentfield_class.setSize(20);
+        safeput("parentField", parentfield_class);                
+    }
+
+    public BaseCollection newObject(XWikiContext context) {
+        return new DBTreeListClass();
+    }
+}

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -28,36 +28,43 @@
 
 public class ListMetaClass extends PropertyMetaClass {
 
-  public ListMetaClass() {
-    super();
-    setPrettyName("List Class");
-    setName(ListClass.class.getName());
+    public ListMetaClass() {
+        super();
+        setPrettyName("List Class");
+        setName(ListClass.class.getName());
 
-    StaticListClass type_class = new StaticListClass(this);
-    type_class.setName("displayType");
-    type_class.setPrettyName("Display Type");
-    type_class.setValues("input|select|radio|checkbox");
-    safeput("displayType", type_class);
+        StaticListClass type_class = new StaticListClass(this);
+        type_class.setName("displayType");
+        type_class.setPrettyName("Display Type");
+        type_class.setValues("input|select|radio|checkbox");
+        safeput("displayType", type_class);
 
-    BooleanClass multi_class = new BooleanClass(this);
-    multi_class.setName("multiSelect");
-    multi_class.setPrettyName("Multiple Select");
-    multi_class.setDisplayType("yesno");
-    multi_class.setUnmodifiable(true);
-    safeput("multiSelect", multi_class);
+        BooleanClass multi_class = new BooleanClass(this);
+        multi_class.setName("multiSelect");
+        multi_class.setPrettyName("Multiple Select");
+        multi_class.setDisplayType("yesno");
+        multi_class.setUnmodifiable(true);
+        safeput("multiSelect", multi_class);
 
-    BooleanClass relational_class = new BooleanClass(this);
-    relational_class.setName("relationalStorage");
-    relational_class.setPrettyName("Relational Storage");
-    relational_class.setDisplayType("yesno");
-    relational_class.setUnmodifiable(true);
-    safeput("relationalStorage", relational_class);
+        BooleanClass relational_class = new BooleanClass(this);
+        relational_class.setName("relationalStorage");
+        relational_class.setPrettyName("Relational Storage");
+        relational_class.setDisplayType("yesno");
+        relational_class.setUnmodifiable(true);
+        safeput("relationalStorage", relational_class);
 
-    NumberClass size_class = new NumberClass(this);
-    size_class.setName("size");
-    size_class.setPrettyName("Size");
-    size_class.setSize(5);
-    size_class.setNumberType("integer");
-    safeput("size", size_class);
-  }
+        BooleanClass picker_class = new BooleanClass(this);
+        picker_class.setName("picker");
+        picker_class.setPrettyName("Use Picker");
+        picker_class.setDisplayType("yesno");
+        picker_class.setUnmodifiable(true);
+        safeput("picker", picker_class);
+
+        NumberClass size_class = new NumberClass(this);
+        size_class.setName("size");
+        size_class.setPrettyName("Size");
+        size_class.setSize(5);
+        size_class.setNumberType("integer");
+        safeput("size", size_class);
+    }
 }

Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/MetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/MetaClass.java	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/MetaClass.java	2006-10-20 04:34:05 UTC (rev 1416)
@@ -48,6 +48,8 @@
         safeput(listclass.getName(), listclass);
         DBListMetaClass dblistclass = new DBListMetaClass();
         safeput(dblistclass.getName(), dblistclass);
+        DBTreeListMetaClass dbtreelistclass = new DBTreeListMetaClass();
+        safeput(dbtreelistclass.getName(), dbtreelistclass);
         DateMetaClass dateclass = new DateMetaClass();
         safeput(dateclass.getName(), dateclass);
         GroupsMetaClass groupsclass = new GroupsMetaClass();

Modified: xwiki/trunk/src/main/web/skins/xwiki10/layoutvars.vm
===================================================================
--- xwiki/trunk/src/main/web/skins/xwiki10/layoutvars.vm	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/skins/xwiki10/layoutvars.vm	2006-10-20 04:34:05 UTC (rev 1416)
@@ -26,7 +26,7 @@
 #set($blogwidth = 200)
 ##
 ##
-#set($showLeftPanels = $xwiki.getXWikiPreference("showLeftPanels"))
+#set($showLeftPanels = $xwiki.getWebPreference("showLeftPanels"))
 #if(!$showLeftPanels || $showLeftPanels == "" || $showLeftPanels == "default")
 #set($showLeftPanels = "1")
 #end
@@ -36,7 +36,7 @@
 #if($showLeftPanels == "no")
 #set($showLeftPanels = "0")
 #end
-#set($showRightPanels = $xwiki.getXWikiPreference("showRightPanels"))
+#set($showRightPanels = $xwiki.getWebPreference("showRightPanels"))
 #if(!$showRightPanels || $showRightPanels == "" || $showRightPanels == "default")
 #set($showRightPanels = "1")
 #end

Added: xwiki/trunk/src/main/web/templates/treeview.vm
===================================================================
--- xwiki/trunk/src/main/web/templates/treeview.vm	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/templates/treeview.vm	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,72 @@
+#if(!$treeviewid)
+#set($treeviewid = 1)
+#else
+#set($treeviewid = 1 + $treeviewid)
+#end
+#if(!$formname)
+#set($formname = "inline")
+#end
+<style type="text/css">
+ at import "/xwiki/yui/treeview/assets/tree.css";
+</style>
+<script type="text/javascript" src="/xwiki/yui/yahoo/yahoo-min.js" ></script>
+<script type="text/javascript" src="/xwiki/yui/treeview/treeview-min.js" ></script>
+<script type="text/javascript" src="/xwiki/yui/treeview/checknode.js"></script>
+<div id="treeview${treeviewid}"></div>
+<script type="text/javascript">
+	var tree${treeviewid};
+	var nodes${treeviewid} = {};
+	var nodeIndex${treeviewid};
+
+    function addTreeElement(tree, nodes, id, text, parent, checked) {
+	    var parent2;
+	    if (parent=="")
+	     parent2 = tree.getRoot();
+	    else
+	     parent2 = nodes[parent];
+	    nodes[id] = new YAHOO.widget.CheckNode(id, text,  parent2, checked, checked);
+        nodes[id].onCheckClick = onCheckClick;
+    }
+
+	var callback = null;
+    function onCheckClick(eventType, args, tree) {
+        var out = [];
+        for (var i in tree${treeviewid}._nodes) {
+            var n = tree${treeviewid}._nodes[i];
+            if (n && "undefined" != typeof n.checkState) {
+                if (n.checkState>0) {
+                  out.push(n.data);
+                }
+            }
+        }
+        document.forms.${formname}["${fieldname}"].value=out.join("|");
+    }
+
+    function showTreeState() {
+        var out = [];
+        for (var i in tree${treeviewid}._nodes) {
+            var n = tree${treeviewid}._nodes[i];
+            if (n && "undefined" != typeof n.checkState) {
+                if (n.checkState>0) {
+                  out.push(n.data);
+                }
+            }
+        }
+        alert(out.join("|"));
+    }
+
+	function treeInit${treeviewid}() {
+		tree${treeviewid} = new YAHOO.widget.TreeView("treeview${treeviewid}");
+	    var tree = tree${treeviewid};
+        var nodes = nodes${treeviewid};
+        #foreach($item in $treelist)
+        #set($checked = $selectlist.contains($item.getId()))
+        addTreeElement(tree, nodes, "$item.id", "$item.value", "$item.parent", #if($checked) true #else false #end)
+        #end
+   		tree.draw();
+        // tree.checkClickEvent.subscribe(onCheckClick);
+	}
+
+    // Init the tree
+    treeInit${treeviewid}();
+</script>

Modified: xwiki/trunk/src/main/web/templates/viewheader.vm
===================================================================
--- xwiki/trunk/src/main/web/templates/viewheader.vm	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/templates/viewheader.vm	2006-10-20 04:34:05 UTC (rev 1416)
@@ -117,7 +117,7 @@
             #end
           #end
           #if (!$isReadOnly)
-            #xwikiitem($doc.getURL("edit") "editinline")
+            #xwikiitem($doc.getURL("inline") "editinline")
             #xwikiitem($doc.getURL("edit", "xpage=editobject") "editobject")
           #end
           #if(($hasadmin||($context.user.equals($doc.creator))) && !$isReadOnly)

Added: xwiki/trunk/src/main/web/yui/calendar/README
===================================================================
--- xwiki/trunk/src/main/web/yui/calendar/README	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/yui/calendar/README	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,30 @@
+Calendar Release Notes
+
+*** version 0.11.3 ***
+
+	- Calendar_Core: Added arguments for selected/deselected dates to onSelect/onDeselect
+	- CalendarGroup: Fixed bug where selected dates passed to constructor were not represented in selectedDates
+	- Calendar2up: Now displays correctly in Opera 9
+
+*** version 0.11.0 ***
+
+	- DateMath: DateMath.add now properly adds weeks
+	- DateMath: between() function added
+	- DateMath: getWeekNumber() fixed to take starting day of week into account
+	- All references to Calendar's built in CSS class handlers are removed, replaced with calls to Dom utility (addClass, removeClass)
+	- Several CSS class constants now have clearer names
+	- All CSS classes are now properly namespaced to avoid CSS conflicts
+	- Fixed table:hover bug in CSS
+	- Calendar no longer requires the container ID and variable name to match in order for month navigation to function properly
+	- Calendar month navigation arrows are now represented as background images
+
+*** version 0.10.0 ***
+
+	- Major performance improvements from attaching DOM events to associated table cells only once, when the Calendar shell is built
+	- DOM events for mouseover/mouseout are now fired for all browsers (not just Internet Explorer)
+	- Reset functionality bug fixed for 2-up Calendar view
+
+*** version 0.9.0 ***
+
+* Initial release
+

Added: xwiki/trunk/src/main/web/yui/calendar/assets/calendar.css
===================================================================
--- xwiki/trunk/src/main/web/yui/calendar/assets/calendar.css	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/yui/calendar/assets/calendar.css	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,161 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version 0.11.3
+*/
+
+.yui-cal2upwrapper {*height:1%;} /* IE */
+.yui-cal2upwrapper:after {content:'.';clear:both;display:block;visibility:hidden;height:0;} /* others */
+
+.yui-calcontainer {
+	float:left;
+	padding:5px;
+	background-color:#F7F9FB;
+	border:1px solid #7B9EBD;
+}
+
+.yui-calcontainer .title {
+	font:100% sans-serif;
+	color:#000;
+	font-weight:bold;
+	margin-bottom:5px;
+	height:auto;
+	position:relative;
+}
+
+.yui-calcontainer .title .close-icon {
+	position:absolute;
+	right:0;
+	top:0;
+	border:none;
+}
+
+.yui-calcontainer .cal2up {
+	float:left;
+}
+
+.yui-calendar .calnavleft {
+	position:absolute;
+	background-repeat:no-repeat;
+	cursor:pointer;
+	top:2px;
+	bottom:0;
+	width:9px;
+	height:12px;   
+	left:2px;
+}
+
+.yui-calendar .calnavright {
+	position:absolute;
+	background-repeat:no-repeat;
+	cursor:pointer;
+	top:2px;
+	bottom:0;
+	width:9px;
+	height:12px;  
+	right:2px;
+}
+
+/* Calendar element styles */
+
+.yui-calendar {
+	font:100% sans-serif;
+	text-align:center;
+	border-spacing:0;
+	border-collapse:separate;
+}
+
+.yui-calendar td.calcell {
+	padding:.1em .2em;
+	border:1px solid #E0E0E0;
+	background-color:#FFF;
+}
+
+.yui-calendar td.calcell a {
+	color:#003DB8;
+	text-decoration:none;
+}
+
+.yui-calendar td.calcell.today {
+	border:1px solid #000;
+}
+
+.yui-calendar td.calcell.oom {
+	cursor:default;
+	color:#999;
+	background-color:#EEE;
+	border:1px solid #E0E0E0;
+}
+
+.yui-calendar td.calcell.selected {
+	color:#003DB8;
+	background-color:#FFF19F;
+	border:1px solid #FF9900;
+}
+
+.yui-calendar td.calcell.calcellhover {
+	cursor:pointer;
+	color:#FFF;
+	background-color:#FF9900;
+	border:1px solid #FF9900;
+}
+
+.yui-calendar td.calcell.calcellhover a {
+	color:#FFF;
+}
+
+.yui-calendar td.calcell.restricted {
+	text-decoration:line-through;
+}
+
+.yui-calendar td.calcell.previous {
+	color:#CCC;
+}
+
+.yui-calendar td.calcell.highlight1 { background-color:#CCFF99; }
+.yui-calendar td.calcell.highlight2 { background-color:#99CCFF; }
+.yui-calendar td.calcell.highlight3 { background-color:#FFCCCC; }
+.yui-calendar td.calcell.highlight4 { background-color:#CCFF99; }
+
+
+.yui-calendar .calhead {
+	border:1px solid #E0E0E0;
+	vertical-align:middle;
+	background-color:#FFF;
+}
+
+.yui-calendar .calheader {
+	position:relative;
+	width:100%;
+	text-align:center;
+}
+
+.yui-calendar .calheader img {
+	border:none;
+}
+
+.yui-calendar .calweekdaycell {
+	color:#666;
+	font-weight:normal;
+}
+
+.yui-calendar .calfoot {
+	background-color:#EEE;
+}
+
+.yui-calendar .calrowhead, .yui-calendar .calrowfoot {
+	color:#666;
+	font-size:9px;
+	font-style:italic;
+	font-weight:normal;
+	width:15px;
+}
+
+.yui-calendar .calrowhead {
+	border-right-width:2px;
+}
+
+/*Specific changes for calendar running under fonts/reset */
+.yui-calendar a:hover {background:inherit;}
+p#clear {clear:left; padding-top:10px;}

Added: xwiki/trunk/src/main/web/yui/calendar/assets/callt.gif
===================================================================
(Binary files differ)


Property changes on: xwiki/trunk/src/main/web/yui/calendar/assets/callt.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: xwiki/trunk/src/main/web/yui/calendar/assets/calrt.gif
===================================================================
(Binary files differ)


Property changes on: xwiki/trunk/src/main/web/yui/calendar/assets/calrt.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: xwiki/trunk/src/main/web/yui/calendar/assets/calx.gif
===================================================================
(Binary files differ)


Property changes on: xwiki/trunk/src/main/web/yui/calendar/assets/calx.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: xwiki/trunk/src/main/web/yui/calendar/calendar-debug.js
===================================================================
--- xwiki/trunk/src/main/web/yui/calendar/calendar-debug.js	2006-10-20 01:38:43 UTC (rev 1415)
+++ xwiki/trunk/src/main/web/yui/calendar/calendar-debug.js	2006-10-20 04:34:05 UTC (rev 1416)
@@ -0,0 +1,2902 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+Version 0.11.3
+*/
+
+/**
+* <p>YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
+* used for adding, subtracting, and comparing dates.</p>
+*/
+YAHOO.widget.DateMath = new function() {
+
+	/**
+	* Constant field representing Day
+	* @type String
+	*/
+	this.DAY = "D";
+
+	/**
+	* Constant field representing Week
+	* @type String
+	*/
+	this.WEEK = "W";
+
+	/**
+	* Constant field representing Year
+	* @type String
+	*/
+	this.YEAR = "Y";
+
+	/**
+	* Constant field representing Month
+	* @type String
+	*/
+	this.MONTH = "M";
+
+	/**
+	* Constant field representing one day, in milliseconds
+	* @type Integer
+	*/
+	this.ONE_DAY_MS = 1000*60*60*24;
+
+	/**
+	* Adds the specified amount of time to the this instance.
+	* @param {Date} date	The JavaScript Date object to perform addition on
+	* @param {string} field	The this field constant to be used for performing addition.
+	* @param {Integer} amount	The number of units (measured in the field constant) to add to the date.
+	*/
+	this.add = function(date, field, amount) {
+		var d = new Date(date.getTime());
+		switch (field) {
+			case this.MONTH:
+				var newMonth = date.getMonth() + amount;
+				var years = 0;
+
+
+				if (newMonth < 0) {
+					while (newMonth < 0) {
+						newMonth += 12;
+						years -= 1;
+					}
+				} else if (newMonth > 11) {
+					while (newMonth > 11) {
+						newMonth -= 12;
+						years += 1;
+					}
+				}
+				
+				d.setMonth(newMonth);
+				d.setFullYear(date.getFullYear() + years);
+				break;
+			case this.DAY:
+				d.setDate(date.getDate() + amount);
+				break;
+			case this.YEAR:
+				d.setFullYear(date.getFullYear() + amount);
+				break;
+			case this.WEEK:
+				d.setDate(date.getDate() + (amount * 7));
+				break;
+		}
+		return d;
+	};
+
+	/**
+	* Subtracts the specified amount of time from the this instance.
+	* @param {Date} date	The JavaScript Date object to perform subtraction on
+	* @param {Integer} field	The this field constant to be used for performing subtraction.
+	* @param {Integer} amount	The number of units (measured in the field constant) to subtract from the date.
+	*/
+	this.subtract = function(date, field, amount) {
+		return this.add(date, field, (amount*-1));
+	};
+
+	/**
+	* Determines whether a given date is before another date on the calendar.
+	* @param {Date} date		The Date object to compare with the compare argument
+	* @param {Date} compareTo	The Date object to use for the comparison
+	* @return {Boolean} true if the date occurs before the compared date; false if not.
+	*/
+	this.before = function(date, compareTo) {
+		var ms = compareTo.getTime();
+		if (date.getTime() < ms) {
+			return true;
+		} else {
+			return false;
+		}
+	};
+
+	/**
+	* Determines whether a given date is after another date on the calendar.
+	* @param {Date} date		The Date object to compare with the compare argument
+	* @param {Date} compareTo	The Date object to use for the comparison
+	* @return {Boolean} true if the date occurs after the compared date; false if not.
+	*/
+	this.after = function(date, compareTo) {
+		var ms = compareTo.getTime();
+		if (date.getTime() > ms) {
+			return true;
+		} else {
+			return false;
+		}
+	};
+
+	/**
+	* Determines whether a given date is between two other dates on the calendar.
+	* @param {Date} date		The date to check for
+	* @param {Date} dateBegin	The start of the range
+	* @param {Date} dateEnd		The end of the range
+	* @return {Boolean} true if the date occurs between the compared dates; false if not.
+	*/
+	this.between = function(date, dateBegin, dateEnd) {
+		if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
+			return true;
+		} else {
+			return false;
+		}
+	};
+	
+	/**
+	* Retrieves a JavaScript Date object representing January 1 of any given year.
+	* @param {Integer} calendarYear		The calendar year for which to retrieve January 1
+	* @return {Date}	January 1 of the calendar year specified.
+	*/
+	this.getJan1 = function(calendarYear) {
+		return new Date(calendarYear,0,1); 
+	};
+
+	/**
+	* Calculates the number of days the specified date is from January 1 of the specified calendar year.
+	* Passing January 1 to this function would return an offset value of zero.
+	* @param {Date}	date	The JavaScript date for which to find the offset
+	* @param {Integer} calendarYear	The calendar year to use for determining the offset
+	* @return {Integer}	The number of days since January 1 of the given year
+	*/
+	this.getDayOffset = function(date, calendarYear) {
+		var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
+		
+		// Find the number of days the passed in date is away from the calendar year start
+		var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
+		return dayOffset;
+	};
+
+	/**
+	* Calculates the week number for the given date. This function assumes that week 1 is the
+	* week in which January 1 appears, regardless of whether the week consists of a full 7 days.
+	* The calendar year can be specified to help find what a the week number would be for a given
+	* date if the date overlaps years. For instance, a week may be considered week 1 of 2005, or
+	* week 53 of 2004. Specifying the optional calendarYear allows one to make this distinction
+	* easily.
+	* @param {Date}	date	The JavaScript date for which to find the week number
+	* @param {Integer} calendarYear	OPTIONAL - The calendar year to use for determining the week number. Default is
+	*											the calendar year of parameter "date".
+	* @param {Integer} weekStartsOn	OPTIONAL - The integer (0-6) representing which day a week begins on. Default is 0 (for Sunday).
+	* @return {Integer}	The week number of the given date.
+	*/
+	this.getWeekNumber = function(date, calendarYear, weekStartsOn) {
+		date.setHours(12,0,0,0);
+
+		if (! weekStartsOn) {
+			weekStartsOn = 0;
+		}
+		if (! calendarYear) {
+			calendarYear = date.getFullYear();
+		}
+		
+		var weekNum = -1;
+		
+		var jan1 = this.getJan1(calendarYear);
+
+		var jan1Offset = jan1.getDay() - weekStartsOn;
+		var jan1DayOfWeek = (jan1Offset >= 0 ? jan1Offset : (7 + jan1Offset));
+
+		var endOfWeek1 = this.add(jan1, this.DAY, (6 - jan1DayOfWeek));
+		endOfWeek1.setHours(23,59,59,999);
+
+		var month = date.getMonth();
+		var day = date.getDate();
+		var year = date.getFullYear();
+		
+		var dayOffset = this.getDayOffset(date, calendarYear); // Days since Jan 1, Calendar Year
+			
+		if (dayOffset < 0 || this.before(date, endOfWeek1)) {
+			weekNum = 1;
+		} else {
+			weekNum = 2;
+			var weekBegin = new Date(endOfWeek1.getTime() + 1);
+			var weekEnd = this.add(weekBegin, this.WEEK, 1);
+
+			while (! this.between(date, weekBegin, weekEnd)) {
+				weekBegin = this.add(weekBegin, this.WEEK, 1);
+				weekEnd = this.add(weekEnd, this.WEEK, 1);
+				weekNum += 1;
+			}
+		}
+		
+		return weekNum;
+	};
+
+	/**
+	* Determines if a given week overlaps two different years.
+	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
+	* @return {Boolean}	true if the date overlaps two different years.
+	*/
+	this.isYearOverlapWeek = function(weekBeginDate) {
+		var overlaps = false;
+		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
+		if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
+			overlaps = true;
+		}
+		return overlaps;
+	};
+
+	/**
+	* Determines if a given week overlaps two different months.
+	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
+	* @return {Boolean}	true if the date overlaps two different months.
+	*/
+	this.isMonthOverlapWeek = function(weekBeginDate) {
+		var overlaps = false;
+		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
+		if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
+			overlaps = true;
+		}
+		return overlaps;
+	};
+
+	/**
+	* Gets the first day of a month containing a given date.
+	* @param {Date}	date	The JavaScript Date used to calculate the month start
+	* @return {Date}		The JavaScript Date representing the first day of the month
+	*/
+	this.findMonthStart = function(date) {
+		var start = new Date(date.getFullYear(), date.getMonth(), 1);
+		return start;
+	};
+
+	/**
+	* Gets the last day of a month containing a given date.
+	* @param {Date}	date	The JavaScript Date used to calculate the month end
+	* @return {Date}		The JavaScript Date representing the last day of the month
+	*/
+	this.findMonthEnd = function(date) {
+		var start = this.findMonthStart(date);
+		var nextMonth = this.add(start, this.MONTH, 1);
+		var end = this.subtract(nextMonth, this.DAY, 1);
+		return end;
+	};
+
+	/**
+	* Clears the time fields from a given date, effectively setting the time to midnight.
+	* @param {Date}	date	The JavaScript Date for which the time fields will be cleared
+	* @return {Date}		The JavaScript Date cleared of all time fields
+	*/
+	this.clearTime = function(date) {
+		date.setHours(0,0,0,0);
+		return date;
+	};
+}
+/**
+* <p>Calendar_Core is the base class for the Calendar widget. In its most basic
+* implementation, it has the ability to render a calendar widget on the page
+* that can be manipulated to select a single date, move back and forth between
+* months and years.</p>
+* <p>To construct the placeholder for the calendar widget, the code is as
+* follows:
+*	<xmp>
+*		<div id="cal1Container"></div>
+*	</xmp>
+* Note that the table can be replaced with any kind of element.
+* </p>
+* @constructor
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+YAHOO.widget.Calendar_Core = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0) {	
+		if (! id) {
+			YAHOO.log("No ID specified", "error");
+		}
+		if (! containerId) {
+			YAHOO.log("No container ID specified", "error");
+		}
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+/**
+* The path to be used for images loaded for the Calendar
+* @type String
+*/
+YAHOO.widget.Calendar_Core.IMG_ROOT = (window.location.href.toLowerCase().indexOf("https") == 0 ? "https://a248.e.akamai.net/sec.yimg.com/i/" : "http://us.i1.yimg.com/us.yimg.com/i/");
+
+/**
+* Type constant used for renderers to represent an individual date (M/D/Y)
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.DATE = "D";
+
+/**
+* Type constant used for renderers to represent an individual date across any year (M/D)
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.MONTH_DAY = "MD";
+
+/**
+* Type constant used for renderers to represent a weekday
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.WEEKDAY = "WD";
+
+/**
+* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.RANGE = "R";
+
+/**
+* Type constant used for renderers to represent a month across any year
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.MONTH = "M";
+
+/**
+* Constant that represents the total number of date cells that are displayed in a given month
+* including 
+* @final
+* @type Integer
+*/
+YAHOO.widget.Calendar_Core.DISPLAY_DAYS = 42;
+
+/**
+* Constant used for halting the execution of the remainder of the render stack
+* @final
+* @type String
+*/
+YAHOO.widget.Calendar_Core.STOP_RENDER = "S";
+
+YAHOO.widget.Calendar_Core.prototype = {
+
+	/**
+	* The configuration object used to set up the calendars various locale and style options.
+	* @type Object
+	*/
+	Config : null,
+
+	/**
+	* The parent CalendarGroup, only to be set explicitly by the parent group
+	* @type CalendarGroup
+	*/	
+	parent : null,
+
+	/**
+	* The index of this item in the parent group
+	* @type Integer
+	*/
+	index : -1,
+
+	/**
+	* The collection of calendar table cells
+	* @type HTMLTableCellElement[]
+	*/
+	cells : null,
+
+	/**
+	* The collection of calendar week header cells
+	* @type HTMLTableCellElement[]
+	*/
+	weekHeaderCells : null,
+
+	/**
+	* The collection of calendar week footer cells
+	* @type HTMLTableCellElement[]
+	*/
+	weekFooterCells : null,
+	
+	/**
+	* The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
+	* @type Array[](Integer[])
+	*/
+	cellDates : null,
+
+	/**
+	* The id that uniquely identifies this calendar. This id should match the id of the placeholder element on the page.
+	* @type String
+	*/
+	id : null,
+
+	/**
+	* The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
+	* @type HTMLElement
+	*/
+	oDomContainer : null,
+
+	/**
+	* A Date object representing today's date.
+	* @type Date
+	*/
+	today : null,
+
+	/**
+	* The list of render functions, along with required parameters, used to render cells. 
+	* @type Array[]
+	*/
+	renderStack : null,
+
+	/**
+	* A copy of the initial render functions created before rendering.
+	* @type Array
+	* @private
+	*/
+	_renderStack : null,
+
+	/**
+	* A Date object representing the month/year that the calendar is currently set to
+	* @type Date
+	*/
+	pageDate : null,
+
+	/**
+	* A Date object representing the month/year that the calendar is initially set to
+	* @type Date
+	* @private
+	*/
+	_pageDate : null,
+	
+	/**
+	* A Date object representing the minimum selectable date
+	* @type Date
+	*/
+	minDate : null,
+	
+	/**
+	* A Date object representing the maximum selectable date
+	* @type Date
+	*/
+	maxDate : null,
+	
+	/**
+	* The list of currently selected dates. The data format for this local collection is 
+	* an array of date field arrays, e.g:
+	* [
+	*	[2004,5,25],
+	*	[2004,5,26]
+	* ]
+	* @type Array[](Integer[])
+	*/
+	selectedDates : null,
+
+	/**
+	* The private list of initially selected dates.
+	* @type Array
+	* @private
+	*/
+	_selectedDates : null,
+
+	/**
+	* A boolean indicating whether the shell of the calendar has already been rendered to the page
+	* @type Boolean
+	*/	
+	shellRendered : false,
+
+	/**
+	* The HTML table element that represents this calendar
+	* @type HTMLTableElement
+	*/	
+	table : null,
+
+	/**
+	* The HTML cell element that represents the main header cell TH used in the calendar table
+	* @type HTMLTableCellElement
+	*/	
+	headerCell : null
+};
+
+
+
+/**
+* Initializes the calendar widget. This method must be called by all subclass constructors.
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+YAHOO.widget.Calendar_Core.prototype.init = function(id, containerId, monthyear, selected) {
+
+	this.logger = new YAHOO.widget.LogWriter("Calendar_Core " + id);	
+
+	this.setupConfig();
+
+	this.id = id;
+
+	this.cellDates = new Array();
+	
+	this.cells = new Array();
+	
+	this.renderStack = new Array();
+	this._renderStack = new Array();
+
+	this.oDomContainer = document.getElementById(containerId);
+	
+	if (! this.oDomContainer) {
+		this.logger.log("No valid container present.", "error");
+	}
+
+	this.today = new Date();
+	YAHOO.widget.DateMath.clearTime(this.today);
+
+	var month;
+	var year;
+
+	if (monthyear) {
+		var aMonthYear = monthyear.split(this.Locale.DATE_FIELD_DELIMITER);
+		month = parseInt(aMonthYear[this.Locale.MY_MONTH_POSITION-1]);
+		year = parseInt(aMonthYear[this.Locale.MY_YEAR_POSITION-1]);
+	} else {
+		month = this.today.getMonth()+1;
+		year = this.today.getFullYear();
+	}
+
+	this.logger.log("Initialized with month/year of " + month + "/" + year, "info");
+
+	this.pageDate = new Date(year, month-1, 1);
+	this._pageDate = new Date(this.pageDate.getTime());
+
+	if (selected) {
+		this.selectedDates = this._parseDates(selected);
+		this._selectedDates = this.selectedDates.concat();
+	} else {
+		this.selectedDates = new Array();
+		this._selectedDates = new Array();
+	}
+
+	this.wireDefaultEvents();
+	this.wireCustomEvents();
+};
+
+
+/**
+* Wires the local DOM events for the Calendar, including cell selection, hover, and
+* default navigation that is used for moving back and forth between calendar pages.
+*/
+YAHOO.widget.Calendar_Core.prototype.wireDefaultEvents = function() {
+	
+	/**
+	* The default event function that is attached to a date link within a calendar cell
+	* when the calendar is rendered. 
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	*/
+	this.doSelectCell = function(e, cal) {		
+		var cell = this;
+		var index = cell.index;
+
+		cal.logger.log("Selecting cell " + index + " via click", "info");
+
+		var d = cal.cellDates[index];
+		var date = new Date(d[0],d[1]-1,d[2]);
+		
+		if (! cal.isDateOOM(date) && ! YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_RESTRICTED) && ! YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_OOB)) {
+			if (cal.Options.MULTI_SELECT) {
+				var link = cell.getElementsByTagName("A")[0];
+				link.blur();
+				
+				var cellDate = cal.cellDates[index];
+				var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
+				
+				if (cellDateIndex > -1) {	
+					cal.deselectCell(index);
+				} else {
+					cal.selectCell(index);
+				}	
+				
+			} else {
+				var link = cell.getElementsByTagName("A")[0];
+				link.blur()
+				cal.selectCell(index);
+			}
+		}
+	}
+
+	/**
+	* The event that is executed when the user hovers over a cell
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doCellMouseOver = function(e, cal) {
+		var cell = this;
+		var index = cell.index;
+		var d = cal.cellDates[index];
+		var date = new Date(d[0],d[1]-1,d[2]);
+
+		if (! cal.isDateOOM(date) && ! YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_RESTRICTED) && ! YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_OOB)) {
+			YAHOO.util.Dom.addClass(cell, cal.Style.CSS_CELL_HOVER);
+		}
+	}
+
+	/**
+	* The event that is executed when the user moves the mouse out of a cell
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doCellMouseOut = function(e, cal) {
+		YAHOO.util.Dom.removeClass(this, cal.Style.CSS_CELL_HOVER);
+	}
+	
+	/**
+	* A wrapper event that executes the nextMonth method through a DOM event
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/	
+	this.doNextMonth = function(e, cal) {
+		cal.nextMonth();
+	}
+
+	/**
+	* A wrapper event that executes the previousMonth method through a DOM event
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/		
+	this.doPreviousMonth = function(e, cal) {
+		cal.previousMonth();
+	}
+}
+
+/**
+* This function can be extended by subclasses to attach additional DOM events to
+* the calendar. By default, this method is unimplemented.
+*/
+YAHOO.widget.Calendar_Core.prototype.wireCustomEvents = function() { }
+
+/**
+This method is called to initialize the widget configuration variables, including
+style, localization, and other display and behavioral options.
+<p>Config: Container for the CSS style configuration variables.</p>
+<p><strong>Config.Style</strong> - Defines the CSS classes used for different calendar elements</p>
+<blockquote>
+	<div><em>CSS_CALENDAR</em> : Container table</div>
+	<div><em>CSS_HEADER</em> : </div>
+	<div><em>CSS_HEADER_TEXT</em> : Calendar header</div>
+	<div><em>CSS_FOOTER</em> : Calendar footer</div>
+	<div><em>CSS_CELL</em> : Calendar day cell</div>
+	<div><em>CSS_CELL_OOM</em> : Calendar OOM (out of month) cell</div>
+	<div><em>CSS_CELL_SELECTED</em> : Calendar selected cell</div>
+	<div><em>CSS_CELL_RESTRICTED</em> : Calendar restricted cell</div>
+	<div><em>CSS_CELL_TODAY</em> : Calendar cell for today's date</div>
+	<div><em>CSS_ROW_HEADER</em> : The cell preceding a row (used for week number by default)</div>
+	<div><em>CSS_ROW_FOOTER</em> : The cell following a row (not implemented by default)</div>
+	<div><em>CSS_WEEKDAY_CELL</em> : The cells used for labeling weekdays</div>
+	<div><em>CSS_WEEKDAY_ROW</em> : The row containing the weekday label cells</div>
+	<div><em>CSS_CONTAINER</em> : The border style used for the default UED rendering</div>
+	<div><em>CSS_2UPWRAPPER</em> : Special container class used to properly adjust the sizing and float</div>
+	<div><em>CSS_NAV_LEFT</em> : Left navigation arrow</div>
+	<div><em>CSS_NAV_RIGHT</em> : Right navigation arrow</div>
+	<div><em>CSS_CELL_TOP</em> : Outlying cell along the top row</div>
+	<div><em>CSS_CELL_LEFT</em> : Outlying cell along the left row</div>
+	<div><em>CSS_CELL_RIGHT</em> : Outlying cell along the right row</div>
+	<div><em>CSS_CELL_BOTTOM</em> : Outlying cell along the bottom row</div>
+	<div><em>CSS_CELL_HOVER</em> : Cell hover style</div>
+	<div><em>CSS_CELL_HIGHLIGHT1</em> : Highlight color 1 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT2</em> : Highlight color 2 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT3</em> : Highlight color 3 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT4</em> : Highlight color 4 for styling cells</div>
+
+</blockquote>
+<p><strong>Config.Locale</strong> - Defines the locale string arrays used for localization</p>
+<blockquote>
+	<div><em>MONTHS_SHORT</em> : Array of 12 months in short format ("Jan", "Feb", etc.)</div>
+	<div><em>MONTHS_LONG</em> : Array of 12 months in short format ("Jan", "Feb", etc.)</div>
+	<div><em>WEEKDAYS_1CHAR</em> : Array of 7 days in 1-character format ("S", "M", etc.)</div>
+	<div><em>WEEKDAYS_SHORT</em> : Array of 7 days in short format ("Su", "Mo", etc.)</div>
+	<div><em>WEEKDAYS_MEDIUM</em> : Array of 7 days in medium format ("Sun", "Mon", etc.)</div>
+	<div><em>WEEKDAYS_LONG</em> : Array of 7 days in long format ("Sunday", "Monday", etc.)</div>
+	<div><em>DATE_DELIMITER</em> : The value used to delimit series of multiple dates (Default: ",")</div>
+	<div><em>DATE_FIELD_DELIMITER</em> : The value used to delimit date fields (Default: "/")</div>
+	<div><em>DATE_RANGE_DELIMITER</em> : The value used to delimit date fields (Default: "-")</div>
+	<div><em>MY_MONTH_POSITION</em> : The value used to determine the position of the month in a month/year combo (e.g. 12/2005) (Default: 1)</div>
+	<div><em>MY_YEAR_POSITION</em> : The value used to determine the position of the year in a month/year combo (e.g. 12/2005) (Default: 2)</div>	
+	<div><em>MD_MONTH_POSITION</em> : The value used to determine the position of the month in a month/day combo (e.g. 12/25) (Default: 1)</div>
+	<div><em>MD_DAY_POSITION</em> : The value used to determine the position of the day in a month/day combo (e.g. 12/25) (Default: 2)</div>
+	<div><em>MDY_MONTH_POSITION</em> : The value used to determine the position of the month in a month/day/year combo (e.g. 12/25/2005) (Default: 1)</div>
+	<div><em>MDY_DAY_POSITION</em> : The value used to determine the position of the day in a month/day/year combo (e.g. 12/25/2005) (Default: 2)</div>
+	<div><em>MDY_YEAR_POSITION</em> : The value used to determine the position of the year in a month/day/year combo (e.g. 12/25/2005) (Default: 3)</div>
+</blockquote>
+<p><strong>Config.Options</strong> - Defines other configurable calendar widget options</p>
+<blockquote>
+	<div><em>SHOW_WEEKDAYS</em> : Boolean, determines whether to display the weekday headers (defaults to true)</div>
+	<div><em>LOCALE_MONTHS</em> : Array, points to the desired Config.Locale array (defaults to Config.Locale.MONTHS_LONG)</div>
+	<div><em>LOCALE_WEEKDAYS</em> : Array, points to the desired Config.Locale array (defaults to Config.Locale.WEEKDAYS_SHORT)</div>
+	<div><em>START_WEEKDAY</em> : Integer, 0-6, representing the day that a week begins on</div>
+	<div><em>SHOW_WEEK_HEADER</em> : Boolean, determines whether to display row headers</div>
+	<div><em>SHOW_WEEK_FOOTER</em> : Boolean, determines whether to display row footers</div>
+	<div><em>HIDE_BLANK_WEEKS</em> : Boolean, determines whether to hide extra weeks that are completely OOM</div>
+	<div><em>NAV_ARROW_LEFT</em> : String, the image path used for the left navigation arrow</div>
+	<div><em>NAV_ARROW_RIGHT</em> : String, the image path used for the right navigation arrow</div>
+</blockquote>
+*/
+YAHOO.widget.Calendar_Core.prototype.setupConfig = function() {
+	/**
+	* Container for the CSS style configuration variables.
+	*/
+	this.Config = new Object();
+	
+	this.Config.Style = {
+		// Style variables
+		CSS_ROW_HEADER: "calrowhead",
+		CSS_ROW_FOOTER: "calrowfoot",
+		CSS_CELL : "calcell",
+		CSS_CELL_SELECTED : "selected",
+		CSS_CELL_RESTRICTED : "restricted",
+		CSS_CELL_TODAY : "today",
+		CSS_CELL_OOM : "oom",
+		CSS_CELL_OOB : "previous",
+		CSS_HEADER : "calheader",
+		CSS_HEADER_TEXT : "calhead",
+		CSS_WEEKDAY_CELL : "calweekdaycell",
+		CSS_WEEKDAY_ROW : "calweekdayrow",
+		CSS_FOOTER : "calfoot",
+		CSS_CALENDAR : "yui-calendar",
+		CSS_CONTAINER : "yui-calcontainer",
+		CSS_2UPWRAPPER : "yui-cal2upwrapper", 
+		CSS_NAV_LEFT : "calnavleft",
+		CSS_NAV_RIGHT : "calnavright",
+		CSS_CELL_TOP : "calcelltop",
+		CSS_CELL_LEFT : "calcellleft",
+		CSS_CELL_RIGHT : "calcellright",
+		CSS_CELL_BOTTOM : "calcellbottom",
+		CSS_CELL_HOVER : "calcellhover",
+		CSS_CELL_HIGHLIGHT1 : "highlight1",
+		CSS_CELL_HIGHLIGHT2 : "highlight2",
+		CSS_CELL_HIGHLIGHT3 : "highlight3",
+		CSS_CELL_HIGHLIGHT4 : "highlight4"
+	};
+
+	this.Style = this.Config.Style;
+
+	this.Config.Locale = {
+		// Locale definition
+		MONTHS_SHORT : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+		MONTHS_LONG : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+		WEEKDAYS_1CHAR : ["S", "M", "T", "W", "T", "F", "S"],
+		WEEKDAYS_SHORT : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+		WEEKDAYS_MEDIUM : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+		WEEKDAYS_LONG : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+		DATE_DELIMITER : ",",
+		DATE_FIELD_DELIMITER : "/",
+		DATE_RANGE_DELIMITER : "-",
+		MY_MONTH_POSITION : 1,
+		MY_YEAR_POSITION : 2,
+		MD_MONTH_POSITION : 1,
+		MD_DAY_POSITION : 2,
+		MDY_MONTH_POSITION : 1,
+		MDY_DAY_POSITION : 2,
+		MDY_YEAR_POSITION : 3
+	};
+
+	this.Locale = this.Config.Locale;
+
+	this.Config.Options = {
+		// Configuration variables
+		MULTI_SELECT : false,
+		SHOW_WEEKDAYS : true,
+		START_WEEKDAY : 0,
+		SHOW_WEEK_HEADER : false,
+		SHOW_WEEK_FOOTER : false,
+		HIDE_BLANK_WEEKS : false,
+		NAV_ARROW_LEFT : YAHOO.widget.Calendar_Core.IMG_ROOT + "us/tr/callt.gif",
+		NAV_ARROW_RIGHT : YAHOO.widget.Calendar_Core.IMG_ROOT + "us/tr/calrt.gif"
+	};
+
+	this.Options = this.Config.Options;
+
+	this.customConfig();
+
+	if (! this.Options.LOCALE_MONTHS) {
+		this.Options.LOCALE_MONTHS=this.Locale.MONTHS_LONG;
+	}
+	if (! this.Options.LOCALE_WEEKDAYS) {
+		this.Options.LOCALE_WEEKDAYS=this.Locale.WEEKDAYS_SHORT;
+	}
+
+	// If true, reconfigure weekday arrays to place Mondays first
+	if (this.Options.START_WEEKDAY > 0) {
+		for (var w=0;w<this.Options.START_WEEKDAY;++w) {
+			this.Locale.WEEKDAYS_SHORT.push(this.Locale.WEEKDAYS_SHORT.shift());
+			this.Locale.WEEKDAYS_MEDIUM.push(this.Locale.WEEKDAYS_MEDIUM.shift());
+			this.Locale.WEEKDAYS_LONG.push(this.Locale.WEEKDAYS_LONG.shift());		
+		}
+	}
+};
+
+/**
+* This method is called when subclasses need to override configuration variables
+* or create new ones. Values can be explicitly set as follows:
+* <blockquote><code>
+*	this.Config.Style.CSS_CELL = "newcalcell";
+*	this.Config.Locale.MONTHS_SHORT = ["Jan", "Fv", "Mars", "Avr", "Mai", "Juin", "Juil", "Aot", "Sept", "Oct", "Nov", "Dc"];
+* </code></blockquote>
+*/
+YAHOO.widget.Calendar_Core.prototype.customConfig = function() { };
+
+/**
+* Builds the date label that will be displayed in the calendar header or
+* footer, depending on configuration.
+* @return	The formatted calendar month label
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.buildMonthLabel = function() {
+	var text = this.Options.LOCALE_MONTHS[this.pageDate.getMonth()] + " " + this.pageDate.getFullYear();
+	return text;
+};
+
+/**
+* Builds the date digit that will be displayed in calendar cells
+* @return	The formatted day label
+* @type	String
+*/
+YAHOO.widget.Calendar_Core.prototype.buildDayLabel = function(workingDate) {
+	var day = workingDate.getDate();
+	return day;
+};
+
+
+
+/**
+* Builds the calendar table shell that will be filled in with dates and formatting.
+* This method calls buildShellHeader, buildShellBody, and buildShellFooter (in that order) 
+* to construct the pieces of the calendar table. The construction of the shell should
+* only happen one time when the calendar is initialized.
+*/
+YAHOO.widget.Calendar_Core.prototype.buildShell = function() {
+	
+	this.table = document.createElement("TABLE");
+	this.table.cellSpacing = 0;	
+	YAHOO.widget.Calendar_Core.setCssClasses(this.table, [this.Style.CSS_CALENDAR]);
+
+	this.table.id = this.id;
+	
+	this.buildShellHeader();
+	this.buildShellBody();
+	this.buildShellFooter();
+	
+	YAHOO.util.Event.addListener(window, "unload", this._unload, this);
+};
+
+/**
+* Builds the calendar shell header by inserting a THEAD into the local calendar table.
+*/
+YAHOO.widget.Calendar_Core.prototype.buildShellHeader = function() {
+	var head = document.createElement("THEAD");
+	var headRow = document.createElement("TR");
+
+	var headerCell = document.createElement("TH");
+	
+	var colSpan = 7;
+	if (this.Config.Options.SHOW_WEEK_HEADER) {
+		this.weekHeaderCells = new Array();
+		colSpan += 1;
+	}
+	if (this.Config.Options.SHOW_WEEK_FOOTER) {
+		this.weekFooterCells = new Array();
+		colSpan += 1;
+	}	
+	
+	headerCell.colSpan = colSpan;
+	
+	YAHOO.widget.Calendar_Core.setCssClasses(headerCell,[this.Style.CSS_HEADER_TEXT]);
+
+	this.headerCell = headerCell;
+
+	headRow.appendChild(headerCell);
+	head.appendChild(headRow);
+
+	// Append day labels, if needed
+	if (this.Options.SHOW_WEEKDAYS) {
+		var row = document.createElement("TR");
+		var fillerCell;
+
+		YAHOO.widget.Calendar_Core.setCssClasses(row,[this.Style.CSS_WEEKDAY_ROW]);
+		
+		if (this.Config.Options.SHOW_WEEK_HEADER) {
+			fillerCell = document.createElement("TH");
+			YAHOO.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
+			row.appendChild(fillerCell);
+		}
+		
+		for(var i=0;i<this.Options.LOCALE_WEEKDAYS.length;++i) {
+			var cell = document.createElement("TH");
+			YAHOO.widget.Calendar_Core.setCssClasses(cell,[this.Style.CSS_WEEKDAY_CELL]);
+			cell.innerHTML=this.Options.LOCALE_WEEKDAYS[i];
+			row.appendChild(cell);
+		}
+
+		if (this.Config.Options.SHOW_WEEK_FOOTER) {
+			fillerCell = document.createElement("TH");
+			YAHOO.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
+			row.appendChild(fillerCell);
+		}
+				
+		head.appendChild(row);
+	}
+
+	this.table.appendChild(head);
+};
+
+/**
+* Builds the calendar shell body (6 weeks by 7 days)
+*/
+YAHOO.widget.Calendar_Core.prototype.buildShellBody = function() {
+	// This should only get executed once
+	this.tbody = document.createElement("TBODY");
+
+	for (var r=0;r<6;++r) {
+		var row = document.createElement("TR");
+		
+		for (var c=0;c<this.headerCell.colSpan;++c) {
+			var cell;
+			if (this.Config.Options.SHOW_WEEK_HEADER && c===0) { // Row header
+				cell = document.createElement("TH");
+				this.weekHeaderCells[this.weekHeaderCells.length] = cell;
+			} else if (this.Config.Options.SHOW_WEEK_FOOTER && c==(this.headerCell.colSpan-1)){ // Row footer
+				cell = document.createElement("TH");
+				this.weekFooterCells[this.weekFooterCells.length] = cell;
+			} else {
+				cell = document.createElement("TD");
+				this.cells[this.cells.length] = cell;
+				YAHOO.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL]);
+				YAHOO.util.Event.addListener(cell, "click", this.doSelectCell, this);
+
+				YAHOO.util.Event.addListener(cell, "mouseover", this.doCellMouseOver, this);
+				YAHOO.util.Event.addListener(cell, "mouseout", this.doCellMouseOut, this);
+			}
+			row.appendChild(cell);
+		}
+		this.tbody.appendChild(row);
+	}
+	
+	this.table.appendChild(this.tbody);
+};
+
+/**
+* Builds the calendar shell footer. In the default implementation, there is
+* no footer.
+*/
+YAHOO.widget.Calendar_Core.prototype.buildShellFooter = function() { };
+
+/**
+* Outputs the calendar shell to the DOM, inserting it into the placeholder element.
+*/
+YAHOO.widget.Calendar_Core.prototype.renderShell = function() {
+	this.oDomContainer.appendChild(this.table);
+	this.shellRendered = true;
+};
+
+/**
+* Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
+* when the method is called: renderHeader, renderBody, renderFooter.
+* Refer to the documentation for those methods for information on 
+* individual render tasks.
+*/
+YAHOO.widget.Calendar_Core.prototype.render = function() {
+	if (! this.shellRendered) {
+		this.buildShell();
+		this.renderShell();
+	}
+
+	this.resetRenderers();
+
+	this.cellDates.length = 0;
+
+	// Find starting day of the current month
+	var workingDate = YAHOO.widget.DateMath.findMonthStart(this.pageDate);
+
+	this.renderHeader();
+	this.renderBody(workingDate);
+	this.renderFooter();
+
+	this.onRender();
+};
+
+
+
+/**
+* Appends the header contents into the widget header.
+*/
+YAHOO.widget.Calendar_Core.prototype.renderHeader = function() {
+	this.logger.log("Rendering header", "info");
+
+	this.headerCell.innerHTML = "";
+	
+	var headerContainer = document.createElement("DIV");
+	headerContainer.className = this.Style.CSS_HEADER;
+	
+	headerContainer.appendChild(document.createTextNode(this.buildMonthLabel()));
+	
+	this.headerCell.appendChild(headerContainer);
+};
+
+/**
+* Appends the calendar body. The default implementation calculates the number of
+* OOM (out of month) cells that need to be rendered at the start of the month, renders those, 
+* and renders all the day cells using the built-in cell rendering methods.
+*
+* While iterating through all of the cells, the calendar checks for renderers in the
+* local render stack that match the date of the current cell, and then applies styles
+* as necessary.
+* 
+* @param {Date}	workingDate	The current working Date object being used to generate the calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.renderBody = function(workingDate) {
+	this.logger.log("Rendering body", "info");
+
+	this.preMonthDays = workingDate.getDay();
+	if (this.Options.START_WEEKDAY > 0) {
+		this.preMonthDays -= this.Options.START_WEEKDAY;
+	}
+	if (this.preMonthDays < 0) {
+		this.preMonthDays += 7;
+	}
+	
+	this.logger.log(this.preMonthDays + " preciding out-of-month days", "info");
+
+	this.monthDays = YAHOO.widget.DateMath.findMonthEnd(workingDate).getDate();
+	this.logger.log(this.monthDays + " month days", "info");
+
+	this.postMonthDays = YAHOO.widget.Calendar_Core.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
+	this.logger.log(this.postMonthDays + " post-month days", "info");
+	
+	workingDate = YAHOO.widget.DateMath.subtract(workingDate, YAHOO.widget.DateMath.DAY, this.preMonthDays);
+	this.logger.log("Calendar page starts on " + workingDate, "info");
+	
+	var weekRowIndex = 0;
+	
+	for (var c=0;c<this.cells.length;++c) {
+		var cellRenderers = new Array();
+		
+		var cell = this.cells[c];
+		this.clearElement(cell);
+
+		cell.index = c;
+		cell.id = this.id + "_cell" + c;
+		
+		this.cellDates[this.cellDates.length]=[workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]; // Add this date to cellDates
+
+		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
+			var rowHeaderCell = null;
+			var rowFooterCell = null;
+			
+			if (this.Options.SHOW_WEEK_HEADER) {
+				rowHeaderCell = this.weekHeaderCells[weekRowIndex];
+				this.clearElement(rowHeaderCell);
+			}
+			
+			if (this.Options.SHOW_WEEK_FOOTER) {
+				rowFooterCell = this.weekFooterCells[weekRowIndex];
+				this.clearElement(rowFooterCell);
+			}			
+			
+			if (this.Options.HIDE_BLANK_WEEKS && this.isDateOOM(workingDate) && ! YAHOO.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+				// The first day of the week is not in this month, and it's not an overlap week
+				continue;
+			} else {
+				if (rowHeaderCell) {
+					this.renderRowHeader(workingDate, rowHeaderCell);
+				}
+				if (rowFooterCell) {
+					this.renderRowFooter(workingDate, rowFooterCell);
+				}	
+			}
+		}
+
+		this.logger.log("Rendering cell " + cell.id + " (" + workingDate.getFullYear() + "-" + (workingDate.getMonth()+1) + "-" + workingDate.getDate() + ")", "cellrender");
+
+		var renderer = null;
+		
+		if (workingDate.getFullYear()	== this.today.getFullYear() &&
+			workingDate.getMonth()		== this.today.getMonth() &&
+			workingDate.getDate()		== this.today.getDate()) {
+			cellRenderers[cellRenderers.length]=this.renderCellStyleToday;
+		}
+		
+		if (this.isDateOOM(workingDate)) {
+			cellRenderers[cellRenderers.length]=this.renderCellNotThisMonth;
+		} else {
+			for (var r=0;r<this.renderStack.length;++r) {
+				var rArray = this.renderStack[r];
+				var type = rArray[0];
+				
+				var month;
+				var day;
+				var year;
+
+				switch (type) {
+					case YAHOO.widget.Calendar_Core.DATE:
+						month = rArray[1][1];
+						day = rArray[1][2];
+						year = rArray[1][0];
+
+						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
+							renderer = rArray[2];
+							this.renderStack.splice(r,1);
+						}
+						break;
+					case YAHOO.widget.Calendar_Core.MONTH_DAY:
+						month = rArray[1][0];
+						day = rArray[1][1];
+						
+						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
+							renderer = rArray[2];
+							this.renderStack.splice(r,1);
+						}
+						break;
+					case YAHOO.widget.Calendar_Core.RANGE:
+						var date1 = rArray[1][0];
+						var date2 = rArray[1][1];
+
+						var d1month = date1[1];
+						var d1day = date1[2];
+						var d1year = date1[0];
+						
+						var d1 = new Date(d1year, d1month-1, d1day);
+
+						var d2month = date2[1];
+						var d2day = date2[2];
+						var d2year = date2[0];
+
+						var d2 = new Date(d2year, d2month-1, d2day);
+
+						if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
+							renderer = rArray[2];
+
+							if (workingDate.getTime()==d2.getTime()) { 
+								this.renderStack.splice(r,1);
+							}
+						}
+						break;
+					case YAHOO.widget.Calendar_Core.WEEKDAY:
+						
+						var weekday = rArray[1][0];
+						if (workingDate.getDay()+1 == weekday) {
+							renderer = rArray[2];
+						}
+						break;
+					case YAHOO.widget.Calendar_Core.MONTH:
+						
+						month = rArray[1][0];
+						if (workingDate.getMonth()+1 == month) {
+							renderer = rArray[2];
+						}
+						break;
+				}
+				
+				if (renderer) {
+					cellRenderers[cellRenderers.length]=renderer;
+				}
+			}
+
+		}
+
+		if (this._indexOfSelectedFieldArray([workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]) > -1) {
+			cellRenderers[cellRenderers.length]=this.renderCellStyleSelected; 
+		}
+
+		if (this.minDate) {
+			this.minDate = YAHOO.widget.DateMath.clearTime(this.minDate);
+		}
+		if (this.maxDate) {
+			this.maxDate = YAHOO.widget.DateMath.clearTime(this.maxDate);
+		}
+
+		if (
+			(this.minDate && (workingDate.getTime() < this.minDate.getTime())) ||
+			(this.maxDate && (workingDate.getTime() > this.maxDate.getTime()))
+		) {
+			cellRenderers[cellRenderers.length]=this.renderOutOfBoundsDate;
+		} else {
+			cellRenderers[cellRenderers.length]=this.renderCellDefault;	
+		}
+		
+		for (var x=0;x<cellRenderers.length;++x) {
+			var ren = cellRenderers[x];
+			this.logger.log("renderer[" + x + "] for (" + workingDate.getFullYear() + "-" + (workingDate.getMonth()+1) + "-" + workingDate.getDate() + ")", "cellrender");
+
+			if (ren.call(this,workingDate,cell) == YAHOO.widget.Calendar_Core.STOP_RENDER) {
+				break;
+			}
+		}
+		
+		workingDate = YAHOO.widget.DateMath.add(workingDate, YAHOO.widget.DateMath.DAY, 1); // Go to the next day
+		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
+			weekRowIndex += 1;
+		}
+
+		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL);
+
+		if (c >= 0 && c <= 6) {
+			YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_TOP);
+		}
+		if ((c % 7) == 0) {
+			YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
+		}
+		if (((c+1) % 7) == 0) {
+			YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_RIGHT);
+		}
+		
+		var postDays = this.postMonthDays; 
+		if (postDays >= 7 && this.Options.HIDE_BLANK_WEEKS) {
+			var blankWeeks = Math.floor(postDays/7);
+			for (var p=0;p<blankWeeks;++p) {
+				postDays -= 7;
+			}
+		}
+		
+		if (c >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
+			YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_BOTTOM);
+		}
+	
+		this.logger.log("Final styles for (" + workingDate.getFullYear() + "-" + (workingDate.getMonth()+1) + "-" + workingDate.getDate() + "): " + cell.className, "cellrender");
+
+	}
+		
+};
+
+/**
+* Appends the contents of the calendar widget footer into the shell. By default, 
+* the calendar does not contain a footer, and this method must be implemented by 
+* subclassing the widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.renderFooter = function() { };
+
+/**
+* @private
+*/
+YAHOO.widget.Calendar_Core.prototype._unload = function(e, cal) {
+	for (var c in cal.cells) {
+		c = null;
+	}
+	
+	cal.cells = null;
+	
+	cal.tbody = null;
+	cal.oDomContainer = null;
+	cal.table = null;
+	cal.headerCell = null;
+	
+	cal = null;
+};
+												  
+												  
+/****************** BEGIN BUILT-IN TABLE CELL RENDERERS ************************************/
+
+YAHOO.widget.Calendar_Core.prototype.renderOutOfBoundsDate = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOB);
+	cell.innerHTML = workingDate.getDate();
+	return YAHOO.widget.Calendar_Core.STOP_RENDER;
+}
+
+/**
+* Renders the row header for a week. The date passed in should be
+* the first date of the given week.
+* @param {Date}					workingDate		The current working Date object (beginning of the week) being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.renderRowHeader = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_ROW_HEADER);
+	
+	var useYear = this.pageDate.getFullYear();
+	
+	if (! YAHOO.widget.DateMath.isYearOverlapWeek(workingDate)) {
+		useYear = workingDate.getFullYear();
+	}
+	
+	var weekNum = YAHOO.widget.DateMath.getWeekNumber(workingDate, useYear, this.Options.START_WEEKDAY);
+	cell.innerHTML = weekNum;
+	
+	if (this.isDateOOM(workingDate) && ! YAHOO.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);	
+	}
+};
+
+/**
+* Renders the row footer for a week. The date passed in should be
+* the first date of the given week.
+* @param {Date}					workingDate		The current working Date object (beginning of the week) being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.renderRowFooter = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_ROW_FOOTER);
+	
+	if (this.isDateOOM(workingDate) && ! YAHOO.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);	
+	}
+};
+
+/**
+* Renders a single standard calendar cell in the calendar widget table.
+* All logic for determining how a standard default cell will be rendered is 
+* encapsulated in this method, and must be accounted for when extending the
+* widget class.
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellDefault = function(workingDate, cell) {
+	cell.innerHTML = "";
+	var link = document.createElement("a");
+
+	link.href="javascript:void(null);";
+	link.name=this.id+"__"+workingDate.getFullYear()+"_"+(workingDate.getMonth()+1)+"_"+workingDate.getDate();
+
+	link.appendChild(document.createTextNode(this.buildDayLabel(workingDate)));
+	cell.appendChild(link);
+};
+
+/**
+* Renders a single standard calendar cell using the CSS hightlight1 style
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleHighlight1 = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
+};
+
+/**
+* Renders a single standard calendar cell using the CSS hightlight2 style
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleHighlight2 = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
+};
+
+/**
+* Renders a single standard calendar cell using the CSS hightlight3 style
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleHighlight3 = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
+};
+
+/**
+* Renders a single standard calendar cell using the CSS hightlight4 style
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleHighlight4 = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
+};
+
+/**
+* Applies the default style used for rendering today's date to the current calendar cell
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleToday = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
+};
+
+/**
+* Applies the default style used for rendering selected dates to the current calendar cell
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellStyleSelected = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
+};
+
+/**
+* Applies the default style used for rendering dates that are not a part of the current
+* month (preceding or trailing the cells for the current month)
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderCellNotThisMonth = function(workingDate, cell) {
+	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);
+	cell.innerHTML=workingDate.getDate();
+	return YAHOO.widget.Calendar_Core.STOP_RENDER;
+};
+
+/**
+* Renders the current calendar cell as a non-selectable "black-out" date using the default
+* restricted style.
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	YAHOO.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+YAHOO.widget.Calendar_Core.prototype.renderBodyCellRestricted = function(workingDate, cell) {
+	YAHOO.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL,this.Style.CSS_CELL_RESTRICTED]);
+	cell.innerHTML=workingDate.getDate();
+	return YAHOO.widget.Calendar_Core.STOP_RENDER;
+};
+/******************** END BUILT-IN TABLE CELL RENDERERS ************************************/
+
+/******************** BEGIN MONTH NAVIGATION METHODS ************************************/
+/**
+* Adds the designated number of months to the current calendar month, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of months to add to the current calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.addMonths = function(count) {
+	this.pageDate = YAHOO.widget.DateMath.add(this.pageDate, YAHOO.widget.DateMath.MONTH, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Subtracts the designated number of months from the current calendar month, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of months to subtract from the current calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.subtractMonths = function(count) {
+	this.pageDate = YAHOO.widget.DateMath.subtract(this.pageDate, YAHOO.widget.DateMath.MONTH, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Adds the designated number of years to the current calendar, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of years to add to the current calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.addYears = function(count) {
+	this.pageDate = YAHOO.widget.DateMath.add(this.pageDate, YAHOO.widget.DateMath.YEAR, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Subtcats the designated number of years from the current calendar, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of years to subtract from the current calendar
+*/
+YAHOO.widget.Calendar_Core.prototype.subtractYears = function(count) {
+	this.pageDate = YAHOO.widget.DateMath.subtract(this.pageDate, YAHOO.widget.DateMath.YEAR, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Navigates to the next month page in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.nextMonth = function() {
+	this.addMonths(1);
+};
+
+/**
+* Navigates to the previous month page in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.previousMonth = function() {
+	this.subtractMonths(1);
+};
+
+/**
+* Navigates to the next year in the currently selected month in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.nextYear = function() {
+	this.addYears(1);
+};
+
+/**
+* Navigates to the previous year in the currently selected month in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.previousYear = function() {
+	this.subtractYears(1);
+};
+
+/****************** END MONTH NAVIGATION METHODS ************************************/
+
+/************* BEGIN SELECTION METHODS *************************************************************/
+
+/**
+* Resets the calendar widget to the originally selected month and year, and 
+* sets the calendar to the initial selection(s).
+*/
+YAHOO.widget.Calendar_Core.prototype.reset = function() {
+	this.selectedDates.length = 0;
+	this.selectedDates = this._selectedDates.concat();
+
+	this.pageDate = new Date(this._pageDate.getTime());
+	this.onReset();
+};
+
+/**
+* Clears the selected dates in the current calendar widget and sets the calendar
+* to the current month and year.
+*/
+YAHOO.widget.Calendar_Core.prototype.clear = function() {
+	this.selectedDates.length = 0;
+	this.pageDate = new Date(this.today.getTime());
+	this.onClear();
+};
+
+/**
+* Selects a date or a collection of dates on the current calendar. This method, by default,
+* does not call the render method explicitly. Once selection has completed, render must be 
+* called for the changes to be reflected visually.
+* @param	{String/Date/Date[]}	date	The date string of dates to select in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.
+* @return						Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.select = function(date) {
+	this.onBeforeSelect();
+	this.logger.log("Select: " + date, "info");
+
+	var aToBeSelected = this._toFieldArray(date);
+	this.logger.log("Selection field array: " + aToBeSelected, "info");
+
+	for (var a=0;a<aToBeSelected.length;++a) {
+		var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
+		if (this._indexOfSelectedFieldArray(toSelect) == -1) { // not already selected?
+			this.selectedDates[this.selectedDates.length]=toSelect;
+		}
+	}
+	
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.onSelect(aToBeSelected);
+
+	return this.getSelectedDates();
+};
+
+/**
+* Selects a date on the current calendar by referencing the index of the cell that should be selected.
+* This method is used to easily select a single cell (usually with a mouse click) without having to do
+* a full render. The selected style is applied to the cell directly.
+* @param	{Integer}	cellIndex	The index of the cell to select in the current calendar. 
+* @return							Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.selectCell = function(cellIndex) {
+	this.onBeforeSelect();
+
+	this.cells = this.tbody.getElementsByTagName("TD");
+
+	var cell = this.cells[cellIndex];
+	var cellDate = this.cellDates[cellIndex];
+
+	var dCellDate = this._toDate(cellDate);
+	this.logger.log("Select: " + dCellDate, "info");
+
+	var selectDate = cellDate.concat();
+
+	this.selectedDates.push(selectDate);
+	
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.renderCellStyleSelected(dCellDate,cell);
+
+	this.onSelect([selectDate]);
+	this.doCellMouseOut.call(cell, null, this);
+
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects a date or a collection of dates on the current calendar. This method, by default,
+* does not call the render method explicitly. Once deselection has completed, render must be 
+* called for the changes to be reflected visually.
+* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.	
+* @return						Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.deselect = function(date) {
+	this.onBeforeDeselect();
+
+	var aToBeSelected = this._toFieldArray(date);
+
+	this.logger.log("Select: " + aToBeSelected, "info");
+
+	for (var a=0;a<aToBeSelected.length;++a) {
+		var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
+		var index = this._indexOfSelectedFieldArray(toSelect);
+	
+		if (index != -1) {	
+			this.selectedDates.splice(index,1);
+		}
+	}
+
+	if (this.parent) {
+		this.parent.sync(this);
+	} 
+
+	this.onDeselect(aToBeSelected);
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
+* This method is used to easily deselect a single cell (usually with a mouse click) without having to do
+* a full render. The selected style is removed from the cell directly.
+* @param	{Integer}	cellIndex	The index of the cell to deselect in the current calendar. 
+* @return							Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.deselectCell = function(i) {
+	this.onBeforeDeselect();
+	this.cells = this.tbody.getElementsByTagName("TD");
+
+	var cell = this.cells[i];
+	var cellDate = this.cellDates[i];
+	var cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
+
+	var dCellDate = this._toDate(cellDate);
+	this.logger.log("Deselect: " + dCellDate, "info");
+
+	var selectDate = cellDate.concat();
+
+	if (cellDateIndex > -1) {
+		if (this.pageDate.getMonth() == dCellDate.getMonth() &&
+			this.pageDate.getFullYear() == dCellDate.getFullYear()) {
+			YAHOO.util.Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
+		}
+
+		this.selectedDates.splice(cellDateIndex, 1);
+	}
+
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.onDeselect(selectDate);
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects all dates on the current calendar.
+* @return				Array of JavaScript Date objects representing all individual dates that are currently selected.
+*						Assuming that this function executes properly, the return value should be an empty array.
+*						However, the empty array is returned for the sake of being able to check the selection status
+*						of the calendar.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.deselectAll = function() {
+	this.onBeforeDeselect();
+	var count = this.selectedDates.length;
+	var sel = this.selectedDates.concat();
+	this.selectedDates.length = 0;
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+	
+	if (count > 0) {
+		this.onDeselect(sel);
+	}
+
+	return this.getSelectedDates();
+};
+/************* END SELECTION METHODS *************************************************************/
+
+
+/************* BEGIN TYPE CONVERSION METHODS ****************************************************/
+
+/**
+* Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
+* used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
+* @private
+* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.	
+* @return						Array of date field arrays
+* @type Array[](Integer[])
+*/
+YAHOO.widget.Calendar_Core.prototype._toFieldArray = function(date) {
+	var returnDate = new Array();
+
+	if (date instanceof Date) {
+		returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
+	} else if (typeof date == 'string') {
+		returnDate = this._parseDates(date);
+	} else if (date instanceof Array) {
+		for (var i=0;i<date.length;++i) {
+			var d = date[i];
+			returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
+		}
+	}
+	
+	return returnDate;
+};
+
+/**
+* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
+* @private
+* @param	{Integer[]}		dateFieldArray	The date field array to convert to a JavaScript Date.
+* @return					JavaScript Date object representing the date field array
+* @type Date
+*/
+YAHOO.widget.Calendar_Core.prototype._toDate = function(dateFieldArray) {
+	if (dateFieldArray instanceof Date) {
+		return dateFieldArray;
+	} else {
+		return new Date(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
+	}
+};
+/************* END TYPE CONVERSION METHODS ******************************************************/
+
+
+/************* BEGIN UTILITY METHODS ****************************************************/
+/**
+* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
+* @private
+* @param	{Integer[]}	array1	The first date field array to compare
+* @param	{Integer[]}	array2	The first date field array to compare
+* @return						The boolean that represents the equality of the two arrays
+* @type Boolean
+*/
+YAHOO.widget.Calendar_Core.prototype._fieldArraysAreEqual = function(array1, array2) {
+	var match = false;
+
+	if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
+		match=true;	
+	}
+
+	return match;
+};
+
+/**
+* Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
+* @private
+* @param	{Integer[]}		find	The date field array to search for
+* @return					The index of the date field array within the collection of selected dates.
+*								-1 will be returned if the date is not found.
+* @type Integer
+*/
+YAHOO.widget.Calendar_Core.prototype._indexOfSelectedFieldArray = function(find) {
+	var selected = -1;
+
+	for (var s=0;s<this.selectedDates.length;++s) {
+		var sArray = this.selectedDates[s];
+		if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
+			selected = s;
+			break;
+		}
+	}
+
+	return selected;
+};
+
+/**
+* Determines whether a given date is OOM (out of month).
+* @param	{Date}	date	The JavaScript Date object for which to check the OOM status
+* @return	{Boolean}	true if the date is OOM
+*/
+YAHOO.widget.Calendar_Core.prototype.isDateOOM = function(date) {
+	var isOOM = false;
+	if (date.getMonth() != this.pageDate.getMonth()) {
+		isOOM = true;
+	}
+	return isOOM;
+};
+
+/************* END UTILITY METHODS *******************************************************/
+
+/************* BEGIN EVENT HANDLERS ******************************************************/
+
+/**
+* Event executed before a date is selected in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.onBeforeSelect = function() {
+	if (! this.Options.MULTI_SELECT) {
+		this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
+		this.deselectAll();
+	}
+};
+
+/**
+* Event executed when a date is selected in the calendar widget.
+* @param	{Array}	selected	An array of date field arrays representing which date or dates were selected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
+*/
+YAHOO.widget.Calendar_Core.prototype.onSelect = function(selected) { };
+
+/**
+* Event executed before a date is deselected in the calendar widget.
+*/
+YAHOO.widget.Calendar_Core.prototype.onBeforeDeselect = function() { };
+
+/**
+* Event executed when a date is deselected in the calendar widget.
+* @param	{Array}	selected	An array of date field arrays representing which date or dates were deselected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
+*/
+YAHOO.widget.Calendar_Core.prototype.onDeselect = function(deselected) { };
+
+/**
+* Event executed when the user navigates to a different calendar page.
+*/
+YAHOO.widget.Calendar_Core.prototype.onChangePage = function() {
+		var me = this;
+
+		this.renderHeader();
+		if (this.renderProcId) {
+			clearTimeout(this.renderProcId);
+		}
+		this.renderProcId = setTimeout(function() {
+											me.render();
+											me.renderProcId = null;
+										}, 1);
+};
+
+/**
+* Event executed when the calendar widget is rendered.
+*/
+YAHOO.widget.Calendar_Core.prototype.onRender = function() { };
+
+/**
+* Event executed when the calendar widget is reset to its original state.
+*/
+YAHOO.widget.Calendar_Core.prototype.onReset = function() { this.render(); };
+
+/**
+* Event executed when the calendar widget is completely cleared to the current month with no selections.
+*/
+YAHOO.widget.Calendar_Core.prototype.onClear = function() { this.render(); };
+
+/**
+* Validates the calendar widget. This method has no default implementation
+* and must be extended by subclassing the widget.
+* @return	Should return true if the widget validates, and false if
+* it doesn't.
+* @type Boolean
+*/
+YAHOO.widget.Calendar_Core.prototype.validate = function() { return true; };
+
+/************* END EVENT HANDLERS *********************************************************/
+
+
+/************* BEGIN DATE PARSE METHODS ***************************************************/
+
+
+/**
+* Converts a date string to a date field array
+* @private
+* @param	{String}	sDate			Date string. Valid formats are mm/dd and mm/dd/yyyy.
+* @return				A date field array representing the string passed to the method
+* @type Array[](Integer[])
+*/
+YAHOO.widget.Calendar_Core.prototype._parseDate = function(sDate) {
+	var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER);
+	var rArray;
+
+	if (aDate.length == 2) {
+		rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
+		rArray.type = YAHOO.widget.Calendar_Core.MONTH_DAY;
+	} else {
+		rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
+		rArray.type = YAHOO.widget.Calendar_Core.DATE;
+	}
+	return rArray;
+};
+
+/**
+* Converts a multi or single-date string to an array of date field arrays
+* @private
+* @param	{String}	sDates		Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
+* @return							An array of date field arrays
+* @type Array[](Integer[])
+*/
+YAHOO.widget.Calendar_Core.prototype._parseDates = function(sDates) {
+	var aReturn = new Array();
+
+	var aDates = sDates.split(this.Locale.DATE_DELIMITER);
+	
+	for (var d=0;d<aDates.length;++d) {
+		var sDate = aDates[d];
+
+		if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
+			// This is a range
+			var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER);
+
+			var dateStart = this._parseDate(aRange[0]);
+			var dateEnd = this._parseDate(aRange[1]);
+
+			var fullRange = this._parseRange(dateStart, dateEnd);
+			aReturn = aReturn.concat(fullRange);
+		} else {
+			// This is not a range
+			var aDate = this._parseDate(sDate);
+			aReturn.push(aDate);
+		}
+	}
+	return aReturn;
+};
+
+/**
+* Converts a date range to the full list of included dates
+* @private
+* @param	{Integer[]}	startDate	Date field array representing the first date in the range
+* @param	{Integer[]}	endDate		Date field array representing the last date in the range
+* @return							An array of date field arrays
+* @type Array[](Integer[])
+*/
+YAHOO.widget.Calendar_Core.prototype._parseRange = function(startDate, endDate) {
+	var dStart   = new Date(startDate[0],startDate[1]-1,startDate[2]);
+	var dCurrent = YAHOO.widget.DateMath.add(new Date(startDate[0],startDate[1]-1,startDate[2]),YAHOO.widget.DateMath.DAY,1);
+	var dEnd     = new Date(endDate[0],  endDate[1]-1,  endDate[2]);
+
+	var results = new Array();
+	results.push(startDate);
+	while (dCurrent.getTime() <= dEnd.getTime()) {
+		results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
+		dCurrent = YAHOO.widget.DateMath.add(dCurrent,YAHOO.widget.DateMath.DAY,1);
+	}
+	return results;
+};
+
+/************* END DATE PARSE METHODS *****************************************************/
+
+/************* BEGIN RENDERER METHODS *****************************************************/
+
+/**
+* Resets the render stack of the current calendar to its original pre-render value.
+*/
+YAHOO.widget.Calendar_Core.prototype.resetRenderers = function() {
+	this.renderStack = this._renderStack.concat();
+};
+
+/**
+* Clears the inner HTML, CSS class and style information from the specified cell.
+* @param	{HTMLTableCellElement}	The cell to clear
+*/ 
+YAHOO.widget.Calendar_Core.prototype.clearElement = function(cell) {
+	cell.innerHTML = "&nbsp;";
+	cell.className="";
+};
+
+/**
+* Adds a renderer to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the conditions specified in the date string for this renderer.
+* @param	{String}	sDates		A date string to associate with the specified renderer. Valid formats
+*									include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+YAHOO.widget.Calendar_Core.prototype.addRenderer = function(sDates, fnRender) {
+	var aDates = this._parseDates(sDates);
+	for (var i=0;i<aDates.length;++i) {
+		var aDate = aDates[i];
+	
+		if (aDate.length == 2) { // this is either a range or a month/day combo
+			if (aDate[0] instanceof Array) { // this is a range
+				this._addRenderer(YAHOO.widget.Calendar_Core.RANGE,aDate,fnRender);
+			} else { // this is a month/day combo
+				this._addRenderer(YAHOO.widget.Calendar_Core.MONTH_DAY,aDate,fnRender);
+			}
+		} else if (aDate.length == 3) {
+			this._addRenderer(YAHOO.widget.Calendar_Core.DATE,aDate,fnRender);
+		}
+	}
+};
+
+/**
+* The private method used for adding cell renderers to the local render stack.
+* This method is called by other methods that set the renderer type prior to the method call.
+* @private
+* @param	{String}	type		The type string that indicates the type of date renderer being added.
+*									Values are YAHOO.widget.Calendar_Core.DATE, YAHOO.widget.Calendar_Core.MONTH_DAY, YAHOO.widget.Calendar_Core.WEEKDAY,
+*									YAHOO.widget.Calendar_Core.RANGE, YAHOO.widget.Calendar_Core.MONTH
+* @param	{Array}		aDates		An array of dates used to construct the renderer. The format varies based
+*									on the renderer type
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+YAHOO.widget.Calendar_Core.prototype._addRenderer = function(type, aDates, fnRender) {
+	var add = [type,aDates,fnRender];
+	this.renderStack.unshift(add);	
+	
+	this._renderStack = this.renderStack.concat();
+};
+
+/**
+* Adds a month to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the month passed to this method.
+* @param	{Integer}	month		The month (1-12) to associate with this renderer
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+YAHOO.widget.Calendar_Core.prototype.addMonthRenderer = function(month, fnRender) {
+	this._addRenderer(YAHOO.widget.Calendar_Core.MONTH,[month],fnRender);
+};
+
+/**
+* Adds a weekday to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the weekday passed to this method.
+* @param	{Integer}	weekay		The weekday (1-7) to associate with this renderer
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+YAHOO.widget.Calendar_Core.prototype.addWeekdayRenderer = function(weekday, fnRender) {
+	this._addRenderer(YAHOO.widget.Calendar_Core.WEEKDAY,[weekday],fnRender);
+};
+//// END RENDERER METHODS ////
+
+//// BEGIN CSS METHODS ////
+
+/**
+* Sets the specified array of CSS classes into the referenced element
+* @param	{HTMLElement}	element		The element to set the CSS classes into
+* @param	{String[]}		aStyles		An array of CSS class names
+*/
+YAHOO.widget.Calendar_Core.setCssClasses = function(element, aStyles) {
+	element.className = "";
+	var className = aStyles.join(" ");
+	element.className = className;
+};
+
+/**
+* Removes all styles from all body cells in the current calendar table.
+* @param	{style}		The CSS class name to remove from all calendar body cells
+*/
+YAHOO.widget.Calendar_Core.prototype.clearAllBodyCellStyles = function(style) {
+	for (var c=0;c<this.cells.length;++c) {
+		YAHOO.util.Dom.removeClass(this.cells[c],style);
+	}
+};
+
+//// END CSS METHODS ////
+
+//// BEGIN GETTER/SETTER METHODS ////
+/**
+* Sets the calendar's month explicitly.
+* @param {Integer}	month		The numeric month, from 1 (January) to 12 (December)
+*/
+YAHOO.widget.Calendar_Core.prototype.setMonth = function(month) {
+	this.pageDate.setMonth(month);
+};
+
+/**
+* Sets the calendar's year explicitly.
+* @param {Integer}	year		The numeric 4-digit year
+*/
+YAHOO.widget.Calendar_Core.prototype.setYear = function(year) {
+	this.pageDate.setFullYear(year);
+};
+
+/**
+* Gets the list of currently selected dates from the calendar.
+* @return	An array of currently selected JavaScript Date objects.
+* @type Date[]
+*/
+YAHOO.widget.Calendar_Core.prototype.getSelectedDates = function() {
+	var returnDates = new Array();
+
+	for (var d=0;d<this.selectedDates.length;++d) {
+		var dateArray = this.selectedDates[d];
+
+		var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
+		returnD