//// below, 1 - 531, 

/*
 * Tabs 3 - New Wave Tabs
 *
 * Copyright (c) 2007 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 */

(function($) {

    // if the UI scope is not availalable, add it
    $.ui = $.ui || {};

    // tabs initialization
    $.fn.tabs = function(initial, options) {
        if (initial && initial.constructor == Object) { // shift arguments
            options = initial;
            initial = null;
        }
        options = options || {};

        initial = initial && initial.constructor == Number && --initial || 0;

        return this.each(function() {
            new $.ui.tabs(this, $.extend(options, { initial: initial }));
        });
    };

    // other chainable tabs methods
    $.each(['Add', 'Remove', 'Enable', 'Disable', 'Click', 'Load', 'Href'], function(i, method) {
        $.fn['tabs' + method] = function() {
            var args = arguments;
            return this.each(function() {
                var instance = $.ui.tabs.getInstance(this);
                instance[method.toLowerCase()].apply(instance, args);
            });
        };
    });
    $.fn.tabsSelected = function() {
        var selected = -1;
        if (this[0]) {
            var instance = $.ui.tabs.getInstance(this[0]),
                $lis = $('li', this);
            selected = $lis.index( $lis.filter('.' + instance.options.selectedClass)[0] );
        }
        return selected >= 0 ? ++selected : -1;
    };

    // tabs class
    $.ui.tabs = function(el, options) {

        this.source = el;

        this.options = $.extend({

            // basic setup
            initial: 0,
            event: 'click',
            disabled: [],
            cookie: null, // pass options object as expected by cookie plugin: { expires: 7, path: '/', domain: 'jquery.com', secure: true }
            // TODO bookmarkable: $.ajaxHistory ? true : false,
            unselected: false,
            unselect: options.unselected ? true : false,

            // Ajax
            spinner: 'Loading&#8230;',
            cache: false,
            idPrefix: 'ui-tabs-',
            ajaxOptions: {},

            // animations
            fxFade: null,
            /*fxSlide: null,
            fxShow: null,
            fxHide: null,*/
            fxSpeed: 'fast',
            fxShowSpeed: 'normal',
            fxHideSpeed: 'normal',

            // callbacks
            add: function() {},
            remove: function() {},
            enable: function() {},
            disable: function() {},
            click: function() {},
            hide: function() {},
            show: function() {},
            load: function() {},
            
            // templates
            tabTemplate: '<li><a href="#{href}"><span>#{text}</span></a></li>',
            panelTemplate: '<div></div>',

            // CSS classes
            navClass: 'ui-tabs-nav',
            selectedClass: 'ui-tabs-selected',
            unselectClass: 'ui-tabs-unselect',
            disabledClass: 'ui-tabs-disabled',
            panelClass: 'ui-tabs-panel',
            hideClass: 'ui-tabs-hide',
            loadingClass: 'ui-tabs-loading'

        }, options);

        this.options.event += '.ui-tabs'; // namespace event
        this.options.cookie = $.cookie && $.cookie.constructor == Function && this.options.cookie;

        // save instance for later
        $.data(el, $.ui.tabs.INSTANCE_KEY, this);
        
        // create tabs
        this.tabify(true);
    };

    // static
    $.ui.tabs.INSTANCE_KEY = 'ui_tabs_instance';
    $.ui.tabs.getInstance = function(el) {
        return $.data(el, $.ui.tabs.INSTANCE_KEY);
    };

    // instance methods
    $.extend($.ui.tabs.prototype, {
        tabId: function(a) {
            return a.title ? a.title.replace(/\s/g, '_')
                : this.options.idPrefix + $.data(a);
        },
        tabify: function(init) {

            this.$lis = $('li:has(a[href])', this.source);
            this.$tabs = this.$lis.map(function() { return $('a', this)[0] });
            this.$panels = $([]);
            
            var self = this, o = this.options;
            
            this.$tabs.each(function(i, a) {
                // inline tab
                if (a.hash && a.hash.replace('#', '')) { // Safari 2 reports '#' for an empty hash
                    self.$panels = self.$panels.add(a.hash);
                }
                // remote tab
                else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
                    $.data(a, 'href', a.href);
                    var id = self.tabId(a);
                    a.href = '#' + id;
                    self.$panels = self.$panels.add(
                        $('#' + id)[0] || $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
                            .insertAfter( self.$panels[i - 1] || self.source )
                    );
                }
                // invalid tab href
                else {
                    o.disabled.push(i + 1);
                }
            });

            if (init) {

                // attach necessary classes for styling if not present
                $(this.source).hasClass(o.navClass) || $(this.source).addClass(o.navClass);
                this.$panels.each(function() {
                    var $this = $(this);
                    $this.hasClass(o.panelClass) || $this.addClass(o.panelClass);
                });
                
                // disabled tabs
                for (var i = 0, position; position = o.disabled[i]; i++) {
                    this.disable(position);
                }
                
                // Try to retrieve initial tab:
                // 1. from fragment identifier in url if present
                // 2. from cookie
                // 3. from selected class attribute on <li>
                // 4. otherwise use given initial argument
                // 5. check if tab is disabled
                this.$tabs.each(function(i, a) {
                    if (location.hash) {
                        if (a.hash == location.hash) {
                            o.initial = i;
                            // prevent page scroll to fragment
                            //if (($.browser.msie || $.browser.opera) && !o.remote) {
                            if ($.browser.msie || $.browser.opera) {
                                var $toShow = $(location.hash), toShowId = $toShow.attr('id');
                                $toShow.attr('id', '');
                                setTimeout(function() {
                                    $toShow.attr('id', toShowId); // restore id
                                }, 500);
                            }
                            scrollTo(0, 0);
                            return false; // break
                        }
                    } else if (o.cookie) {
                        o.initial = parseInt($.cookie( $.ui.tabs.INSTANCE_KEY + $.data(self.source) )) || 0;
                        return false; // break
                    } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) {
                        o.initial = i;
                        return false; // break
                    }
                });
                var n = this.$lis.length;
                while (this.$lis.eq(o.initial).hasClass(o.disabledClass) && n) {
                    o.initial = ++o.initial < this.$lis.length ? o.initial : 0;
                    n--;
                }
                if (!n) { // all tabs disabled, set option unselected to true
                    o.unselected = o.unselect = true;
                }

                // highlight selected tab
                this.$panels.addClass(o.hideClass);
                this.$lis.removeClass(o.selectedClass);
                if (!o.unselected) {
                    this.$panels.eq(o.initial).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
                    this.$lis.eq(o.initial).addClass(o.selectedClass);
                }

                // load if remote tab
                var href = !o.unselected && $.data(this.$tabs[o.initial], 'href');
                if (href) {
                    this.load(o.initial + 1, href);
                }
                
                // disable click if event is configured to something else
                if (!/^click/.test(o.event)) {
                    this.$tabs.bind('click', function(e) { e.preventDefault(); });
                }

            }

            // setup animations
            var showAnim = {}, showSpeed = o.fxShowSpeed || o.fxSpeed,
                hideAnim = {}, hideSpeed = o.fxHideSpeed || o.fxSpeed;
            if (o.fxSlide || o.fxFade) {
                if (o.fxSlide) {
                    showAnim['height'] = 'show';
                    hideAnim['height'] = 'hide';
                }
                if (o.fxFade) {
                    showAnim['opacity'] = 'show';
                    hideAnim['opacity'] = 'hide';
                }
            } else {
                if (o.fxShow) {
                    showAnim = o.fxShow;
                } else { // use some kind of animation to prevent browser scrolling to the tab
                    showAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
                    showSpeed = 1; // as little as 1 is sufficient
                }
                if (o.fxHide) {
                    hideAnim = o.fxHide;
                } else { // use some kind of animation to prevent browser scrolling to the tab
                    hideAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
                    hideSpeed = 1; // as little as 1 is sufficient
                }
            }

            // reset some styles to maintain print style sheets etc.
            var resetCSS = { display: '', overflow: '', height: '' };
            if (!$.browser.msie) { // not in IE to prevent ClearType font issue
                resetCSS['opacity'] = '';
            }

            // Hide a tab, animation prevents browser scrolling to fragment,
            // $show is optional.
            function hideTab(clicked, $hide, $show) {
                $hide.animate(hideAnim, hideSpeed, function() { //
                    $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
                    if ($.browser.msie && hideAnim['opacity']) {
                        $hide[0].style.filter = '';
                    }
                    o.hide(clicked, $hide[0], $show && $show[0] || null);
                    if ($show) {
                        showTab(clicked, $show, $hide);
                    }
                });
            }

            // Show a tab, animation prevents browser scrolling to fragment,
            // $hide is optional
            function showTab(clicked, $show, $hide) {
                if (!(o.fxSlide || o.fxFade || o.fxShow)) {
                    $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
                }
                $show.animate(showAnim, showSpeed, function() {
                    $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
                    if ($.browser.msie && showAnim['opacity']) {
                        $show[0].style.filter = '';
                    }
                    o.show(clicked, $show[0], $hide && $hide[0] || null);
                });
            }

            // switch a tab
            function switchTab(clicked, $li, $hide, $show) {
                /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
                    $.ajaxHistory.update(clicked.hash);
                }*/
                $li.addClass(o.selectedClass)
                    .siblings().removeClass(o.selectedClass);
                hideTab(clicked, $hide, $show);
            }

            // attach tab event handler, unbind to avoid duplicates from former tabifying...
            this.$tabs.unbind(o.event).bind(o.event, function() {

                //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
                var $li = $(this).parents('li:eq(0)'),
                    $hide = self.$panels.filter(':visible'),
                    $show = $(this.hash);

                // If tab is already selected and not unselectable or tab disabled or click callback returns false stop here.
                // Check if click handler returns false last so that it is not executed for a disabled tab!
                if (($li.hasClass(o.selectedClass) && !o.unselect) || $li.hasClass(o.disabledClass)
                    || o.click(this, $show[0], $hide[0]) === false) {
                    this.blur();
                    return false;
                }
                
                if (o.cookie) {
                    $.cookie($.ui.tabs.INSTANCE_KEY + $.data(self.source), self.$tabs.index(this), o.cookie);
                }
                    
                // if tab may be closed
                if (o.unselect) {
                    if ($li.hasClass(o.selectedClass)) {
                        $li.removeClass(o.selectedClass);
                        self.$panels.stop();
                        hideTab(this, $hide);
                        this.blur();
                        return false;
                    } else if (!$hide.length) {
                        self.$panels.stop();
                        if ($.data(this, 'href')) { // remote tab
                            var a = this;
                            self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() {
                                $li.addClass(o.selectedClass).addClass(o.unselectClass);
                                showTab(a, $show);
                            });
                        } else {
                            $li.addClass(o.selectedClass).addClass(o.unselectClass);
                            showTab(this, $show);
                        }
                        this.blur();
                        return false;
                    }
                }

                // stop possibly running animations
                self.$panels.stop();

                // show new tab
                if ($show.length) {

                    // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
                    /*if ($.browser.msie && o.bookmarkable) {
                        var showId = this.hash.replace('#', '');
                        $show.attr('id', '');
                        setTimeout(function() {
                            $show.attr('id', showId); // restore id
                        }, 0);
                    }*/

                    if ($.data(this, 'href')) { // remote tab
                        var a = this;
                        self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() {
                            switchTab(a, $li, $hide, $show);
                        });
                    } else {
                        switchTab(this, $li, $hide, $show);
                    }

                    // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
                    /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
                    var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
                    setTimeout(function() {
                        scrollTo(scrollX, scrollY);
                    }, 0);*/

                } else {
                    throw 'jQuery UI Tabs: Mismatching fragment identifier.';
                }

                // Prevent IE from keeping other link focussed when using the back button
                // and remove dotted border from clicked link. This is controlled in modern
                // browsers via CSS, also blur removes focus from address bar in Firefox
                // which can become a usability and annoying problem with tabsRotate.
                if ($.browser.msie) {
                    this.blur(); 
                }

                //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
                return false;

            });

        },
        add: function(url, text, position) {
            if (url && text) {
                position = position || this.$tabs.length; // append by default  
                
                var o = this.options,
                    $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{text\}/, text));
                
                var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
                
                // try to find an existing element before creating a new one
                var $panel = $('#' + id);
                $panel = $panel.length && $panel
                    || $(o.panelTemplate).attr('id', id).addClass(o.panelClass).addClass(o.hideClass);
                if (position >= this.$lis.length) {
                    $li.appendTo(this.source);
                    $panel.appendTo(this.source.parentNode);
                } else {
                    $li.insertBefore(this.$lis[position - 1]);
                    $panel.insertBefore(this.$panels[position - 1]);
                }
                
                this.tabify();
                
                if (this.$tabs.length == 1) {
                     $li.addClass(o.selectedClass);
                     $panel.removeClass(o.hideClass);
                     var href = $.data(this.$tabs[0], 'href');
                     if (href) {
                         this.load(position + 1, href);
                     }
                }
                o.add(this.$tabs[position], this.$panels[position]); // callback
            } else {
                throw 'jQuery UI Tabs: Not enough arguments to add tab.';
            }
        },
        remove: function(position) {
            if (position && position.constructor == Number) {                
                var o = this.options, $li = this.$lis.eq(position - 1).remove(),
                    $panel = this.$panels.eq(position - 1).remove();
                    
                // If selected tab was removed focus tab to the right or
                // tab to the left if last tab was removed.
                if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) {
                    this.click(position + (position < this.$tabs.length ? 1 : -1));
                }
                this.tabify();
                o.remove($li.end()[0], $panel[0]); // callback
            }
        },
        enable: function(position) {
            var o = this.options, $li = this.$lis.eq(position - 1);
            $li.removeClass(o.disabledClass);
            if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
                $li.css('display', 'inline-block');
                setTimeout(function() {
                    $li.css('display', 'block')
                }, 0)
            }
            o.enable(this.$tabs[position - 1], this.$panels[position - 1]); // callback
        },
        disable: function(position) {
            var o = this.options;      
            this.$lis.eq(position - 1).addClass(o.disabledClass);
            o.disable(this.$tabs[position - 1], this.$panels[position - 1]); // callback
        },
        click: function(position) {
            this.$tabs.eq(position - 1).trigger(this.options.event);
        },
        load: function(position, url, callback) {
            var self = this, o = this.options,
                $a = this.$tabs.eq(position - 1), a = $a[0], $span = $('span', a);
            
            // shift arguments
            if (url && url.constructor == Function) {
                callback = url;
                url = null;
            }

            // set new URL or get existing
            if (url) {
                $.data(a, 'href', url);
            } else {
                url = $.data(a, 'href');
            }

            // load
            if (o.spinner) {
                $.data(a, 'title', $span.html());
                $span.html('<em>' + o.spinner + '</em>');
            }
            var finish = function() {
                self.$tabs.filter('.' + o.loadingClass).each(function() {
                    $(this).removeClass(o.loadingClass);
                    if (o.spinner) {
//                        $('span', this).html( $.data(this, 'title') );
                    }
                });
                self.xhr = null;
            };
            var ajaxOptions = $.extend(o.ajaxOptions, {
                url: url,
                success: function(r) {
                    $(a.hash).html(r);
                    finish();
                    // This callback is required because the switch has to take 
                    // place after loading has completed.
                    if (callback && callback.constructor == Function) {
                        callback();
                    }
                    if (o.cache) {
                        $.removeData(a, 'href'); // if loaded once do not load them again
                    }
                    o.load(self.$tabs[position - 1], self.$panels[position - 1]); // callback
                }
            });
            if (this.xhr) {
                // terminate pending requests from other tabs and restore title
                this.xhr.abort();
                finish();
            }
            $a.addClass(o.loadingClass);
            setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
                self.xhr = $.ajax(ajaxOptions);
            }, 0);
            
        },
        href: function(position, href) {
            $.data(this.$tabs.eq(position - 1)[0], 'href', href);
        }
    });

})(jQuery);

///////  below, 531 - 2800, jacs.js, only some commenting removed

/* *****************************************************************************
     JavaScript Advanced Calendar Script (JACS) - Cross-Browser pop-up calendar.

     Copyright (C) 2007  Anthony Garrett

     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
     License as published by the Free Software Foundation; either
     version 2.1 of the License, or (at your option) any later version.

     This library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Lesser General Public License for more details.

     You should have received a copy of the GNU Lesser General Public
     License along with this library; if not, it is available at
     the GNU web site (http://www.gnu.org/) or by writing to the
     Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
     Boston, MA  02110-1301  USA

*///*****************************************************************************
/*
   Contact:   Sorry, I can't offer support for this but if you find a problem
              (or just want to tell me how useful you find it), please send
              me an email at jacsFeedback@tarrget.info (Note the two Rs in
              tarrget).  I will try to fix problems quickly but this is a
              spare time thing for me.

   Credits:   I wrote this based on my Simple Calendar Widget script which
              I wrote from scratch myself but I couldn't have done either
              without the superb "JavaScript The Definitive Guide" by David
              Flanagan (Pub. O'Reilly ISBN 0-596-00048-0) and Peter-Paul Koch's
              (PPK) brilliant Quirksmode site.

   Link back: Please give me credit and link back to my page if you can.  To
              ensure that search engines give my page a higher ranking you can
              add the following HTML to any indexed page on your web site:

              <A HREF="http://www.tarrget.info/calendar/jacs.htm">
                JavaScript Advanced Calendar Script (JACS) by Anthony Garrett
              </A>

              Your root directory of the web site should also contain an empty
              file called "jacsblank.html". For a full explanation see
              http://www.tarrget.info/calendar/IEnightmare.html.

   Features:  Easily customised (output date format, colours, language,
                                 year range and week start day)
              Accepts a date as input (see comments below for formats).
              Allows multiple calendars on a page and static calendar displays.

              Cross-browser code tested against;
                    Internet Explorer 6.0.28+    Mozilla  1.7.1
                    Opera             7.52+      Firefox  0.9.1+
                    Konqueror         3.4.0      Safari   3 (Beta for Windows)

   How to add the Calendar to your page:
              This script needs to be defined for your page so add the following
              line;
                    <script type='text/JavaScript' src='jacs.js'></script>

   How to use the Calendar once it is defined for your page:

        Dynamic calendar:

              Simply choose an event to trigger the calendar (like an onclick or an onmouseover)
              and an element to work on (for the calendar to take its initial date from and write
              its output date to) then write it like this;

                    onclick="JACS.show(document.getElementById('myElement'),event);"
                or
                    onfocus="JACS.show(this,event);"

              NOTE: If you wish to use the calendar with an Anchor tag, do not use the
                    href="javascript:JACS.show(...)" syntax.

                    Instead you should use the following;

                    <a href="#" onclick="JACS.show(<<element>>,event);return false;">
                        <<your text>>
                    </a>

              If you are using a text node then specify the text's parent node in the
              function call. The date should be the only text under that node;

                    <p onclick="JACS.show(this,event);"><<date>></p>

        Static calendar:

                    JACS.show(<<element>><<,optional calendar ID>><<,optional disabled days>>);

              A static calendar appears on screen when the page loads, cannot be dragged and
              remains on screen after it has been used to select a date. It returns the date
              into the value of a defined element (e.g. an INPUT element) but, of course,
              that can be hidden.

        Calendar with selected days:

              You can select days of the week by adding arguments to the
              call to JACS.show. These selected days can be the only ones
              enabled or the only ones disabled depending on the setting of
              the attribute valuesEnabled (see below). The values should be
              Sunday = 0 through to Saturday = 6. The parameters can be a
              series of single values or an array holding those values. A call
              to JACS.show with Friday and Monday selected could look something
              like this;

                        JACS.show(<<element>>,event,5,1);
              or this;
                        var myArray = [5,1];
                        JACS.show(<<element>>,event,myArray);

        Named calendar:

                    JACS.show(<<element>>,event<<,calendar ID>>);

              'jacs' is the default ID of the calendar but you can assign any ID
              you want.  You can call one name as many times as you like,
              but as it is one object, it can only appear on screen in one location
              at a time.  If you want more than that then you must give different IDs.

              [Note: in the above paragraph I use "name" and "id" interchangeably, not
                     in the sense of HTML tag attributes "name" and "id". ]

        Calendar with post-processing:

              The following technique runs a function each time a dynamic calendar
              closes or a date is selected from a static calendar:

                    JACS.show(<<Dynamic or Static calendar argument list>>);
                    JACS.next(<<optional calendar ID,>><<function>><<,arguments>>);

              Where <<function>> is a function defined on the calling page
              and <<arguments>> is the list of arguments being passed to that
              function.

              The calendar ID defaults to 'jacs', if you are using a different
              calendar object (See calendar naming above), you must give its
              ID as the first argument.

              NOTES: These two calls are expected in this order (i.e. show before
                     next) because JACS.next expects the calendar object to exist.

                     If JACS.make has not been called for the object and JACS.show
                     is called after JACS.next then the calendar object may not
                     exist (if the object has not been created earlier in the
                     users path through the page) so a JavaScript error would
                     be generated.

              Every function that is triggered using JACS.next() acquires an
              attribute JACSid. This attribute holds the value of the
              calendar ID that JACS.next() has been called for. So, your
              function has access to all of the calendar instance's attributes
              including dateReturned (boolean TRUE if the calendar has been
              closed by selection of a date, otherwise FALSE).

                    E.G. document.getElementById(<<function>>.JACSid).dateReturned

        Disabling or enabling dates or date ranges;

              Setting enabled or disabled date ranges for a calendar object is
              achieved by setting the dates array attribute of the calendar object
              (see more information below).

              By default the calendar object is only created when it is first
              needed for display so you should make sure that it is explicitly
              created using;

                    JACS.make(<<calendar id>><<,dynamic (boolean, default TRUE)>>);

        Combining the techniques:

              A fully defined call to JACS.show, including all optional parameters
              should send parameters in the following order;

                            I/O      Trigger  Calendar  Selected
                            Element  Event    ID        days
              Dynamic         0        1        2         2/3
              Static          0                 1         1/2
              Type          Object   Object   String    Number(s)
              Required      Yes      Yes      No        No
              Default       None     None     'jacs'    None

              NOTE: The Trigger Event is ONLY relevant for dynamic calendars
                    and must be omitted for static calendars.

              Dynamic e.g.  JACS.show(document.getElementById('myElement1'),
                                      event,'jacs',0,1,2,3,4,5,6);

              Static  e.g.  JACS.show(document.getElementById('myElement2'),
                                           'myCal',0,6);

              A single calendar instance must not be called with both Dynamic
              and Static parameters (It is only one structure within the page
              so it cannot remain visible in one location while it is displayed
              in another).

----------------------------------------------------------------------------------
   See http://www.tarrget.info/calendar/scw.htm for a full version history
   up to version 3.60 and
       http://www.tarrget.info/calendar/jacs.htm for versions to date.

   Version   Date        By               Description
   =======   ====        ===============  ===========
     1.00    2007-09-21  Anthony Garrett  Fixed JACS.next parameters - thanks to
                                           Rogier Lankhorst for the feedback, also
                                           refined JACS.next processing.

                                          Updated the event trapping to make it
                                           less intrusive on the page body.  NOTE:
                                           This requires that a dynamic calendar's
                                           second parameter should be the calling
                                           event (not the calling object as in
                                           previous versions).  Thanks to Steve
                                           Davis for the bug report that led to
                                           this change.

                                          Replaced the date input sequence user
                                           configuration setting with parsing the
                                           sequence from the full format. New users
                                           are often confused by the sequence and
                                           in practice (to allow the calendar's date
                                           output to be used for input) the sequence
                                           must always match the full format element
                                           order.

                                          Fixed a bug that caused undelimited
                                           dates to be handled incorrectly. They
                                           are now parsed against the full date
                                           output format then checked for validity.
                                           Thanks to Dan Wood for raising this bug.

                                          Fixed Standards-based (non IE)
                                           calendar dragging which wasn't releasing
                                           the calendar onmouseup.

                                          Fixed problem where selected weekdays
                                           carried over from one call to another
                                           on the same calendar object.

                                          Corrected the Month and Year select box
                                           displays in Opera. They were not changing
                                           when the month was shifted using the
                                           calendar's left and right arrows.

                                          Extended IFRAME backing to all calendar objects
                                           in order to improve calendar display over
                                           some embedded applets and objects.  Thanks to
                                           Stanko Kupcevic for his feedback on this.
                                           NOTE: It is not possible to protect any
                                           JavaScript object displayed over an
                                           embedded DYNAMIC (and, therefore refreshed)
                                           object because browsers usually do not
                                           directly control the screen handling within
                                           the object.  The best advice therefore remains
                                           to design pages in such a way that the calendar
                                           does not overlap embedded objects.

                                         Added curly braces and semi-colons
                                           for best practice and for robustness
                                           when code is compacted/obfuscated.

     0.90    2007-04-04  Anthony Garrett  Major re-write of the script to allow
                                           multiple calendar objects visible on
                                           on the page, and to allow static
                                           calendars. Dropped the legacy
                                           "showCal" entry-point function.

                                          Added ability to select calendar
                                           position relative to return value
                                           element.  Thanks to Justin Lawrence
                                           for that request.

*///*****************************************************************************


/* *****************************************************************************

    EXPOSED CALENDAR OBJECTS (FUNCTIONS):

        JACS.make   Creates calendar objects;
                        is called as part of JACS.show (if needed) but can also
                        be called to create a calendar instance at any time.

        JACS.show   Entry point for display of a calendar: Called in main page.

        JACS.next   Sets up a function that runs when a date is selected on a
                    static calendar or a dynamic calendar moves or closes.

        JACS.cals   returns an array of all the calendar IDs that have been
                    used on the page.

                    NOTES: 1 "used" here means: Invoked with JACS.make or JACS.show.
                             Calls without a defined calendar ID invoke the default
                             ID, 'jacs'.

                           2 Each calendar structure is added to the page when it
                             is first used. So this array may not hold all dynamic
                             calendar IDs that are defined on the page.  If you
                             want to be sure that the array does show all of them,
                             explicitly invoke  JACs.make(<<ID>>); for each ID on
                             page load.

*///*****************************************************************************


var JACS = new function()
    {// This date is used throughout to determine today's date.
     var dateNow = new Date(Date.parse(new Date().toDateString()));

     // This array keeps track of the defined calendars for the page.
     var cals = new Array();

     // This function simply shortens the code relpacing
     // document.getElementById('myID') with getEl('myId')
     // everywhere in the script.
     function getEl(id) {return document.getElementById(id);};

     // This DIV inside an IE-only conditional comments is a
     // reliable way of setting up object testing for IE.
     document.writeln("<!--[if IE]><div id='jacsIE'></div><![endif]-->");
     document.writeln("<!--[if lt IE 7]><div id='jacsIElt7'></div><![endif]-->");


     // I have made every effort to isolate the pop-up script from any
     // CSS defined on the main page but if you have anything set that
     // affects the pop-up (or you may want to change the way it looks)
     // then you can address it in the following style sheets.

     document.writeln(
        '<style type="text/css">' +
            '.jacs, .jacsStatic {padding:1px;vertical-align:middle;}' +
            'iframe.jacs        {position:absolute;visibility:hidden;' +
                                'top:0px;left:0px;width:1px;height:1px;}' +
            'table.jacs, ' +
            'table.jacsStatic   {padding:0px;visibility:hidden;width:200px;'+
                                'cursor:default;text-align:center;}' +
            'table.jacs         {top:0px;left:0px;position:absolute;}' +
        '</style>'  );

     // This style sheet can be extracted from the script and edited into regular
     // CSS (by removing all occurrences of + and '). That can be used as the
     // basis for themes. Classes are described in comments within the style
     // sheet.

     document.writeln(
        '<style type="text/css">' +
            '/* IMPORTANT:  The JACS calendar script requires all ' +
            '               the classes defined here. */' +
            'table.jacs,' +
            'table.jacsStatic   {padding:       1px;' +
                                'vertical-align:middle;' +
                                'border:        ridge 2px;' +
                                'font-size:     10pt;' +
                                'font-family:   Arial,Helvetica,' +
                                                'Sans-Serif;' +
                                'font-weight:   bold;}' +
            'td.jacsDrag,' +
            'td.jacsHead                 {padding:       0px 0px;' +
                                         'text-align:    center;}' +
            'td.jacsDrag                 {font-size:     8pt;}' +
            'select.jacsHead             {margin:        3px 1px;}' +
            'input.jacsHead              {height:        22px;' +
                                         'width:         22px;' +
                                         'vertical-align:middle;' +
                                         'text-align:    center;' +
                                         'margin:        2px 1px;' +
                                         'font-weight:   bold;' +
                                         'font-size:     10pt;' +
                                         'font-family:   fixedSys;}' +
            'td.jacsWeekNumberHead,' +
            'td.jacsWeek                 {padding:       0px;' +
                                         'text-align:    center;' +
                                         'font-weight:   bold;}' +
            'td.jacsFoot,' +
            'td.jacsFootHover,' +
            'td.jacsFoot:hover,' +
            'td.jacsFootDisabled         {padding:       0px;' +
                                         'text-align:    center;' +
                                         'font-weight:   normal;}' +
            'table.jacsCells             {text-align:    right;' +
                                         'font-size:     8pt;' +
                                         'width:         96%;}' +
            'td.jacsCells,' +
            'td.jacsCellsHover,' +
            'td.jacsCells:hover,' +
            'td.jacsCellsDisabled,' +
            'td.jacsCellsExMonth,' +
            'td.jacsCellsExMonthHover,' +
            'td.jacsCellsExMonth:hover,' +
            'td.jacsCellsExMonthDisabled,' +
            'td.jacsCellsWeekend,' +
            'td.jacsCellsWeekendHover,' +
            'td.jacsCellsWeekend:hover,' +
            'td.jacsCellsWeekendDisabled,' +
            'td.jacsInputDate,' +
            'td.jacsInputDateHover,' +
            'td.jacsInputDate:hover,' +
            'td.jacsInputDateDisabled,' +
            'td.jacsWeekNo,' +
            'td.jacsWeeks                {padding:           3px;' +
                                         'width:             16px;' +
                                         'height:            16px;' +
                                         'border-width:      1px;' +
                                         'border-style:      solid;' +
                                         'font-weight:       bold;' +
                                         'vertical-align:    middle;}' +
            '/* Blend the colours into your page here...    */' +
            '/* Calendar background */' +
            'table.jacs,' +
            'table.jacsStatic            {background-color:  #6666CC;}' +
            '/* Drag Handle */' +
            'td.jacsDrag                 {background-color:  #9999CC;' +
                                         'color:             #CCCCFF;}' +
            '/* Week number heading */' +
            'td.jacsWeekNumberHead       {color:             #6666CC;}' +
            '/* Week day headings */' +
            'td.jacsWeek                 {color:             #CCCCCC;}' +
            '/* Week numbers */' +
            'td.jacsWeekNo               {background-color:  #776677;' +
                                         'color:             #CCCCCC;}' +
            '/* Enabled Days */' +
            '/* Week Day */' +
            'td.jacsCells                {background-color:  #CCCCCC;' +
                                         'color:             #000000;}' +
            '/* Day matching the input date */' +
            'td.jacsInputDate            {background-color:  #CC9999;' +
                                         'color:             #FF0000;}' +
            '/* Weekend Day */' +
            'td.jacsCellsWeekend         {background-color:  #CCCCCC;' +
                                         'color:             #CC6666;}' +
            '/* Day outside the current month */' +
            'td.jacsCellsExMonth         {background-color:  #CCCCCC;' +
                                         'color:             #666666;}' +
            '/* Today selector */' +
            'td.jacsFoot                 {background-color:  #6666CC;' +
                                         'color:             #FFFFFF;}' +
            '/* MouseOver/Hover formatting ' +
            '       If you want to "turn off" any of the formatting ' +
            '       then just set to the same as the standard format' +
            '       above. ' +
            ' ' +
            '       Note: The reason that the following are' +
            '       implemented using both a class and a :hover' +
            '       pseudoclass is because Opera handles the rendering' +
            '       involved in the class-swap very poorly and IE6 ' +
            '       (and below) only implements pseudoclasses on the' +
            '       anchor tag.' +
            '*/' +
            '/* Active cells */' +
            'td.jacsCells:hover,' +
            'td.jacsCellsHover           {background-color:  #FFFF00;' +
                                         'cursor:            pointer;' +
                                         'color:             #000000;}' +
            '/* Day matching the input date */' +
            'td.jacsInputDate:hover,' +
            'td.jacsInputDateHover       {background-color:  #FFFF00;' +
                                         'cursor:            pointer;' +
                                         'color:             #000000;}' +
            '/* Weekend cells */' +
            'td.jacsCellsWeekend:hover,' +
            'td.jacsCellsWeekendHover    {background-color:  #FFFF00;' +
                                         'cursor:            pointer;' +
                                         'color:             #000000;}' +
            '/* Day outside the current month */' +
            'td.jacsCellsExMonth:hover,' +
            'td.jacsCellsExMonthHover    {background-color:  #FFFF00;' +
                                         'cursor:            pointer;' +
                                         'color:             #000000;}' +
            '/* Today selector */' +
            'td.jacsFoot:hover,' +
            'td.jacsFootHover            {color:             #FFFF00;' +
                                         'cursor:            pointer;' +
                                         'font-weight:       bold;}' +
            '/* Disabled cells */' +
            '/* Week Day */' +
            '/* Day matching the input date */' +
            'td.jacsInputDateDisabled    {background-color:  #999999;' +
                                         'color:             #000000;}' +
            'td.jacsCellsDisabled        {background-color:  #999999;' +
                                         'color:             #000000;}' +
            '/* Weekend Day */' +
            'td.jacsCellsWeekendDisabled {background-color:  #999999;' +
                                         'color:             #CC6666;}' +
            '/* Day outside the current month */' +
            'td.jacsCellsExMonthDisabled {background-color:  #999999;' +
                                         'color:             #666666;}' +
            'td.jacsFootDisabled         {background-color:  #6666CC;' +
                                         'color:             #FFFFFF;}' +
        '</style>');

     function calAttributes(cal)
        {switch (cal.id)
            {case 'EnterYourIDHere':

                // If you want to vary the attributes for a specific instance
                // of the calendar, replace 'EnterYourIDHere' (above) with the
                // ID that you have defined for that calendar then amend and
                // uncomment the block-commented section below (which is just
                // a copy of the default section below with all the
                // documentation comments removed).

                /*

                cal.zIndex                   = 1;
                cal.baseYear                 = dateNow.getFullYear()-10;
                cal.dropDownYears            = 20;
                cal.weekStart                = 1;
                cal.weekNumberBaseDay        = 4;
                cal.weekNumberDisplay        = false;

                try   {jacsSetLanguage(cal);}
                catch (exception)
                    {cal.today               = 'Today:';
                     cal.drag                = 'click here to drag';
                     cal.monthNames          = ['Jan','Feb','Mar','Apr','May','Jun',
                                                'Jul','Aug','Sep','Oct','Nov','Dec'];
                     cal.weekInits           = ['S','M','T','W','T','F','S'];
                     cal.invalidDateMsg      = 'The entered date is invalid.\n';
                     cal.outOfRangeMsg       = 'The entered date is out of range.';
                     cal.doesNotExistMsg     = 'The entered date does not exist.';
                     cal.invalidAlert        = ['Invalid date (',') ignored.'];
                     cal.dateSettingError    = ['Error ',' is not a Date object.'];
                     cal.rangeSettingError   = ['Error ',' should consist of two elements.'];
                    }

                cal.showInvalidDateMsg       = true;
                cal.showOutOfRangeMsg        = true;
                cal.showDoesNotExistMsg      = true;
                cal.showInvalidAlert         = true;
                cal.showDateSettingError     = true;
                cal.showRangeSettingError    = true;
                cal.delimiters               = ['/','-','.',':',',',' '];
                cal.dateDisplayFormat        = 'mm-dd-yy';
                cal.dateFormat               = 'MMM DD, YYYY';
                cal.strict                   = false;
                cal.dates                    = new Array();
                cal.dayCells                 = [true, true, true, true, true, true, true,
                                                true, true, true, true, true, true, true,
                                                true, true, true, true, true, true, true,
                                                true, true, true, true, true, true, true,
                                                true, true, true, true, true, true, true,
                                                true, true, true, true, true, true, true];
                cal.outOfRangeDisable        = true;
                cal.outOfMonthDisable        = false;
                cal.outOfMonthHide           = false;
                cal.formatTodayCell          = true;
                cal.todayCellBorderColour    = 'red';
                cal.allowDrag                = false;
                cal.onBlurMoveNext           = false;
                cal.clickToHide              = false;
                cal.xBase                    = 'L';    // L Left, M Middle, R Right  or integer pixel offset from left
                cal.yBase                    = 'B';    // T Top,  M Middle, B Bottom or integer pixel offset from top
                cal.xPosition                = 'L';    // L Left, M Middle, R Right  or integer pixel offset from left
                cal.yPosition                = 'T';    // T Top,  M Middle, B Bottom or integer pixel offset from top
                cal.seedDate                 = new Date();
                cal.fullInputDate            = false;
                cal.activeToday              = true;

                cal.monthSum                 = 0;
                cal.days                     = new Array();
                cal.dateReturned             = false;

                */

                break;
             default:

                // cal.zIndex controls how the pop-up calendar interacts with
                // the rest of the page.  It is usually adequate to leave it
                // as 1 (One) but I have made it available here to help anyone
                // who needs to alter the level in order to ensure that the
                // calendar displays correctly in relation to all other elements
                // on the page.

                cal.zIndex = 1;

                // Set the bounds for the calendar here...
                // If you want the year to roll forward you can use something
                // like this...
                //      var baseYear = dateNow.getFullYear()-5;
                // alternatively, hard code a date like this...
                //      var baseYear = 1990;

                cal.baseYear = dateNow.getFullYear()-100;

                // How many years do want to be valid and to show in the
                // drop-down list?

                cal.dropDownYears = 110;

                // weekStart determines the start of the week in the display
                // Set it to: 0 (Zero) for Sunday, 1 (One) for Monday etc..

                // Note:  Always start the weekInits array with your
                //        string for Sunday whatever weekStart (below)
                //        is set to.

                cal.weekStart = 1;

                // Week numbering rules are generally based on a day in the week
                // that determines the first week of the year.  ISO 8601 uses
                // Thursday (day four when Sunday is day zero).  You can alter
                // the base day here.

                // See http://www.cl.cam.ac.uk/~mgk25/iso-time.html
                // for more information

                cal.weekNumberBaseDay = 4;

                // The week start day for the display is taken as the week start
                // for week numbering.  This ensures that only one week number
                // applies to one line of the calendar table.
                // [ISO 8601 begins the week with Day 1 = Monday.]

                // If you want to see week numbering on the calendar, set
                // this to true.  If not, false.

                cal.weekNumberDisplay = false;

                // If the calendar is given a date that it can't parse a month
                // from, it will use a default month.  If the following attribute
                // is FALSE then the default month is month 6 (June), if set to
                // TRUE then the default will be the current month.

                cal.defaultToCurrentMonth = false;

                // All language-dependent settings can be made here...

                // If you wish to work in a single language (other than English)
                // then just replace the English below with your own text.

                // Using multiple languages:
                // In order to keep this script to a resonable size I have not
                // included multiple languages here.  However, you can set the language
                // fields in a function that you should name  jacsSetLanguage.  The script
                // will then use your languages. I have included all the translations
                // that have been sent to me in such a function on my demonstration
                // site at http://www.tarrget.info/calendar/jacsLanguages.js.

                try   {jacsSetLanguage(cal);}
                catch (exception)
                    {// English
                     cal.language            = 'en';
                     cal.today               = 'Today:';
                     cal.drag                = 'click here to drag';
                     cal.monthNames          = ['Jan','Feb','Mar','Apr','May','Jun',
                                                'Jul','Aug','Sep','Oct','Nov','Dec'];
                     cal.weekInits           = ['S','M','T','W','T','F','S'];
                     cal.invalidDateMsg      = 'The entered date is invalid.\n';
                     cal.outOfRangeMsg       = 'The entered date is out of range.';
                     cal.doesNotExistMsg     = 'The entered date does not exist.';
                     cal.invalidAlert        = ['Invalid date (',') ignored.'];
                     cal.dateSettingError    = ['Error ',' is not a Date object.'];
                     cal.rangeSettingError   = ['Error ',' should consist of two elements.'];
                    }

                // Each of the calendar's alert message types can be disabled
                // independently here.

                cal.showInvalidDateMsg      = true;
                cal.showOutOfRangeMsg       = true;
                cal.showDoesNotExistMsg     = true;
                cal.showInvalidAlert        = true;
                cal.showDateSettingError    = true;
                cal.showRangeSettingError   = true;

                // Set the allowed input date delimiters here...
                // E.g. To set the rising slash, hyphen, full-stop (aka stop or
                //      point), colon, comma and space as delimiters use
                //              var cal.delimiters   = ['/','-','.',':',',',' '];

                cal.delimiters = ['/','-','.',':',',',' '];

                // Set the format for the displayed 'Today' date and for the
                // output date here.
                //
                // The format is described using delimiters of your choice (as
                // set in cal.delimiters above) and case insensitive letters
                // D, M and Y.
                //
                // NOTE: If no delimiters are input then the date output format is used
                //       to parse the value.  This allows less flexiblility in the input
                //       value than using delimiters but an accurately entered date
                //       remains parsable.

                // Displayed "Today" date format

                cal.dateDisplayFormat = 'mm/dd/yyyy';     // e.g. 'MMM-DD-YYYY' for the US

                // Output date format

                cal.dateFormat  = 'YYYY-mm-dd'; // e.g. 'MMM-DD-YYYY' for the US
                // Note: The delimiters used should be in cal.delimiters.

                // Personally I like the fact that entering 31-Sep-2005 (a date
                // that doesn't exist) displays 1-Oct-2005, however you may want
                // that to be an error.  If so, set cal.strict = true.  That
                // will cause an error message to display and the selected month
                // is displayed without a selected day. Thanks to Brad Allan for
                // his feedback prompting this feature.

                cal.strict = false;

                // Choose whether the dates and days you specify in cal.dates
                // and as parameters to the JACS.show call are enabled (with all
                // other dates disabled) or disabled (with all other dates enabled).

                cal.valuesEnabled = false;

                // If you wish to set any displayed day, e.g. Every Monday,
                // you can do it using the following array.  The array elements
                // match the displayed cells.
                //
                // With the valuesEnabled attribute FALSE you could put something
                // like the following in your calling page to disable all weekend
                // days;
                //
                //  for (var i=0;i<<<calendar object>>.dayCells.length;i++)
                //      {if (i%7%6==0) <<calendar object>>.dayCells[i] = false;}
                //
                // The above approach will allow you to select days of the week
                // for the whole of your page easily.  If you need to set different
                // selected days for a number of date input fields on your page
                // there is an easier way: You can pass optional arguments to
                // JACS.show. The syntax is described at the top of this script in
                // the section:
                //    "How to use the Calendar once it is defined for your page:"
                //
                // It is possible to use these two approaches in combination.

                cal.dayCells = [true, true, true, true, true, true, true,
                                true, true, true, true, true, true, true,
                                true, true, true, true, true, true, true,
                                true, true, true, true, true, true, true,
                                true, true, true, true, true, true, true,
                                true, true, true, true, true, true, true];

                // You can specify any date (e.g. 24-Jan-2006 or Today) by creating
                // an element of the array cal.dates as a date object with the
                // value you want to handle.  Date ranges can be handled by placing
                // an array of two values (Start and End) into an element of this array.
                //
                // Use cal.valuesEnabled to determine whether any specified dates
                // are treated as the only enabled ones or the only disabled ones.

                cal.dates = new Array();

                // e.g. To specify 10-Dec-2005:
                //          cal.dates[0] = new Date(2005,11,10);
                //
                //      Or a range from 2004-Dec-25 to 2005-Jan-01:
                //
                //          cal.dates[1] =
                //              [new Date(2004,11,25),new Date(2005,0,1)];
                //
                //      The following will specify all calendar dates up to
                //      yesterday:
                //
                //          cal.dates[2] =
                //              [new Date(cal.baseYear,0,1),
                //               new Date(dateNow.getFullYear(),
                //                        dateNow.getMonth(),
                //                        dateNow.getDate()-1)];
                //
                // Remember that Javascript months are zero-based.

                // Dates that are out of the specified range can be displayed at
                // the start of the very first month and end of the very last.
                // Set outOfRangeDisable = true to disable these dates
                // (or false to allow their selection).

                cal.outOfRangeDisable = true;

                // Dates that are out of the displayed month are shown at the start
                // (unless the month starts on the first day of the week) and end of
                // each month. Set outOfMonthDisable = true to disable these dates
                // (or false to allow their selection). Set outOfMonthHide = true
                // to hide these dates (or false to make them visible).

                cal.outOfMonthDisable = false;
                cal.outOfMonthHide    = false;

                // If you want a special format for the cell that contains the current day
                // set this to true.  This sets a thin border around the cell in the colour
                // set by cal.todayCellBorderColour.

                cal.formatTodayCell = true;
                cal.todayCellBorderColour = '#f00'; // red

                // You can allow the calendar to be dragged around the screen by
                // using the setting allowDrag = true.
                // I can't say I recommend it because of the danger of the user
                // forgetting which date field the calendar will update when
                // there are multiple date fields on a page.

                cal.allowDrag = false;

                // It is not easy to code HTML events to make the focus move
                // automatically on to the next element in the tab order so
                // here is a parameter you can set that will tell the script
                // to do it for you.  NOTE: The script may have to build a list
                // of all the page's elements in tabIndex order to achieve this
                // so there can be an overhead to using this feature.

                cal.onBlurMoveNext = false;

                // You can allow a click on the calendar to close dynamic
                // calendars by setting clickToHide = true.  If set to false
                // the script will hide a dynamic calendar when a date is
                // selected or the main page is clicked.

                cal.clickToHide = false;

                // Dynamic calendar positioning is relative to the return value
                // element. The script is supplied with the parameters below
                // setting the calendar's top left corner to appear at the
                // return element's bottom left corner.

                cal.xBase     = 'L';
                cal.yBase     = 'B';
                cal.xPosition = 'L';
                cal.yPosition = 'T';

                // For the horizontal (X) parameters, xBase and xPosition,
                // the accepted values are;  L - Left
                //                           M - Middle
                //                           R - Right
                //                      or  nn - integer pixel offset from left +/-
                //
                // For the vertical (Y) parameters, yBase and yPosition,
                // the accepted values are;  T - Top
                //                           M - Middle
                //                           B - Bottom
                //                      or  nn - integer pixel offset from top +/-
                //

                // Do not set the value of this calendar attribute.  It is used
                // to tell you whether a date has been selected or not when
                // using the JACS.next feature to trigger a function after the
                // calendar is used.
                // dateReturned is False unless the user has clicked on an
                // active date cell or the value for "Today", in which case
                // it is True.

                cal.dateReturned  = false;

                // Finally: The following attributes are used in calendar
                //          functions.  You need do nothing with them here.

                cal.seedDate      = new Date();
                cal.fullInputDate = false;
                cal.activeToday   = true;
                cal.monthSum      = 0;
                cal.days          = new Array();
                cal.arrOnNext     = new Array();
                cal.triggerEle;
                cal.targetEle;
            }
        };



     // Format a date into the required pattern

     Date.prototype.jacsFormat =
        function(format,monthNames)
            {var charCount = 0,
                 codeChar  = '',
                 result    = '';

             for (var i=0;i<=format.length;i++)
                {if (i<format.length && format.charAt(i)==codeChar)
                        {// If we haven't hit the end of the string and
                         // the format string character is the same as
                         // the previous one, just clock up one to the
                         // length of the current element definition
                         charCount++;
                        }
                 else   {switch (codeChar)
                            {case 'y': case 'Y':
                                result += (this.getFullYear()%Math.pow(10,charCount)).toString().jacsPadLeft(charCount);
                                break;
                             case 'm': case 'M':
                                // If we find an M, check the number of them to
                                // determine whether to get the month number or
                                // the month name.
                                result += (charCount<3)
                                            ?(this.getMonth()+1).toString().jacsPadLeft(charCount)
                                            :monthNames[this.getMonth()];
                                break;
                             case 'd': case 'D':
                                // If we find a D, get the date and format it
                                result += this.getDate().toString().jacsPadLeft(charCount);
                                break;
                             default:
                                // Copy any unrecognised characters across
                                while (charCount-->0) {result += codeChar;}
                            }

                         if (i<format.length)
                            {// Store the character we have just worked on
                             codeChar  = format.charAt(i);
                             charCount = 1;
                            }
                        }
                }
             return result;
            };

     // Left pad zeroes

     String.prototype.jacsPadLeft =
        function(padToLength)
            {var result = '';
             for (var i=0;i<(padToLength-this.length);i++) {result += '0'};
             return (result+this);
            };

     // Set up a closure so that any next function can be triggered after the calendar
     // has been closed AND that function can take arguments.

     Function.prototype.jacsRunNext =
        function()  {var func = this, args = arguments[0];
                     func.JACSid = arguments[1];
                     return function() {return func.apply(this, args);};
                    };


     if (document.addEventListener)
          {window.addEventListener(  'load',jacsLoader,true);}
     else {window.attachEvent     ('onload',jacsLoader);}

     function jacsLoader()
        {// Define document level event to hide the calendar on click.

         if (document.addEventListener)
              {document.addEventListener('click',hide, false);}
         else {document.attachEvent('onclick',hide);}

         // Create an onBeforeUnload event to handle IE memory leaks.

         if (getEl('jacsIElt7')) {window.attachEvent('onbeforeunload',defeatLeaks);}

         function defeatLeaks()
            {for (var i=0;i<cals.length;i++)
                {// Display the week number column (header and row numbers).
                 getEl(cals[i]+'Week_').style.display='';

                 for (var j=0;j<6;j++) {getEl(cals[i]+'Week_'+j).style.display='';}

                 // Set events to null.

                 getEl(cals[i]+'Foot').onclick     = null;
                 getEl(cals[i]+'Foot').onmouseover = null;
                 getEl(cals[i]+'Foot').onmouseout  = null;

                 var cal    = getEl(cals[i]),
                     cells  = getEl(cals[i]+'Cells').childNodes;

                 for (var j=0;j<cells.length;j++)
                    {var rows = cells[j].childNodes;
                     for (var k=1;k<rows.length;k++)
                        {rows[k].onclick     = null;
                         rows[k].onmouseover = null;
                         rows[k].onmouseout  = null;
                        }
                    }

                 // Set calendar's leaky custom attributes to null.

                 cal.arrOnNext  = null;
                 cal.onNext     = null;
                 cal.ele        = null;
                }
            };
        };


     function showMonth(bias,calId)
        {// Set the selectable Month and Year
         // May be called: from the left and right arrows
         //                  (shift month -1 and +1 respectively)
         //                from the month selection list
         //                from the year selection list
         //                from the showCal routine
         //                  (which initiates the display).
         var cal       = getEl(calId),
             showDate  = new Date(Date.parse(new Date().toDateString())),
             startDate = new Date();

         // Set the time to the middle of the day so that the handful of
         // regions that have daylight saving shifts that change the day
         // of the month (i.e. turn the clock back at midnight or forward
         // at 23:00) do not mess up the date display in the calendar.

         showDate.setHours(12);

         selYears  = getEl(calId+'Years');
         selMonths = getEl(calId+'Months');

         if ( selYears.options.selectedIndex>-1) {cal.monthSum =12*(selYears.options.selectedIndex)+bias;}
         if (selMonths.options.selectedIndex>-1) {cal.monthSum+=selMonths.options.selectedIndex;}

         showDate.setFullYear(cal.baseYear+Math.floor(cal.monthSum/12),(cal.monthSum%12),1);

         // If the Week numbers are displayed, shift the week day names to the right.

         getEl(calId+'Week_').style.display = (cal.weekNumberDisplay)?'':'none';

         // Opera has a bug with setting the selected index.
         // It requires the following work-around to force SELECTs to display correctly.
         if (window.opera)
            {selMonths.style.display = 'inherit';
              selYears.style.display = 'inherit';
            }

         tmp = (12*parseInt((showDate.getFullYear()-cal.baseYear),10)) + parseInt(showDate.getMonth(),10);

         if (tmp > -1 && tmp < (12*cal.dropDownYears))
            {selYears.options.selectedIndex  = Math.floor(cal.monthSum/12);
             selMonths.options.selectedIndex = (cal.monthSum%12);

             curMonth = showDate.getMonth();

             showDate.setDate((((showDate.getDay()-cal.weekStart)<0)?-6:1)+cal.weekStart-showDate.getDay());

             var compareDateValue = new Date(showDate.getFullYear(),showDate.getMonth(),showDate.getDate()).valueOf();

             startDate = new Date(showDate);

             if (getEl(calId+'Foot'))
                {var foot = getEl(calId+'Foot');

                 function footOutput() {setOutput(dateNow,calId);};

                 if (cal.dates.length==0)
                    {if (cal.activeToday)
                        {foot.onclick   = footOutput;
                         foot.className = 'jacsFoot';

                         if (getEl('jacsIE'))
                            {foot.onmouseover = changeClass;
                             foot.onmouseout  = changeClass;
                            }

                         if (document.removeEventListener)
                                {foot.removeEventListener('click',stopPropagation,false);}
                         else   {foot.detachEvent(      'onclick',stopPropagation);}
                        }
                     else
                        {foot.onclick   = null;
                         foot.className = 'jacsFootDisabled';

                         if (getEl('jacsIE'))
                            {foot.onmouseover = null;
                             foot.onmouseout  = null;
                            }

                         if (document.addEventListener)
                                {foot.addEventListener('click',stopPropagation,false);}
                         else   {foot.attachEvent(   'onclick',stopPropagation);}
                        }
                    }
                 else
                    {for (var k=0;k<cal.dates.length;k++)
                        {if (!cal.activeToday ||
                             (typeof cal.dates[k]=='object' &&
                                  ((cal.dates[k].constructor==Date  && dateNow.valueOf() == cal.dates[k].valueOf()) ||
                                   (cal.dates[k].constructor==Array && dateNow.valueOf() >= cal.dates[k][0].valueOf() &&
                                                                       dateNow.valueOf() <= cal.dates[k][1].valueOf()
                                   )
                                  )
                             )
                            )
                            {foot.onclick   = (cal.valuesEnabled)?footOutput:null;
                             foot.className = (cal.valuesEnabled)?'jacsFoot':'jacsFootDisabled';

                             if (getEl('jacsIE'))
                                {foot.onmouseover = (cal.valuesEnabled)?changeClass:null;
                                 foot.onmouseout  = (cal.valuesEnabled)?changeClass:null;
                                }

                             if (cal.valuesEnabled)
                                {if (document.removeEventListener) {foot.removeEventListener('click',stopPropagation,false);}
                                 else                              {foot.detachEvent(      'onclick',stopPropagation);}
                                }
                             else
                                {if (document.addEventListener) {foot.addEventListener('click',stopPropagation,false);}
                                 else                           {foot.attachEvent(   'onclick',stopPropagation);}
                                }

                             break;
                            }
                         else
                            {foot.onclick   = (cal.valuesEnabled)?null:footOutput;
                             foot.className = (cal.valuesEnabled)?'jacsFootDisabled':'jacsFoot';

                             if (getEl('jacsIE'))
                                {foot.onmouseover = (cal.valuesEnabled)?null:changeClass;
                                 foot.onmouseout  = (cal.valuesEnabled)?null:changeClass;
                                }

                             if (cal.valuesEnabled)
                                {if (document.addEventListener) {foot.addEventListener('click',stopPropagation,false);}
                                 else                           {foot.attachEvent(   'onclick',stopPropagation);}
                                }
                             else
                                {if (document.removeEventListener) {foot.removeEventListener('click',stopPropagation,false);}
                                 else                              {foot.detachEvent(      'onclick',stopPropagation);}
                                }
                            }
                        }
                    }
                }

             function setOutput(outputDate,calId)
                {var cal = getEl(calId);

                 if (typeof cal.targetEle.value == 'undefined')
                        {cal.triggerEle.textNode.replaceData(0,cal.triggerEle.len,outputDate.jacsFormat(cal.dateFormat,cal.monthNames));}
                 else   {cal.ele.value = outputDate.jacsFormat(cal.dateFormat,cal.monthNames);}

                 cal.dateReturned = true;

                 if (cal.dynamic) {hide(calId);}
                 else {if (typeof cal.onNext!='undefined' && cal.onNext!=null) {cal.onNext();}
                       JACS.show(cal.ele,cal.id,cal.days);
                      }

                 if (cal.onBlurMoveNext)
                    {// if the target element has a tabIndex look for tabIndex+1
                     // if that exists then set the focus to it

                     var tagsToFind = 'INPUT;A;SELECT;TEXTAREA;BUTTON;AREA;OBJECT',
                         found      = false;

                     if (cal.ele.tabIndex>0)
                        {var tags = tagsToFind.split(';');

                         tagsOuterLoop:
                         for (var i=0;tags.length;i++)
                            {elementsByTag = document.getElementsByTagName(tags[i]);

                             for (var j=0;j<elementsByTag.length;j++)
                                {if (elementsByTag[j].tabIndex==(cal.ele.tabIndex+1) && !elementsByTag[j].disabled &&
                                     elementsByTag[j].type!='hidden' && elementsByTag[j].style.display!='none' &&
                                     elementsByTag[j].style.visibility!='hidden')
                                    {elementsByTag[j].focus();
                                     found = true;
                                     break tagsOuterLoop;
                                    }
                                }
                            }
                        }

                     // else do the full search to find the next element

                     if (!found)
                        {// find element tabIndices
                         function orderElements()
                            {var tabOrder  = new Array,
                                 unordered = new Array;

                             function elementArrays(ele)
                                {for (var i=0;i<ele.childNodes.length;i++)
                                    {var tempEle = ele.childNodes[i];
                                     if (tempEle.nodeType==1 && tempEle.style.display!='none' &&
                                         !tempEle.disabled   && tempEle.type!='hidden' &&
                                         tempEle.style.visibility!='hidden')
                                        {if (tagsToFind.indexOf(tempEle.tagName)>-1)
                                            {if (tempEle.tabIndex>0) {tabOrder[tempEle.tabIndex]  = tempEle}
                                             else                    {unordered[unordered.length] = tempEle}
                                            }
                                         elementArrays(tempEle);
                                        }
                                    }
                                };

                             elementArrays(document.body);

                             while (tabOrder.length>0 && tabOrder[0]==null) {tabOrder.shift();}

                             return tabOrder.concat(unordered);
                            };

                         var tabSequenced = orderElements();

                         // find the current element in tabIndex ordered array
                         // and set focus to the next element (or the first if
                         // the current is the last)

                         for (var i=0;i<tabSequenced.length;i++)
                            {if (tabSequenced[i]==cal.targetEle)
                                {if (i<(tabSequenced.length-1)) {tabSequenced[i+1].focus()}
                                 else                           {tabSequenced[0].focus()}
                                 break;
                                }
                            }
                        }
                    }
                 else
                    {if (!cal.targetEle.disabled      && cal.targetEle.style.display!='none' &&
                         cal.targetEle.type!='hidden' && cal.targetEle.style.visibility!='hidden')
                        {cal.targetEle.focus();}
                    }
                };

             function changeClass(evt)
                {var ele = eventTrigger(evt);

                 if (ele.nodeType==3) {ele=ele.parentNode;}

                 if (((evt)?evt.type:event.type)=='mouseover')
                    {switch (ele.className)
                        {case 'jacsCells':
                            ele.className = 'jacsCellsHover';        break;
                         case 'jacsCellsExMonth':
                            ele.className = 'jacsCellsExMonthHover'; break;
                         case 'jacsCellsWeekend':
                            ele.className = 'jacsCellsWeekendHover'; break;
                         case 'jacsFoot':
                            ele.className = 'jacsFootHover';         break;
                         case 'jacsInputDate':
                            ele.className = 'jacsInputDateHover';
                        }
                    }
                 else
                    {switch (ele.className)
                        {case 'jacsCellsHover':
                            ele.className = 'jacsCells';             break;
                         case 'jacsCellsExMonthHover':
                            ele.className = 'jacsCellsExMonth';      break;
                         case 'jacsCellsWeekendHover':
                            ele.className = 'jacsCellsWeekend';      break;
                         case 'jacsFootHover':
                            ele.className = 'jacsFoot';              break;
                         case 'jacsInputDateHover':
                            ele.className = 'jacsInputDate';
                        }
                    }
                 return true;
                };

             function eventTrigger(evt)
                {if (!evt) {evt = event;}
                 return evt.target||evt.srcElement;
                };

             function weekNumber(inDate)
                {// The base day in the week of the input date
                 var inDateWeekBase = new Date(inDate);

                 inDateWeekBase.setDate(inDateWeekBase.getDate() - inDateWeekBase.getDay() + cal.weekNumberBaseDay +
                                            ((inDate.getDay() > cal.weekNumberBaseDay)?7:0));

                 // The first Base Day in the year
                 var firstBaseDay = new Date(inDateWeekBase.getFullYear(),0,1);

                 firstBaseDay.setDate(firstBaseDay.getDate() - firstBaseDay.getDay() + cal.weekNumberBaseDay);

                 if (firstBaseDay<new Date(inDateWeekBase.getFullYear(),0,1))
                    {firstBaseDay.setDate(firstBaseDay.getDate()+7);}

                 // Start of Week 01
                 var startWeekOne = new Date(firstBaseDay - cal.weekNumberBaseDay + inDate.getDay());

                 if (startWeekOne>firstBaseDay) {startWeekOne.setDate(startWeekOne.getDate()-7);}

                 // Subtract the date of the current week from the date of the first week of the year to
                 // get the number of weeks in milliseconds.  Divide by the number of milliseconds in a
                 // week then round to no decimals in order to remove the effect of daylight saving.  Add
                 // one to make the first week, week 1.  Place a string zero on the front so that week
                 // numbers are zero filled.

                 var weekNo = '0'+(Math.round((inDateWeekBase - firstBaseDay)/604800000,0)+1);

                 // Return the last two characters in the week number string

                 return weekNo.substring(weekNo.length-2,weekNo.length);
                };

             // walk the DOM to display the dates.

             var cells = getEl(calId+'Cells').childNodes;

             for (var i=0;i<cells.length;i++)
                {var rows = cells[i];
                 if (rows.nodeType==1 && rows.tagName=='TR')
                    {tmpEl = rows.childNodes[0];
                     if (cal.weekNumberDisplay)
                          {//Calculate the week number using showDate
                           tmpEl.innerHTML = weekNumber(showDate);
                           tmpEl.style.borderColor =
                               (tmpEl.currentStyle)
                                    ?tmpEl.currentStyle['backgroundColor']
                                    :(document.defaultView.getComputedStyle)
                                        ?document.defaultView.getComputedStyle(tmpEl,null).backgroundColor
                                        :'';
                           tmpEl.style.display = '';
                          }
                     else  {tmpEl.style.display='none';}

                     for (var j=1;j<rows.childNodes.length;j++)
                        {var cols = rows.childNodes[j];
                         if (cols.nodeType==1 && cols.tagName=='TD')
                            {rows.childNodes[j].innerHTML = showDate.getDate();

                             var cell = rows.childNodes[j];

                             cell.style.visibility = (cal.outOfMonthHide &&
                                                      (showDate < (new Date(showDate.getFullYear(),curMonth,1,showDate.getHours())) ||
                                                       showDate > (new Date(showDate.getFullYear(),curMonth+1,0,showDate.getHours()))
                                                      )
                                                     )?'hidden':'inherit';

                             // Disable if the outOfRangeDisable option has been set and the current date
                             // is out of range or the cal.valuesEnabled option is true.
                             var disabled = cal.valuesEnabled;

                             if ((cal.outOfRangeDisable && (showDate < (new Date(cal.baseYear,0,1,12)) ||
                                                            showDate > (new Date(cal.baseYear+cal.dropDownYears,0,0,12))
                                                           )
                                 ) ||
                                 (cal.outOfMonthDisable && (showDate < (new Date(showDate.getFullYear(),curMonth,1,showDate.getHours())) ||
                                                            showDate > (new Date(showDate.getFullYear(),curMonth+1,0,showDate.getHours()))
                                                           )
                                 )
                                ) {disabled = true;}
                             else
                                {if ((cal.days.join().search(((j-1+(7*(i*cells.length/6))+cal.weekStart)%7))>-1) ||
                                      !cal.dayCells[j-1+(7*((i*cells.length)/6))]
                                    )   {disabled = !cal.valuesEnabled;} // Set (Disable or Enable) if the day is passed as a parameter of JACS.show
                                 else   {for (var k=0;k<cal.dates.length;k++)
                                            {if (typeof cal.dates[k]=='object' &&
                                                 ((cal.dates[k].constructor==Date  && compareDateValue == cal.dates[k].valueOf()) ||
                                                  (cal.dates[k].constructor==Array && compareDateValue >= cal.dates[k][0].valueOf() &&
                                                                                      compareDateValue <= cal.dates[k][1].valueOf()
                                                  )
                                                 )
                                                )
                                                {disabled = !cal.valuesEnabled;
                                                 break;
                                                }
                                            }
                                        }
                                }

                             if (disabled)
                                {rows.childNodes[j].onclick = null;

                                 if (getEl('jacsIE'))
                                    {rows.childNodes[j].onmouseover = null;
                                     rows.childNodes[j].onmouseout  = null;
                                    }

                                 cell.className=
                                    (showDate.getMonth()!=curMonth)
                                        ?'jacsCellsExMonthDisabled'
                                        :(cal.fullInputDate &&
                                          compareDateValue==
                                          cal.seedDate.valueOf())
                                            ?'jacsInputDateDisabled'
                                            :(showDate.getDay()%6==0)
                                                ?'jacsCellsWeekendDisabled'
                                                :'jacsCellsDisabled';

                                 cell.style.borderColor =
                                     (cal.formatTodayCell && showDate.toDateString()==dateNow.toDateString())
                                        ?cal.todayCellBorderColour
                                        :(cell.currentStyle)
                                            ?cell.currentStyle['backgroundColor']
                                            :(document.defaultView.getComputedStyle)
                                                ?document.defaultView.getComputedStyle(cell,null).backgroundColor
                                                :'';
                                }
                             else
                                {function cellOutput(evt)
                                    {var ele = eventTrigger(evt),
                                         outputDate = new Date(startDate);

                                     if (ele.nodeType==3) ele=ele.parentNode;

                                     outputDate.setDate(startDate.getDate() +
                                        parseInt(ele.id.substr(calId.length+5),10));

                                     setOutput(outputDate,calId);
                                    };

                                 rows.childNodes[j].onclick=cellOutput;

                                 if (getEl('jacsIE'))
                                    {rows.childNodes[j].onmouseover = changeClass;
                                     rows.childNodes[j].onmouseout  = changeClass;
                                    }

                                 cell.className=
                                     (showDate.getMonth()!=curMonth)
                                        ?'jacsCellsExMonth'
                                        :(cal.fullInputDate &&
                                          compareDateValue==
                                          cal.seedDate.valueOf())
                                            ?'jacsInputDate'
                                            :(showDate.getDay()%6==0)
                                                ?'jacsCellsWeekend'
                                                :'jacsCells';

                                 cell.style.borderColor =
                                     (cal.formatTodayCell && showDate.toDateString()==dateNow.toDateString())
                                        ?cal.todayCellBorderColour
                                        :(cell.currentStyle)
                                            ?cell.currentStyle['backgroundColor']
                                            :(document.defaultView.getComputedStyle)
                                                ?document.defaultView.getComputedStyle(cell,null).backgroundColor
                                                :'';
                               }

                             showDate.setDate(showDate.getDate()+1);
                             compareDateValue = new Date(showDate.getFullYear(),
                                                         showDate.getMonth(),
                                                         showDate.getDate()).valueOf();
                            }
                        }
                    }
                }
            }

         // Opera has a bug with setting the selected index.
         // It requires the following work-around to force SELECTs to display correctly.
         // Also Opera's poor dynamic rendering prior to 9.5 requires
         // the visibility to be reset to prevent garbage in the calendar
         // when the displayed month is changed.
         if (window.opera)
            {selMonths.style.display = 'inline';
              selYears.style.display = 'inline';
             cal.style.visibility = 'hidden';
             cal.style.visibility = 'inherit';
            }
        };

     function hide(instanceID)
        {if (typeof instanceID=='object')
                {for (var i=0;i<cals.length;i++) {hideOne(cals[i]);}}
         else   {hideOne(instanceID);}

         function hideOne(id)
            {cal = getEl(id);

             if (cal.dynamic)
                {cal.style.visibility = 'hidden';
                 getEl(id+'Iframe').style.visibility='hidden';
                 doNext(cal);
                }
            };
        };

     function doNext(cal)
        {if (cal.arrOnNext.length > 0)
             {cal.onNext = cal.arrOnNext.shift();
              cal.onNext();
              // Explicit null set to prevent closure causing memory leak
              cal.onNext = null;
             }
        };

     function stopPropagation(evt)
       {if (evt.stopPropagation)
             {if (evt.target!=evt.currentTarget) {evt.stopPropagation(); evt.preventDefault();}}
        else {evt.cancelBubble = true;}
       };


     return {show: function(ele)
                {// Check the type of any additional parameters.
                 // The optional string parameter is a calendar ID,
                 // Take any remaining parameters as day numbers to be handled
                 // (enabled/disabled) according to the setting of the
                 // calendar's  valuesEnabled  attribute.
                 // 0 = Sunday through to 6 = Saturday.

                 if (typeof arguments[1]=='object')
                    {var dynamic = true;

                     if (typeof arguments[2]=='string')
                            {var calId = arguments[2], min = 3;}
                     else   {var calId = 'jacs',       min = 2;}

                     // Stop the click event that opens the calendar
                     // from bubbling up to the document-level event
                     // handler that hides it!

                     var event = arguments[1];
                     if (!event) {event = window.event;}
                     var sourceEle = (event.target)?event.target:event.srcElement;
                     if (event.stopPropagation) {event.stopPropagation();}
                     else                       {event.cancelBubble = true;}
                    }
                 else
                    {var sourceEle = ele, dynamic = false;

                     if (typeof arguments[1]=='string')
                            {var calId = arguments[1], min = 2;}
                     else   {var calId = 'jacs',       min = 1;}
                    }

                 // Add an event to the return element.
                 // This helps the script to support tab sequences.

                 if (document.addEventListener)
                        {ele.addEventListener('keydown',hideOnTab,false);}
                 else   {ele.attachEvent('onkeydown',hideOnTab);}

                 function hideOnTab(evt)
                    {if (!evt) {var evt = window.event;}
                     if ((evt.keyCode||evt.which)==9) {hide(calId);}
                    };

                 // Create the calendar structure. One is enough unless you want more
                 // than one calendar visible on the page at one time.  If you DO need
                 // more, you can create as many as you like but each must have a unique
                 // ID.

                 // The first parameter of JACS.make is the ID of the calendar. The
                 // second is a boolean that determines whether the calendar is to be
                 // static on the page (assigned to a single input field and always
                 // visible) or dynamic (shown and hidden on events and can be assigned
                 // to any number of input fields).

                 if (!getEl(calId)) {JACS.make(calId,dynamic);}

                 cal = getEl(calId);

                 // If the calendar has been triggered using an onfocus event,
                 // and the script actively returns the focus to the target
                 // element (i.e. when cal.onBlurMoveNext = false), most browsers
                 // do not re-trigger the onfocus event but IE does. So we need
                 // to kill the event.

                 if (getEl('jacsIE') && event && cal.dateReturned && !cal.onBlurMoveNext)
                    {if (event.type == 'focus') {cal.dateReturned = false; return false;}}

                 if (cal.style.visibility != 'hidden' && cal.style.visibility != 'inherit') {doNext(cal);}

                 cal.triggerEle = sourceEle;

                 cal.dateReturned = false;
                 cal.activeToday  = true;

                 // Set enabled/disabled days

                 if (arguments.length==min) {cal.days.length=0;}
                 else {selectedDays = (typeof arguments[min]=='object')?arguments[min]:arguments;
                       for (var i=(min|0);i<selectedDays.length;i++)
                         {if (cal.days.join().indexOf(selectedDays[i])==-1) {cal.days.push(selectedDays[i]);}}
                      }

                 for (var i=0;i<cal.days.length;i++)
                    {if (dateNow.getDay()==cal.days[i]%7) {cal.activeToday = false; break;}}

                 //   If no value is preset then the seed date is
                 //      Today (when today is in range) OR
                 //      The middle of the date range.

                 cal.seedDate = dateNow;

                 // Find the date and Strip space characters from start and
                 // end of date input.

                 var dateValue = '';

                 if (ele.value) {dateValue = ele.value.replace(/^\s+/,'').replace(/\s+$/,'');}
                 else   {if (typeof ele.value == 'undefined')
                            {var childNodes = ele.childNodes;
                             for (var i=0;i<childNodes.length;i++)
                                {if (childNodes[i].nodeType == 3)
                                    {dateValue = childNodes[i].nodeValue.replace(/^\s+/,'').replace(/\s+$/,'');
                                     if (dateValue.length > 0)
                                        {cal.triggerEle.textNode = childNodes[i];
                                         cal.triggerEle.len      = childNodes[i].nodeValue.length;
                                         break;
                                        }
                                    }
                                }
                            }
                        }

                 // Set the year range

                 var yearOptions = getEl(calId+'Years').options;

                 if (yearOptions.length==0 || yearOptions[0].value!=cal.baseYear)
                    {yearOptions.length = 0;
                     for (var i=0;i<cal.dropDownYears;i++) {yearOptions[i] = new Option((cal.baseYear+i),(cal.baseYear+i));}
                    }

                 if (dateValue.length==0)
                    {// If no value is entered and today is within the range,
                     // use today's date, otherwise use the middle of the valid range.

                     cal.fullInputDate=false;

                     if ((new Date(cal.baseYear+cal.dropDownYears,0,0))<cal.seedDate ||
                         (new Date(cal.baseYear,0,1))                  >cal.seedDate
                        )
                        {cal.seedDate = new Date(cal.baseYear+Math.floor(cal.dropDownYears / 2), 5, 1);}
                    }
                 else
                    {function inputFormat()
                        {var seed = new Array(),
                             input = dateValue.split(new RegExp('[\\'+cal.delimiters.join('\\')+']+','g'));

                         // "Escape" all the user defined date delimiters above -
                         // several delimiters will need it and it does no harm for
                         // the others.

                         // Strip any empty array elements (caused by delimiters)
                         // from the beginning or end of the array. They will
                         // still appear in the output string if in the output
                         // format.

                         if (input[0]!=null)
                            {if (input[0].length==0)              {input.splice(0,1);}
                             if (input[input.length-1].length==0) {input.splice(input.length-1,1);}
                            }

                         cal.fullInputDate = false;

                         cal.dateFormat = cal.dateFormat.toUpperCase();

                         // List all the allowed letters in the date format
                         var template = ['D','M','Y'];

                         // Prepare the sequence of date input elements
                         var result = new Array();

                         for (var i=0;i<template.length;i++)
                            {if (cal.dateFormat.search(template[i])>-1)
                                {result[cal.dateFormat.search(template[i])] = template[i];}
                            }

                         cal.dateSequence = result.join('');

                         // Separate the elements of the date input
                         switch (input.length)
                            {case 1:
                                {// Year only entry or undelimited date format

                                 if (cal.dateFormat.indexOf('Y')>-1 &&
                                     input[0].length>cal.dateFormat.lastIndexOf('Y'))
                                    {seed[0] = parseInt(input[0].substring(cal.dateFormat.indexOf('Y'),
                                                                           cal.dateFormat.lastIndexOf('Y')+1),10);
                                    }
                                 else   {seed[0] = parseInt(input[0],10);}

                                 if (cal.dateFormat.indexOf('M')>-1 &&
                                     input[0].length>cal.dateFormat.lastIndexOf('M'))
                                    {seed[1] = input[0].substring(cal.dateFormat.indexOf('M'),
                                                                  cal.dateFormat.lastIndexOf('M')+1);
                                    }
                                 else   {seed[1] = cal.defaultToCurrentMonth?(dateNow.getMonth()+1).toString():'6';}

                                 if (cal.dateFormat.indexOf('D')>-1 &&
                                     input[0].length>cal.dateFormat.lastIndexOf('D'))
                                    {seed[2] = parseInt(input[0].substring(cal.dateFormat.indexOf('D'),
                                                                           cal.dateFormat.lastIndexOf('D')+1),10);
                                    }
                                 else   {seed[2] = 1;}

                                 if (input[0].length==cal.dateFormat.length)    {cal.fullInputDate = true;}
                                 break;
                                }
                             case 2:
                                {// Year and Month entry
                                 seed[0] = parseInt(input[cal.dateSequence.replace(/D/i,'').search(/Y/i)],10);  // Year
                                 seed[1] = input[cal.dateSequence.replace(/D/i,'').search(/M/i)];               // Month
                                 seed[2] = 1;                                                                        // Day
                                 break;
                                }
                             case 3:
                                {// Day Month and Year entry
                                 seed[0] = parseInt(input[cal.dateSequence.search(/Y/i)],10);  // Year
                                 seed[1] = input[cal.dateSequence.search(/M/i)];               // Month
                                 seed[2] = parseInt(input[cal.dateSequence.search(/D/i)],10);  // Day
                                 cal.fullInputDate = true;
                                 break;
                                }
                             default:
                                {// A stuff-up has led to more than three elements in the date.
                                 seed[0] = 0;     // Year
                                 seed[1] = 0;     // Month
                                 seed[2] = 0;     // Day
                                }
                            }

                         // These regular expressions validate the input date format
                         // to the following rules;
                         //         Day   1-31 (optional zero on single digits)
                         //         Month 1-12 (optional zero on single digits)
                         //                     or case insensitive name
                         //         Year  One, Two or four digits

                         // Months names are as set in the language-dependent
                         // definitions and delimiters are set just below there

                         var expValDay    = new RegExp('^(0?[1-9]|[1-2][0-9]|3[0-1])$'),
                             expValMonth  = new RegExp('^(0?[1-9]|1[0-2]|'+cal.monthNames.join('|')+')$','i'),
                             expValYear   = new RegExp('^([0-9]{1,2}|[0-9]{4})$');

                         // Apply validation and report failures

                         if (expValYear.exec(seed[0]) ==null ||
                             expValMonth.exec(seed[1])==null ||
                             expValDay.exec(seed[2])  ==null
                            )
                            {if (cal.invalidDateMsg)
                                {alert(cal.invalidDateMsg + cal.invalidAlert[0] + dateValue + cal.invalidAlert[1]);}
                             seed[0] = cal.baseYear + Math.floor(cal.dropDownYears/2);                   // Year
                             seed[1] = cal.defaultToCurrentMonth?(dateNow.getMonth()+1).toString():'6';  // Month
                             seed[2] = 1;                                                                // Day
                             cal.fullInputDate = false;
                            }

                         // Return the Year  in seed[0]
                         //            Month in seed[1]
                         //            Day   in seed[2]

                         return seed;
                        };

                     // Parse the string into an array using the allowed delimiters

                     seedDate = inputFormat();

                     // So now we have the Year, Month and Day in an array.

                     //   If the year is one or two digits then the routine assumes a
                     //   year belongs in the 21st Century unless it is less than 50
                     //   in which case it assumes the 20th Century is intended.

                     if (seedDate[0]<100) {seedDate[0] += (seedDate[0]>50)?1900:2000;}

                     // Check whether the month is in digits or an abbreviation

                     if (seedDate[1].search(/\d+/)!=0)
                        {month = cal.monthNames.join('|').toUpperCase().search(seedDate[1].substr(0,3).toUpperCase());
                         seedDate[1] = Math.floor(month/4)+1;
                        }

                     cal.seedDate = new Date(seedDate[0],seedDate[1]-1,seedDate[2]);
                    }

                 // Test that we have arrived at a valid date

                 if (isNaN(cal.seedDate))
                    {if (cal.showInvalidDateMsg)
                        {alert(cal.invalidDateMsg + cal.invalidAlert[0] + dateValue + cal.invalidAlert[1]);}
                     cal.seedDate = new Date(cal.baseYear + Math.floor(cal.dropDownYears/2),5,1);
                     cal.fullInputDate = false;
                    }
                 else
                    {// Test that the date is within range,
                     // if not then set date to a sensible date in range.

                     if ((new Date(cal.baseYear,0,1))>cal.seedDate)
                        {if (cal.strict && cal.showOutOfRangeMsg) {alert(cal.outOfRangeMsg);}
                         cal.seedDate = new Date(cal.baseYear,0,1);
                         cal.fullInputDate=false;
                        }
                     else
                        {if ((new Date(cal.baseYear+cal.dropDownYears,0,0))<cal.seedDate)
                            {if (cal.strict && cal.showOutOfRangeMsg) {alert(cal.outOfRangeMsg);}
                             cal.seedDate = new Date(cal.baseYear + Math.floor(cal.dropDownYears),-1,1);
                             cal.fullInputDate=false;
                            }
                         else
                            {if (cal.strict && cal.fullInputDate &&
                                  (cal.seedDate.getDate()     !=seedDate[2] ||
                                   (cal.seedDate.getMonth()+1)!=seedDate[1] ||
                                   cal.seedDate.getFullYear() !=seedDate[0]
                                  )
                                )
                                {if (cal.showDoesNotExistMsg) {alert(cal.doesNotExistMsg);}
                                 cal.seedDate = new Date(cal.seedDate.getFullYear(),cal.seedDate.getMonth()-1,1);
                                 cal.fullInputDate=false;
                                }
                            }
                        }
                    }

                 // Test the chosen dates for validity
                 // Give error message if not valid

                 for (var i=0;i<cal.dates.length;i++)
                    {if (!((typeof cal.dates[i]=='object') && (cal.dates[i].constructor==Date)))
                        {if ((typeof cal.dates[i]=='object') && (cal.dates[i].constructor==Array))
                            {var pass = true;

                             if (cal.dates[i].length!=2)
                                {if (cal.showRangeSettingError)
                                    {alert(cal.rangeSettingError[0] + cal.dates[i] + cal.rangeSettingError[1]);}
                                 pass = false;
                                }
                             else
                                {for (var j=0;j<cal.dates[i].length;j++)
                                    if (!((typeof cal.dates[i][j]=='object') && (cal.dates[i][j].constructor==Date)))
                                        {if (cal.showRangeSettingError)
                                            {alert(cal.dateSettingError[0] + cal.dates[i][j] + cal.dateSettingError[1]);}
                                         pass = false;
                                        }
                                }

                             if (pass && (cal.dates[i][0]>cal.dates[i][1])) {cal.dates[i].reverse();}
                            }
                         else
                            {if (cal.showRangeSettingError)
                                {alert(cal.dateSettingError[0] + cal.dates[i] + cal.dateSettingError[1]);}
                            }
                        }
                    }

                 // Set language-dependent values

                 getEl(calId+'DragText').innerHTML = cal.drag;

                 var monthOptions = getEl(calId+'Months').options,  months = '';

                 if (monthOptions.length>0) {for (var i=0;i<monthOptions.length;i++) {months += monthOptions[i].value+',';}}

                 if (monthOptions.length==0 || (cal.monthNames.join()+',')!=months)
                    {monthOptions.length = 0;

                     if (cal.monthNames.length<monthOptions.length) {monthOptions.length = cal.monthNames.length;}

                     for (var i=0;i<cal.monthNames.length;i++)
                        {if (i>monthOptions.length-1)
                              {monthOptions[i] = new Option(cal.monthNames[i],cal.monthNames[i]);}
                         else {monthOptions[i].innerHTML = cal.monthNames[i];}
                        }
                    }

                 for (var i=0;i<cal.weekInits.length;i++)
                    {getEl(calId+'WeekInit'+i).innerHTML = cal.weekInits[(i+cal.weekStart)%cal.weekInits.length];}

                 if (getEl(calId+'Foot'))
                    {getEl(calId+'Foot').innerHTML = cal.today+' '+dateNow.jacsFormat(cal.dateDisplayFormat,cal.monthNames);}

                 // Calculate the number of months that the entered (or
                 // defaulted) month is after the start of the allowed
                 // date range.
                 cal.monthSum =  12*(cal.seedDate.getFullYear() - cal.baseYear) + cal.seedDate.getMonth();

                 // Set the drop down boxes.
                 getEl(calId+'Years').options.selectedIndex  = Math.floor(cal.monthSum/12);
                 getEl(calId+'Months').options.selectedIndex = (cal.monthSum%12);

                 getEl(calId).ele = ele;

                 // Display the month
                 showMonth(0,calId);

                 // Remember the Element
                 cal.targetEle = ele;

                 // Position the calendar box.
                 if (dynamic)
                    {// Check whether or not dragging is allowed and display drag handle if necessary
                     getEl(calId+'Drag').style.display = (cal.allowDrag)?'':'none';

                     var offsetTop  = parseInt(ele.offsetTop ,10),
                         offsetLeft = parseInt(ele.offsetLeft,10);

                     if (cal.xBase.length>0)
                            {if (isNaN(cal.xBase))
                                    {cal.xBase = cal.xBase.toUpperCase();
                                     offsetLeft += (cal.xBase=='R')
                                                        ?parseInt(ele.offsetWidth,10)
                                                        :(cal.xBase=='M')?Math.round(parseInt(ele.offsetWidth,10)/2):0;
                                    }
                             else   {offsetLeft += parseInt(cal.xBase,10);}
                            }

                     if (cal.yBase.length>0)
                            {if (isNaN(cal.yBase))
                                    {cal.yBase  = cal.yBase.toUpperCase();
                                     offsetTop += (cal.yBase=='B')
                                                    ?parseInt(ele.offsetHeight,10)
                                                    :(cal.yBase=='M')?Math.round(parseInt(ele.offsetHeight,10)/2):0;
                                    }
                             else   {offsetTop += parseInt(cal.yBase,10);}
                            }
                     else   {offsetTop += parseInt(ele.offsetHeight,10);}

                     if (cal.xPosition.length>0)
                            {if (isNaN(cal.xPosition))
                                    {cal.xPosition = cal.xPosition.toUpperCase();
                                     offsetLeft -= (cal.xPosition=='R')
                                                        ?parseInt(cal.offsetWidth,10)
                                                        :(cal.xPosition=='M')?Math.round(parseInt(cal.offsetWidth,10)/2):0;
                                    }
                             else   {offsetLeft += parseInt(cal.xPosition,10);}
                            }

                     if (cal.yPosition.length>0)
                            {if (isNaN(cal.yPosition))
                                    {cal.yPosition = cal.yPosition.toUpperCase();
                                     offsetTop -= (cal.yPosition=='B')
                                                        ?parseInt(cal.offsetHeight,10)
                                                        :(cal.yPosition=='M')?Math.round((parseInt(cal.offsetHeight,10))/2):0;
                                    }
                             else   {offsetTop += parseInt(cal.yPosition,10);}
                            }

                     // The object sniffing for Opera allows for the fact that Opera
                     // is the only major browser that correctly reports the position
                     // of an element in a scrollable DIV.  This is because IE and
                     // Firefox omit the DIV from the offsetParent tree.
                     if (!window.opera)
                         {while (ele.tagName!='BODY' && ele.tagName!='HTML')
                             {offsetTop  -= parseInt(ele.scrollTop, 10);
                              offsetLeft -= parseInt(ele.scrollLeft,10);
                              ele = ele.parentNode;
                             }
                          ele = cal.targetEle;
                         }

                     while (ele.tagName!='BODY' && ele.tagName!='HTML')
                        {ele = ele.offsetParent;
                         offsetTop  += parseInt(ele.offsetTop, 10);
                         offsetLeft += parseInt(ele.offsetLeft,10);
                        }

                     cal.style.top  = offsetTop +'px';
                     cal.style.left = offsetLeft+'px';

                     getEl(calId+'Iframe').style.top    = offsetTop +'px';
                     getEl(calId+'Iframe').style.left   = offsetLeft+'px';
                     getEl(calId+'Iframe').style.width  = (cal.offsetWidth-(getEl('jacsIE')?2:4))+'px';
                     getEl(calId+'Iframe').style.height = (cal.offsetHeight-(getEl('jacsIE')?2:4))+'px';
                     getEl(calId+'Iframe').style.visibility = 'inherit';
                    }

                 // Show it on the page
                 cal.style.visibility = 'inherit';
                },

             make: function (calId)
                {cals.push(calId);

                 var dynamic = (typeof arguments[1]=='boolean')?arguments[1]:true;

                 TABLEjacs           = document.createElement('table');
                 TABLEjacs.id        = calId;
                 TABLEjacs.dynamic   = dynamic;
                 TABLEjacs.className = (dynamic)?'jacs':'jacsStatic';

                 calAttributes(TABLEjacs);

                 if (dynamic) {TABLEjacs.style.zIndex = TABLEjacs.zIndex+1;}

                 function cancel(evt)
                    {if (TABLEjacs.clickToHide) {hide(calId);}
                     stopPropagation(evt);
                    };

                 TBODYjacs                 = document.createElement('tbody');
                 TRjacs1                   = document.createElement('tr');
                 TRjacs1.className         = 'jacs';
                 TDjacs1                   = document.createElement('td');
                 TDjacs1.className         = 'jacs';
                 TABLEjacsHead             = document.createElement('table');
                 TABLEjacsHead.id          = calId+'Head';
                 TABLEjacsHead.cellSpacing = '0';
                 TABLEjacsHead.cellPadding = '0';
                 TABLEjacsHead.className   = 'jacsHead';
                 TABLEjacsHead.width       = '100%';

                 TBODYjacsHead             = document.createElement('tbody');

                 TRjacsDrag                = document.createElement('tr');
                 TRjacsDrag.id             = calId+'Drag';
                 TRjacsDrag.style.display  = 'none';

                 TDjacsDrag                = document.createElement('td');
                 TDjacsDrag.className      = 'jacsDrag';
                 TDjacsDrag.colSpan        = '4';

                 function beginDrag(evt)
                    {var elToDrag = getEl(calId);

                     var deltaX    = evt.clientX,
                         deltaY    = evt.clientY,
                         offsetEle = elToDrag;

                     while (offsetEle.tagName!='BODY' && offsetEle.tagName!='HTML')
                        {deltaX   -= parseInt(offsetEle.offsetLeft,10);
                         deltaY   -= parseInt(offsetEle.offsetTop ,10);
                         offsetEle = offsetEle.offsetParent;
                        }

                     if (document.addEventListener)
                            {elToDrag.addEventListener('mousemove',moveHandler,true);
                             elToDrag.addEventListener('mouseup',    upHandler,true);
                            }
                     else   {elToDrag.attachEvent('onmousemove', moveHandler);
                             elToDrag.attachEvent('onmouseup',     upHandler);
                             elToDrag.setCapture();
                            }

                     stopPropagation(evt);

                     function moveHandler(evt)
                        {if (!evt) {evt = window.event;}

                         elToDrag.style.left = (evt.clientX-deltaX)+'px';
                         elToDrag.style.top  = (evt.clientY-deltaY)+'px';

                         getEl(calId+'Iframe').style.left = (evt.clientX-deltaX)+'px';
                         getEl(calId+'Iframe').style.top  = (evt.clientY-deltaY)+'px';

                         stopPropagation(evt);
                        };

                     function upHandler(evt)
                        {if (!evt) {evt = window.event;}

                         if (document.removeEventListener)
                                {elToDrag.removeEventListener('mousemove',moveHandler,true);
                                 elToDrag.removeEventListener(  'mouseup',  upHandler,true);
                                }
                         else   {elToDrag.detachEvent('onmouseup',    upHandler);
                                 elToDrag.detachEvent('onmousemove',moveHandler);
                                 elToDrag.releaseCapture();
                                }

                         stopPropagation(evt);
                        };
                    };

                 DIVjacsDragText           = document.createElement('div');
                 DIVjacsDragText.id        = calId+'DragText';

                 TRjacsHead                = document.createElement('tr');
                 TRjacsHead.className      = 'jacsHead';

                 TDjacsHead1               = document.createElement('td');
                 TDjacsHead1.className     = 'jacsHead';

                 INPUTjacsHead1            = document.createElement('input');
                 INPUTjacsHead1.className  = 'jacsHead';
                 INPUTjacsHead1.id         = calId+'HeadLeft';
                 INPUTjacsHead1.type       = 'button';
                 INPUTjacsHead1.tabIndex   = '-1';
                 INPUTjacsHead1.value      = '<';
                 INPUTjacsHead1.onclick    = function() {showMonth(-1,calId);}

                 TDjacsHead2               = document.createElement('td');
                 TDjacsHead2.className     = 'jacsHead';

                 SELECTjacsHead2           = document.createElement('select');
                 SELECTjacsHead2.className = 'jacsHead';
                 SELECTjacsHead2.id        = calId+'Months';
                 SELECTjacsHead2.tabIndex  = '-1';
                 SELECTjacsHead2.onchange  = function() {showMonth(0,calId);}

                 TDjacsHead3               = document.createElement('td');
                 TDjacsHead3.className     = 'jacsHead';

                 SELECTjacsHead3           = document.createElement('select');
                 SELECTjacsHead3.className = 'jacsHead';
                 SELECTjacsHead3.id        = calId+'Years';
                 SELECTjacsHead3.tabIndex  = '-1';
                 SELECTjacsHead3.onchange  = function() {showMonth(0,calId);}

                 TDjacsHead4               = document.createElement('td');
                 TDjacsHead4.className     = 'jacsHead';

                 INPUTjacsHead4            = document.createElement('input');
                 INPUTjacsHead4.className  = 'jacsHead';
                 INPUTjacsHead4.id         = calId+'HeadRight';
                 INPUTjacsHead4.type       = 'button';
                 INPUTjacsHead4.tabIndex   = '-1';
                 INPUTjacsHead4.value      = '>';
                 INPUTjacsHead4.onclick    = function() {showMonth(1,calId);}

                 TRjacs2                   = document.createElement('tr');
                 TRjacs2.className         = 'jacs';

                 TDjacs2                   = document.createElement('td');
                 TDjacs2.className         = 'jacs';

                 TABLEjacsCells            = document.createElement('table');
                 TABLEjacsCells.className  = 'jacsCells';
                 TABLEjacsCells.align      = 'center';
                 TABLEjacsCells.width      = '100%';

                 THEADjacsCells            = document.createElement('thead');
                 TRjacsCells               = document.createElement('tr');
                 TDjacsCells               = document.createElement('td');
                 TDjacsCells.className     = 'jacsWeekNumberHead';
                 TDjacsCells.id            = calId+'Week_';

                 TABLEjacs.appendChild(TBODYjacs);
                 TBODYjacs.appendChild(TRjacs1);
                    TRjacs1.appendChild(TDjacs1);
                        TDjacs1.appendChild(TABLEjacsHead);
                            TABLEjacsHead.appendChild(TBODYjacsHead);
                                 TBODYjacsHead.appendChild(TRjacsDrag);
                                    TRjacsDrag.appendChild(TDjacsDrag);
                                        TDjacsDrag.appendChild(DIVjacsDragText);
                                 TBODYjacsHead.appendChild(TRjacsHead);
                                    TRjacsHead.appendChild(TDjacsHead1);
                                        TDjacsHead1.appendChild(INPUTjacsHead1);
                                    TRjacsHead.appendChild(TDjacsHead2);
                                        TDjacsHead2.appendChild(SELECTjacsHead2);
                                    TRjacsHead.appendChild(TDjacsHead3);
                                        TDjacsHead3.appendChild(SELECTjacsHead3);
                                    TRjacsHead.appendChild(TDjacsHead4);
                                        TDjacsHead4.appendChild(INPUTjacsHead4);
                 TBODYjacs.appendChild(TRjacs2);
                    TRjacs2.appendChild(TDjacs2);
                        TDjacs2.appendChild(TABLEjacsCells);
                            TABLEjacsCells.appendChild(THEADjacsCells);
                                THEADjacsCells.appendChild(TRjacsCells);
                                    TRjacsCells.appendChild(TDjacsCells);

                                    for (var i=0;i<7;i++)
                                        {TDjacsCells           = document.createElement('td');
                                         TDjacsCells.className = 'jacsWeek';
                                         TDjacsCells.id        = calId+'WeekInit'+i;
                                         TRjacsCells.appendChild(TDjacsCells);
                                        }

                            TBODYjacsCells    = document.createElement('tbody');
                            TBODYjacsCells.id = calId+'Cells';

                            TABLEjacsCells.appendChild(TBODYjacsCells);

                            for (var i=0;i<6;i++)
                                {TRjacsCells              = document.createElement('tr');
                                 TBODYjacsCells.appendChild(TRjacsCells);

                                    TDjacsCells           = document.createElement('td');
                                    TDjacsCells.className = 'jacsWeekNo';
                                    TDjacsCells.id        = calId+'Week_'+i;
                                    TRjacsCells.appendChild(TDjacsCells);

                                    for (var j=0;j<7;j++)
                                        {TDjacsCells           = document.createElement('td');
                                         TDjacsCells.className = 'jacsCells';
                                         TDjacsCells.id        = calId+'Cell_'+(j+(i*7));
                                         TRjacsCells.appendChild(TDjacsCells);
                                        }
                                }

                            if ((new Date(TABLEjacs.baseYear + TABLEjacs.dropDownYears,0,0))>dateNow &&
                                (new Date(TABLEjacs.baseYear,0,0))                          <dateNow)
                                {TFOOTjacsFoot           = document.createElement('tfoot');
                                 TFOOTjacsFoot.className = 'jacsFoot';
                                 TABLEjacsCells.appendChild(TFOOTjacsFoot);

                                 TRjacsFoot              = document.createElement('tr');
                                 TRjacsFoot.className    = 'jacsFoot';
                                 TFOOTjacsFoot.appendChild(TRjacsFoot);

                                 TDjacsFoot              = document.createElement('td');
                                 TDjacsFoot.className    = 'jacsFoot';
                                 TDjacsFoot.id           = calId+'Foot';
                                 TDjacsFoot.colSpan      = '8';
                                 TRjacsFoot.appendChild(TDjacsFoot);
                                }

                 if (TABLEjacs.clickToHide)
                    {if (document.addEventListener)
                            {      TABLEjacs.addEventListener('click',    cancel,         false);
                                   TABLEjacs.addEventListener('change',   cancel,         false);
                                  TDjacsDrag.addEventListener('mousedown',beginDrag,      false);
                              INPUTjacsHead1.addEventListener('click',    stopPropagation,false);
                             SELECTjacsHead2.addEventListener('click',    stopPropagation,false);
                             SELECTjacsHead2.addEventListener('change',   stopPropagation,false);
                             SELECTjacsHead3.addEventListener('click',    stopPropagation,false);
                             SELECTjacsHead3.addEventListener('change',   stopPropagation,false);
                              INPUTjacsHead4.addEventListener('click',    stopPropagation,false);
                              TBODYjacsCells.addEventListener('click',    stopPropagation,false);
                            }
                     else   {      TABLEjacs.attachEvent('onclick',    cancel);
                                   TABLEjacs.attachEvent('onchange',   cancel);
                                  TDjacsDrag.attachEvent('onmousedown',beginDrag);
                              INPUTjacsHead1.attachEvent('onclick',    stopPropagation);
                             SELECTjacsHead2.attachEvent('onclick',    stopPropagation);
                             SELECTjacsHead2.attachEvent('onchange',   stopPropagation);
                             SELECTjacsHead3.attachEvent('onclick',    stopPropagation);
                             SELECTjacsHead3.attachEvent('onchange',   stopPropagation);
                              INPUTjacsHead4.attachEvent('onclick',    stopPropagation);
                              TBODYjacsCells.attachEvent('onclick',    stopPropagation);
                            }
                    }
                 else
                    {if (document.addEventListener)
                        {      TABLEjacs.addEventListener('click',    stopPropagation,false);
                               TABLEjacs.addEventListener('change',   stopPropagation,false);
                              TDjacsDrag.addEventListener('mousedown',beginDrag,      false);
                        }
                     else
                        {      TABLEjacs.attachEvent('onclick',    stopPropagation);
                               TABLEjacs.attachEvent('onchange',   stopPropagation);
                              TDjacsDrag.attachEvent('onmousedown',beginDrag);
                        }
                    }

                 if (dynamic)
                        {iFrame = document.createElement('iframe');

                         iFrame.className    = 'jacs';
                         iFrame.id           = calId+'Iframe';
                         if (getEl('jacsIElt7')) {iFrame.src = '/jacsblank.html';}
                         iFrame.name         = 'jacsIframe';
                         iFrame.frameborder  = '0';
                         iFrame.style.zIndex = TABLEjacs.zIndex;

                         document.body.insertBefore(iFrame, document.body.firstChild);
                         document.body.insertBefore(TABLEjacs, iFrame);
                        }
                 else   {if (!getEl('jacsSpan'+calId)) {document.writeln("<span id='jacsSpan"+calId+"'></span>");}
                         getEl('jacsSpan'+calId).appendChild(TABLEjacs);
                        }
                },

             cals: function ()  {return cals;},
             next: function ()
                {if (typeof arguments[0]=='string')
                        {calID       = arguments[0];
                         inFunc      = arguments[1];
                         argPosition = 2;
                        }
                 else   {calID       = 'jacs';
                         inFunc      = arguments[0];
                         argPosition = 1;
                        }

                 if (getEl(calID))
                    {// Take the arguments to be passed through to the defined function.

                     var args = new Array();

                     for (var i=argPosition;i<arguments.length;i++) {args.push(arguments[i]);}

                     // Pass them through to jacsRunNext

                     newFunc = inFunc.jacsRunNext(args,calID);

                     // If the function has already been set, clear the old
                     // function and set the new one (mostly relevant for dynamic
                     // calendars but refreshing the function for static calendars
                     // caters for dynamic parameters).

                     var cal = getEl(calID);

                     if (cal.dynamic) {cal.arrOnNext.push(newFunc);}
                     else             {cal.onNext = newFunc;}
                    }
                 else
                    {alert('ERROR: Calendar object <<' + calID + '>> does not exist.\n' +
                           'Please check that the calendar object id is correct\n' +
                           'and that JACS.show is called before JACS.next.');
                    }
                }
            };
    };

////////////   below, 2800 to 4254, ui.datepicker.js - lines commented out in original file (by default) are removed

/* jQuery UI Date Picker v3.2 - previously jQuery Calendar
   Written by Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@iprimus.com.au).

   Copyright (c) 2007 Marc Grabanski (http://marcgrabanski.com/code/ui-datepicker)
   Dual licensed under the MIT (MIT-LICENSE.txt)
   and GPL (GPL-LICENSE.txt) licenses.
   Date: 09-03-2007  */

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object
   (DatepickerInstance), allowing multiple different settings on the same page. */
   
(function($) { // hide the namespace

function Datepicker() {
	this.debug = false; // Change this to true to start debugging
	this._nextId = 0; // Next ID for a date picker instance
	this._inst = []; // List of instances indexed by ID
	this._curInst = null; // The current instance in use
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		clearText: 'Clear', // Display text for clear link
		clearStatus: 'Erase the current date', // Status text for clear link
		closeText: 'Close', // Display text for close link
		closeStatus: 'Close without change', // Status text for close link
		prevText: '&#x3c;Prev', // Display text for previous month link
		prevStatus: 'Show the previous month', // Status text for previous month link
		nextText: 'Next&#x3e;', // Display text for next month link
		nextStatus: 'Show the next month', // Status text for next month link
		currentText: 'Today', // Display text for current month link
		currentStatus: 'Show the current month', // Status text for current month link
		monthNames: ['January','February','March','April','May','June',
			'July','August','September','October','November','December'], // Names of months for drop-down and formatting
		monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
		monthStatus: 'Show a different month', // Status text for selecting a month
		yearStatus: 'Show a different year', // Status text for selecting a year
		weekHeader: 'Wk', // Header for the week of the year column
		weekStatus: 'Week of the year', // Status text for the week of the year column
		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
		dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
		dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
		dateStatus: 'Select DD, M d', // Status text for the date selection
		dateFormat: 'mm/dd/yy', // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		initStatus: 'Select a date', // Initial Status text on opening
		isRTL: false // True if right-to-left language, false if left-to-right
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: 'focus', // 'focus' for popup on focus,
			// 'button' for trigger button, or 'both' for either
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		closeAtTop: true, // True to have the clear/close at the top,
			// false to have them at the bottom
		mandatory: false, // True to hide the Clear link, false to include it
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		changeMonth: true, // True if month can be selected directly, false if only prev/next
		changeYear: true, // True if year can be selected directly, false if only prev/next
		yearRange: '-10:+10', // Range of years to display in drop-down,
			// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
		changeFirstDay: true, // True to click on day name to change, false to remain as set
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		showWeeks: false, // True to show week of the year, false to omit
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: '+10', // Short year values < this are in the current century,
			// > this are in the previous century, 
			// string value starting with '+' for current year + value
		showStatus: false, // True to show status bar at bottom, false to not show it
		statusForDate: this.dateStatus, // Function to provide status text for a date -
			// takes date and instance as parameters, returns display text
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		speed: 'medium', // Speed of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not,
			// [1] = custom CSS class name(s) or '', e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		numberOfMonths: 1, // Number of months to show at a time
		stepMonths: 1, // Number of months to step back/forward
		rangeSelect: false, // Allows for selecting a date range on one date picker
		rangeSeparator: ' - ' // Text between two dates in a range
	};
	$.extend(this._defaults, this.regional['']);
	this._datepickerDiv = $('<div id="datepicker_div"></div>');
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: 'hasDatepicker',

	/* Debug logging (if enabled). */
	log: function () {
		if (this.debug) {
			console.log.apply('', arguments);
		}
	},
	
	/* Register a new date picker instance - with custom settings. */
	_register: function(inst) {
		var id = this._nextId++;
		this._inst[id] = inst;
		return id;
	},

	/* Retrieve a particular date picker instance based on its ID. */
	_getInst: function(id) {
		return this._inst[id] || id;
	},

	/* Override the default settings for all instances of the date picker. 
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return the manager object */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Handle keystrokes. */
	_doKeyDown: function(e) {
		var inst = $.datepicker._getInst(this._calId);
		if ($.datepicker._datepickerShowing) {
			switch (e.keyCode) {
				case 9:  $.datepicker.hideDatepicker('');
						break; // hide on tab out
				case 13: $.datepicker._selectDay(inst, inst._selectedMonth, inst._selectedYear,
							$('td.datepicker_daysCellOver', inst._datepickerDiv)[0]);
						return false; // don't submit the form
						break; // select the value on enter
				case 27: $.datepicker.hideDatepicker(inst._get('speed'));
						break; // hide on escape
				case 33: $.datepicker._adjustDate(inst,
							(e.ctrlKey ? -1 : -inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(inst,
							(e.ctrlKey ? +1 : +inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
						break; // next month/year on page down/+ ctrl
				case 35: if (e.ctrlKey) $.datepicker._clearDate(inst);
						break; // clear on ctrl+end
				case 36: if (e.ctrlKey) $.datepicker._gotoToday(inst);
						break; // current on ctrl+home
				case 37: if (e.ctrlKey) $.datepicker._adjustDate(inst, -1, 'D');
						break; // -1 day on ctrl+left
				case 38: if (e.ctrlKey) $.datepicker._adjustDate(inst, -7, 'D');
						break; // -1 week on ctrl+up
				case 39: if (e.ctrlKey) $.datepicker._adjustDate(inst, +1, 'D');
						break; // +1 day on ctrl+right
				case 40: if (e.ctrlKey) $.datepicker._adjustDate(inst, +7, 'D');
						break; // +1 week on ctrl+down
			}
		}
		else if (e.keyCode == 36 && e.ctrlKey) { // display the date picker on ctrl+home
			$.datepicker.showFor(this);
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(e) {
		var inst = $.datepicker._getInst(this._calId);
		var chars = $.datepicker._possibleChars(inst._get('dateFormat'));
		var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
		return (chr < ' ' || !chars || chars.indexOf(chr) > -1);
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		if (this._hasClass(input, this.markerClassName)) {
			return;
		}
		var appendText = inst._get('appendText');
		var isRTL = inst._get('isRTL');
		if (appendText) {
			if (isRTL) {
				input.before('<span class="datepicker_append">' + appendText + '</span>');
			}
			else {
				input.after('<span class="datepicker_append">' + appendText + '</span>');
			}
		}
		var showOn = inst._get('showOn');
		if (showOn == 'focus' || showOn == 'both') { // pop-up date picker when in the marked field
			input.focus(this.showFor);
		}
		if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
			var buttonText = inst._get('buttonText');
			var buttonImage = inst._get('buttonImage');
			var buttonImageOnly = inst._get('buttonImageOnly');
			var trigger = $(buttonImageOnly ? '<img class="datepicker_trigger" src="' +
				buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
				'<button type="button" class="datepicker_trigger">' + (buttonImage != '' ?
				'<img src="' + buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
				buttonText) + '</button>');
			input.wrap('<span class="datepicker_wrap"></span>');
			if (isRTL) {
				input.before(trigger);
			}
			else {
				input.after(trigger);
			}
			trigger.click(this.showFor);
		}
		input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress);
		input[0]._calId = inst._id;
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var input = $(target);
		if (this._hasClass(input, this.markerClassName)) {
			return;
		}
		input.addClass(this.markerClassName).append(inst._datepickerDiv);
		input[0]._calId = inst._id;
		this._updateDatepicker(inst);
		/* @todo: fix _inlineShow automatic resizing
			- Endless loop bug in IE6.  
			- inst._datepickerDiv.resize doesn't ever fire in firefox.  */
		// inst._datepickerDiv.resize(function() { $.datepicker._inlineShow(inst); });
	},

	/* Tidy up after displaying the date picker. */
	_inlineShow: function(inst) {
		var numMonths = inst._get('numberOfMonths'); // fix width for dynamic number of date pickers
		numMonths = (numMonths == null ? 1 : (typeof numMonths == 'number' ? numMonths : numMonths[1]));
		inst._datepickerDiv.width(numMonths * $('.datepicker', inst._datepickerDiv[0]).width());
	}, 

	/* Does this element have a particular class? */
	_hasClass: function(element, className) {
		var classes = element.attr('class');
		return (classes && classes.indexOf(className) > -1);
	},

	/* Pop-up the date picker in a "dialog" box.
	   @param  dateText  string - the initial date to display (in the current format)
	   @param  onSelect  function - the function(dateText) to call when a date is selected
	   @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen or
	                     event - with x/y coordinates or
	                     leave empty for default (screen centre)
	   @return the manager object */
	dialogDatepicker: function(dateText, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			inst = this._dialogInst = new DatepickerInstance({}, false);
			this._dialogInput = $('<input type="text" size="1" style="position: absolute; top: -100px;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			this._dialogInput[0]._calId = inst._id;
		}
		extendRemove(inst._settings, settings || {});
		this._dialogInput.val(dateText);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			var browserWidth = window.innerWidth || document.documentElement.clientWidth ||
				document.body.clientWidth;
			var browserHeight = window.innerHeight || document.documentElement.clientHeight ||
				document.body.clientHeight;
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
		inst._settings.onSelect = onSelect;
		this._inDialog = true;
		this._datepickerDiv.addClass('datepicker_dialog');
		this.showFor(this._dialogInput[0]);
		if ($.blockUI) {
			$.blockUI(this._datepickerDiv);
		}
		return this;
	},

	/* Enable the input field(s) for entry.
	   @param  inputs  element - single input field or
	                   string - the ID or other jQuery selector of the input field(s) or
	                   object - jQuery collection of input fields
	   @return the manager object */
	enableFor: function(inputs) {
		inputs = (inputs.jquery ? inputs : $(inputs));
		inputs.each(function() {
			this.disabled = false;
			$(this).siblings('button.datepicker_trigger').each(function() { this.disabled = false; });
			$(this).siblings('img.datepicker_trigger').css({opacity: '1.0', cursor: ''});
			var $this = this;
			$.datepicker._disabledInputs = $.map($.datepicker._disabledInputs,
				function(value) { return (value == $this ? null : value); }); // delete entry
		});
		return this;
	},

	/* Disable the input field(s) from entry.
	   @param  inputs  element - single input field or
	                   string - the ID or other jQuery selector of the input field(s) or
	                   object - jQuery collection of input fields
	   @return the manager object */
	disableFor: function(inputs) {
		inputs = (inputs.jquery ? inputs : $(inputs));
		inputs.each(function() {
			this.disabled = true;
			$(this).siblings('button.datepicker_trigger').each(function() { this.disabled = true; });
			$(this).siblings('img.datepicker_trigger').css({opacity: '0.5', cursor: 'default'});
			var $this = this;
			$.datepicker._disabledInputs = $.map($.datepicker._disabledInputs,
				function(value) { return (value == $this ? null : value); }); // delete entry
			$.datepicker._disabledInputs[$.datepicker._disabledInputs.length] = this;
		});
		return this;
	},

	/* Is the input field disabled?
	   @param  input  element - single input field or
	                  string - the ID or other jQuery selector of the input field or
	                  object - jQuery collection of input field
	   @return boolean - true if disabled, false if enabled */
	isDisabled: function(input) {
		input = (input.jquery ? input[0] : (typeof input == 'string' ? $(input)[0] : input));
		for (var i = 0; i < $.datepicker._disabledInputs.length; i++) {
			if ($.datepicker._disabledInputs[i] == input) {
				return true;
			}
		}
		return false;
	},

	/* Update the settings for a date picker attached to an input field or division.
	   @param  control   element - the input field or div/span attached to the date picker or
	                     string - the ID or other jQuery selector of the input field or
	                     object - jQuery object for input field or div/span
	   @param  settings  object - the new settings to update
	   @return the manager object */
	reconfigureFor: function(control, settings) {
		control = (control.jquery ? control[0] :
			(typeof control == 'string' ? $(control)[0] : control));
		var inst = this._getInst(control._calId);
		if (inst) {
			extendRemove(inst._settings, settings || {});
			this._updateDatepicker(inst);
		}
		return this;
	},

	/* Set the date for a date picker attached to an input field or division.
	   @param  control  element - the input field or div/span attached to the date picker or
	                    string - the ID or other jQuery selector of the input field or
	                    object - jQuery object for input field or div/span
	   @param  date     Date - the new date
	   @param  endDate  Date - the new end date for a range (optional)
	   @return the manager object */
	setDateFor: function(control, date, endDate) {
		control = (control.jquery ? control[0] :
			(typeof control == 'string' ? $(control)[0] : control));
		var inst = this._getInst(control._calId);
		if (inst) {
			inst._setDate(date, endDate);
			this._updateDatepicker(inst);
		}
		return this;
	},

	/* Retrieve the date for a date picker attached to an input field or division.
	   @param  control  element - the input field or div/span attached to the date picker or
	                    string - the ID or other jQuery selector of the input field or
	                    object - jQuery object for input field or div/span
	   @return Date - the current date or
	           Date[2] - the current dates for a range*/
	getDateFor: function(control) {
		control = (control.jquery ? control[0] :
			(typeof control == 'string' ? $(control)[0] : control));
		var inst = this._getInst(control._calId);
		return (inst ? inst._getDate() : null);
	},

	/* Pop-up the date picker for a given input field.
	   @param  control  element - the input field attached to the date picker or
	                    string - the ID or other jQuery selector of the input field or
	                    object - jQuery object for input field
	   @return the manager object */
	showFor: function(control) {
		control = (control.jquery ? control[0] :
			(typeof control == 'string' ? $(control)[0] : control));
		var input = (control.nodeName && control.nodeName.toLowerCase() == 'input' ? control : this);
		if (input.nodeName.toLowerCase() != 'input') { // find from button/image trigger
			input = $('input', input.parentNode)[0];
		}
		if ($.datepicker._lastInput == input) { // already here
			return;
		}
		if ($.datepicker.isDisabled(input)) {
			return;
		}
		var inst = $.datepicker._getInst(input._calId);
		var beforeShow = inst._get('beforeShow');
		extendRemove(inst._settings, (beforeShow ? beforeShow(input) : {}));
		$.datepicker.hideDatepicker('');
		$.datepicker._lastInput = input;
		inst._setDateFromField(input);
		if ($.datepicker._inDialog) { // hide cursor
			input.value = '';
		}
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}
		var isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css('position') == 'fixed';
		});
		if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
			$.datepicker._pos[0] -= document.documentElement.scrollLeft;
			$.datepicker._pos[1] -= document.documentElement.scrollTop;
		}
		inst._datepickerDiv.css('position', ($.datepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute'))).
			css('left', $.datepicker._pos[0] + 'px').css('top', $.datepicker._pos[1] + 'px');
		$.datepicker._pos = null;
		$.datepicker._showDatepicker(inst);
		return this;
	},

	/* Construct and display the date picker. */
	_showDatepicker: function(id) {
		var inst = this._getInst(id);
		inst._rangeStart = null;
		this._updateDatepicker(inst);
		if (!inst._inline) {
			var speed = inst._get('speed');
			var postProcess = function() {
				$.datepicker._datepickerShowing = true;
				$.datepicker._afterShow(inst);
			};
			inst._datepickerDiv.show(speed, postProcess);
			if (speed == '') {
				postProcess();
			}
			if (inst._input[0].type != 'hidden') {
				inst._input[0].focus();
			}
			this._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		inst._datepickerDiv.empty().append(inst._generateDatepicker());
		if (inst._get('numberOfMonths') != 1) {
			inst._datepickerDiv.addClass('datepicker_multi');
		} 
		else {
			inst._datepickerDiv.removeClass('datepicker_multi');
		}
		if (inst._get('isRTL')) {
			inst._datepickerDiv.addClass('datepicker_rtl');
		}
		else {
			inst._datepickerDiv.removeClass('datepicker_rtl');
		}
		if (inst._input && inst._input[0].type != 'hidden') {
			inst._input[0].focus();
		}
	},

	/* Tidy up after displaying the date picker. */
	_afterShow: function(inst) {
		var numMonths = inst._get('numberOfMonths'); // fix width for dynamic number of date pickers
		numMonths = (numMonths == null ? 1 : (typeof numMonths == 'number' ? numMonths : numMonths[1]));
		inst._datepickerDiv.width(numMonths * $('.datepicker', inst._datepickerDiv[0]).width());
		if ($.browser.msie && parseInt($.browser.version) < 7) { // fix IE < 7 select problems
			$('#datepicker_cover').css({width: inst._datepickerDiv.width() + 4,
				height: inst._datepickerDiv.height() + 4});
		}
		// re-position on screen if necessary
		var isFixed = inst._datepickerDiv.css('position') == 'fixed';
		var pos = inst._input ? $.datepicker._findPos(inst._input[0]) : null;
		var browserWidth = window.innerWidth || document.documentElement.clientWidth ||
			document.body.clientWidth;
		var browserHeight = window.innerHeight || document.documentElement.clientHeight ||
			document.body.clientHeight;
		var scrollX = (isFixed ? 0 : document.documentElement.scrollLeft || document.body.scrollLeft);
		var scrollY = (isFixed ? 0 : document.documentElement.scrollTop || document.body.scrollTop);
		// reposition date picker horizontally if outside the browser window
		if ((inst._datepickerDiv.offset().left + inst._datepickerDiv.width() -
				(isFixed && $.browser.msie ? document.documentElement.scrollLeft : 0)) >
				(browserWidth + scrollX)) {
			inst._datepickerDiv.css('left', Math.max(scrollX,
				pos[0] + (inst._input ? $(inst._input[0]).width() : null) - inst._datepickerDiv.width() -
				(isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0)) + 'px');
		}
		// reposition date picker vertically if outside the browser window
		if ((inst._datepickerDiv.offset().top + inst._datepickerDiv.height() -
				(isFixed && $.browser.msie ? document.documentElement.scrollTop : 0)) >
				(browserHeight + scrollY) ) {
			inst._datepickerDiv.css('top', Math.max(scrollY,
				pos[1] - (this._inDialog ? 0 : inst._datepickerDiv.height()) -
				(isFixed && $.browser.opera ? document.documentElement.scrollTop : 0)) + 'px');
		}
	},
	
	/* Find an object's position on the screen. */
	_findPos: function(obj) {
		while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
			obj = obj.nextSibling;
		}
		var curleft = curtop = 0;
		if (obj && obj.offsetParent) {
			curleft = obj.offsetLeft;
			curtop = obj.offsetTop;
			while (obj = obj.offsetParent) {
				var origcurleft = curleft;
				curleft += obj.offsetLeft;
				if (curleft < 0) {
					curleft = origcurleft;
				}
				curtop += obj.offsetTop;
			}
		}
		return [curleft,curtop];
	},

	/* Hide the date picker from view.
	   @param  speed  string - the speed at which to close the date picker
	   @return void */
	hideDatepicker: function(speed) {
		var inst = this._curInst;
		if (!inst) {
			return;
		}
		var rangeSelect = inst._get('rangeSelect');
		if (rangeSelect && this._stayOpen) {
			this._selectDate(inst, inst._formatDate(
				inst._currentDay, inst._currentMonth, inst._currentYear));
		}
		this._stayOpen = false;
		if (this._datepickerShowing) {
			speed = (speed != null ? speed : inst._get('speed'));
			inst._datepickerDiv.hide(speed, function() {
				$.datepicker._tidyDialog(inst);
			});
			if (speed == '') {
				this._tidyDialog(inst);
			}
			this._datepickerShowing = false;
			this._lastInput = null;
			inst._settings.prompt = null;
			if (this._inDialog) {
				this._dialogInput.css('position', 'absolute').
					css('left', '0px').css('top', '-100px');
				if ($.blockUI) {
					$.unblockUI();
					$('body').append(this._datepickerDiv);
				}
			}
			this._inDialog = false;
		}
		this._curInst = null;
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst._datepickerDiv.removeClass('datepicker_dialog');
		$('.datepicker_prompt', inst._datepickerDiv).remove();
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!$.datepicker._curInst) {
			return;
		}
		var target = $(event.target);
		if ((target.parents("#datepicker_div").length == 0) &&
				(target.attr('class') != 'datepicker_trigger') &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) {
			$.datepicker.hideDatepicker('');
		}
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var inst = this._getInst(id);
		inst._adjustDate(offset, period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var date = new Date();
		var inst = this._getInst(id);
		inst._selectedDay = date.getDate();
		inst._selectedMonth = date.getMonth();
		inst._selectedYear = date.getFullYear();
		this._adjustDate(inst);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var inst = this._getInst(id);
		inst._selectingMonthYear = false;
		inst[period == 'M' ? '_selectedMonth' : '_selectedYear'] =
			select.options[select.selectedIndex].value - 0;
		this._adjustDate(inst);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var inst = this._getInst(id);
		if (inst._input && inst._selectingMonthYear && !$.browser.msie) {
			inst._input[0].focus();
		}
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for changing the first week day. */
	_changeFirstDay: function(id, day) {
		var inst = this._getInst(id);
		inst._settings.firstDay = day;
		this._updateDatepicker(inst);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		if (this._hasClass($(td), 'datepicker_unselectable')) {
			return;
		}
		var inst = this._getInst(id);
		var rangeSelect = inst._get('rangeSelect');
		if (rangeSelect) {
			if (!this._stayOpen) {
				$('.datepicker td').removeClass('datepicker_currentDay');
				$(td).addClass('datepicker_currentDay');
			} 
			this._stayOpen = !this._stayOpen;
		}
		inst._currentDay = $('a', td).html();
		inst._currentMonth = month;
		inst._currentYear = year;
		this._selectDate(id, inst._formatDate(
			inst._currentDay, inst._currentMonth, inst._currentYear));
		if (this._stayOpen) {
			inst._endDay = inst._endMonth = inst._endYear = null;
			inst._rangeStart = new Date(inst._currentYear, inst._currentMonth, inst._currentDay);
			this._updateDatepicker(inst);
		}
		else if (rangeSelect) {
			inst._endDay = inst._currentDay;
			inst._endMonth = inst._currentMonth;
			inst._endYear = inst._currentYear;
			inst._selectedDay = inst._currentDay = inst._rangeStart.getDate();
			inst._selectedMonth = inst._currentMonth = inst._rangeStart.getMonth();
			inst._selectedYear = inst._currentYear = inst._rangeStart.getFullYear();
			inst._rangeStart = null;
			if (inst._inline) {
				this._updateDatepicker(inst);
			}
		}
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var inst = this._getInst(id);
		this._stayOpen = false;
		inst._endDay = inst._endMonth = inst._endYear = inst._rangeStart = null;
		this._selectDate(inst, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var inst = this._getInst(id);
		dateStr = (dateStr != null ? dateStr : inst._formatDate());
		if (inst._rangeStart) {
			dateStr = inst._formatDate(inst._rangeStart) + inst._get('rangeSeparator') + dateStr;
		}
		if (inst._input) {
			inst._input.val(dateStr);
		}
		var onSelect = inst._get('onSelect');
		if (onSelect) {
			onSelect(dateStr, inst);  // trigger custom callback
		}
		else {
			if (inst._input) {
				inst._input.trigger('change'); // fire the change event
			}
		}
		if (inst._inline) {
			this._updateDatepicker(inst);
		}
		else {
			if (!this._stayOpen) {
				this.hideDatepicker(inst._get('speed'));
			}
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},
	
	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	   @param  date  Date - the date to get the week for
	   @return  number - the number of the week within the year that contains this date */
	iso8601Week: function(date) {
		var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
		var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
		var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
		firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
		if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
			checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
			return $.datepicker.iso8601Week(checkDate);
		}
		else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
			firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
			if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
				checkDate.setDate(checkDate.getDate() + 3); // Generate for next year
				return $.datepicker.iso8601Week(checkDate);
			}
		}
		return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
	},
	
	/* Provide status text for a particular date.
	   @param  date  the date to get the status for
	   @param  inst  the current datepicker instance
	   @return  the status display text for this date */
	dateStatus: function(date, inst) {
		return $.datepicker.formatDate(inst._get('dateStatus'), date, inst._get('dayNamesShort'),
			inst._get('dayNames'), inst._get('monthNamesShort'), inst._get('monthNames'));
	},

	/* Parse a string value into a date object.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   '...' - literal text
	   '' - single quote

	   @param  format           String - the expected format of the date
	   @param  value            String - the date in the above format
	   @param  shortYearCutoff  Number - the cutoff year for determining the century (optional)
	   @param  dayNamesShort    String[7] - abbreviated names of the days from Sunday (optional)
	   @param  dayNames         String[7] - names of the days from Sunday (optional)
	   @param  monthNamesShort  String[12] - abbreviated names of the months (optional)
	   @param  monthNames       String[12] - names of the months (optional)
	   @return  Date - the extracted date value or null if value is blank */
	parseDate: function (format, value, shortYearCutoff, dayNamesShort, dayNames, monthNamesShort, monthNames) {
		if (format == null || value == null) {
			throw 'Invalid arguments';
		}
		value = (typeof value == 'object' ? value.toString() : value + '');
		if (value == '') {
			return null;
		}
		dayNamesShort = dayNamesShort || this._defaults.dayNamesShort;
		dayNames = dayNames || this._defaults.dayNames;
		monthNamesShort = monthNamesShort || this._defaults.monthNamesShort;
		monthNames = monthNames || this._defaults.monthNames;
		var year = -1;
		var month = -1;
		var day = -1;
		var literal = false;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches) {
				iFormat++;
			}
			return matches;	
		};
		// Extract a number from the string value
		var getNumber = function(match) {
			lookAhead(match);
			var size = (match == 'y' ? 4 : 2);
			var num = 0;
			while (size > 0 && iValue < value.length &&
					value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
				num = num * 10 + (value.charAt(iValue++) - 0);
				size--;
			}
			if (size == (match == 'y' ? 4 : 2)) {
				throw 'Missing number at position ' + iValue;
			}
			return num;
		};
		// Extract a name from the string value and convert to an index
		var getName = function(match, shortNames, longNames) {
			var names = (lookAhead(match) ? longNames : shortNames);
			var size = 0;
			for (var j = 0; j < names.length; j++) {
				size = Math.max(size, names[j].length);
			}
			var name = '';
			var iInit = iValue;
			while (size > 0 && iValue < value.length) {
				name += value.charAt(iValue++);
				for (var i = 0; i < names.length; i++) {
					if (name == names[i]) {
						return i + 1;
					}
				}
				size--;
			}
			throw 'Unknown name at position ' + iInit;
		};
		// Confirm that a literal character matches the string value
		var checkLiteral = function() {
			if (value.charAt(iValue) != format.charAt(iFormat)) {
				throw 'Unexpected literal at position ' + iValue;
			}
			iValue++;
		};
		var iValue = 0;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal) {
				if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
					literal = false;
				}
				else {
					checkLiteral();
				}
			}
			else {
				switch (format.charAt(iFormat)) {
					case 'd':
						day = getNumber('d');
						break;
					case 'D': 
						getName('D', dayNamesShort, dayNames);
						break;
					case 'm': 
						month = getNumber('m');
						break;
					case 'M':
						month = getName('M', monthNamesShort, monthNames); 
						break;
					case 'y':
						year = getNumber('y');
						break;
					case '\'':
						if (lookAhead('\'')) {
							checkLiteral();
						}
						else {
							literal = true;
						}
						break;
					default:
						checkLiteral();
				}
			}
		}
		if (year < 100) {
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		}
		var date = new Date(year, month - 1, day);
		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) {
			throw 'Invalid date'; // E.g. 31/02/*
		}
		return date;
	},

	/* Format a date object into a string value.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   '...' - literal text
	   '' - single quote

	   @param  format           String - the desired format of the date
	   @param  date             Date - the date value to format
	   @param  dayNamesShort    String[7] - abbreviated names of the days from Sunday (optional)
	   @param  dayNames         String[7] - names of the days from Sunday (optional)
	   @param  monthNamesShort  String[12] - abbreviated names of the months (optional)
	   @param  monthNames       String[12] - names of the months (optional)
	   @return  String - the date in the above format */
	formatDate: function (format, date, dayNamesShort, dayNames, monthNamesShort, monthNames) {
		if (!date) {
			return '';
		}
		dayNamesShort = dayNamesShort || this._defaults.dayNamesShort;
		dayNames = dayNames || this._defaults.dayNames;
		monthNamesShort = monthNamesShort || this._defaults.monthNamesShort;
		monthNames = monthNames || this._defaults.monthNames;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches) {
				iFormat++;
			}
			return matches;	
		};
		// Format a number, with leading zero if necessary
		var formatNumber = function(match, value) {
			return (lookAhead(match) && value < 10 ? '0' : '') + value;
		};
		// Format a name, short or long as requested
		var formatName = function(match, value, shortNames, longNames) {
			return (lookAhead(match) ? longNames[value] : shortNames[value]);
		};
		var output = '';
		var literal = false;
		if (date) {
			for (var iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal) {
					if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
						literal = false;
					}
					else {
						output += format.charAt(iFormat);
					}
				}
				else {
					switch (format.charAt(iFormat)) {
						case 'd':
							output += formatNumber('d', date.getDate()); 
							break;
						case 'D': 
							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
							break;
						case 'm': 
							output += formatNumber('m', date.getMonth() + 1); 
							break;
						case 'M':
							output += formatName('M', date.getMonth(), monthNamesShort, monthNames); 
							break;
						case 'y':
							output += (lookAhead('y') ? date.getFullYear() : 
								(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
							break;
						case '\'':
							if (lookAhead('\'')) {
								output += '\'';
							}
							else {
								literal = true;
							}
							break;
						default:
							output += format.charAt(iFormat);
					}
				}
			}
		}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var chars = '';
		var literal = false;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal) {
				if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
					literal = false;
				}
				else {
					chars += format.charAt(iFormat);
				}
			}
			else {
				switch (format.charAt(iFormat)) {
					case 'd':
					case 'm': 
					case 'y':
						chars += '0123456789'; 
						break;
					case 'D': 
					case 'M':
						return null; // Accept anything
					case '\'':
						if (lookAhead('\'')) {
							chars += '\'';
						}
						else {
							literal = true;
						}
						break;
					default:
						chars += format.charAt(iFormat);
				}
			}
		}
		return chars;
	}
});

/* Individualised settings for date picker functionality applied to one or more related inputs.
   Instances are managed and manipulated through the Datepicker manager. */
function DatepickerInstance(settings, inline) {
	this._id = $.datepicker._register(this);
	this._selectedDay = 0;
	this._selectedMonth = 0; // 0-11
	this._selectedYear = 0; // 4-digit year
	this._input = null; // The attached input field
	this._inline = inline; // True if showing inline, false if used in a popup
	this._datepickerDiv = (!inline ? $.datepicker._datepickerDiv :
		$('<div id="datepicker_div_' + this._id + '" class="datepicker_inline"></div>'));
	// customise the date picker object - uses manager defaults if not overridden
	this._settings = extendRemove({}, settings || {}); // clone
	if (inline) {
		this._setDate(this._getDefaultDate());
	}
}

$.extend(DatepickerInstance.prototype, {
	/* Get a setting value, defaulting if necessary. */
	_get: function(name) {
		return (this._settings[name] != null ? this._settings[name] : $.datepicker._defaults[name]);
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(input) {
		this._input = $(input);
		var dateFormat = this._get('dateFormat');
		var dates = this._input ? this._input.val().split(this._get('rangeSeparator')) : null; 
		this._endDay = this._endMonth = this._endYear = null;
		var shortYearCutoff = this._get('shortYearCutoff');
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		var date = this._getDefaultDate();
		if (dates.length > 0) {
			var dayNamesShort = this._get('dayNamesShort');
			var dayNames = this._get('dayNames');
			var monthNamesShort = this._get('monthNamesShort');
			var monthNames = this._get('monthNames');
			if (dates.length > 1) {
				date = $.datepicker.parseDate(dateFormat, dates[1], shortYearCutoff,
					dayNamesShort, dayNames, monthNamesShort, monthNames) ||
					this._getDefaultDate();
				this._endDay = date.getDate();
				this._endMonth = date.getMonth();
				this._endYear = date.getFullYear();
			}
			try {
				date = $.datepicker.parseDate(dateFormat, dates[0], shortYearCutoff,
					dayNamesShort, dayNames, monthNamesShort, monthNames) ||
					this._getDefaultDate();
			}
			catch (e) {
				$.datepicker.log(e);
				date = this._getDefaultDate();
			}
		}
		this._selectedDay = this._currentDay = date.getDate();
		this._selectedMonth = this._currentMonth = date.getMonth();
		this._selectedYear = this._currentYear = date.getFullYear();
		this._adjustDate();
	},
	
	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function() {
		var offsetDate = function(offset) {
			var date = new Date();
			date.setDate(date.getDate() + offset);
			return date;
		};
		var defaultDate = this._get('defaultDate');
		return (defaultDate == null ? new Date() :
			(typeof defaultDate == 'number' ? offsetDate(defaultDate) : defaultDate));
	},

	/* Set the date(s) directly. */
	_setDate: function(date, endDate) {
		this._selectedDay = this._currentDay = date.getDate();
		this._selectedMonth = this._currentMonth = date.getMonth();
		this._selectedYear = this._currentYear = date.getFullYear();
		if (this._get('rangeSelect')) {
			if (endDate) {
				this._endDay = endDate.getDate();
				this._endMonth = endDate.getMonth();
				this._endYear = endDate.getFullYear();
			}
			else {
				this._endDay = this._currentDay;
				this._endMonth = this._currentMonth;
				this._endYear = this._currentYear;
			}
		}
		this._adjustDate();
	},

	/* Retrieve the date(s) directly. */
	_getDate: function() {
		var startDate = (!this._currentYear || (this._input && this._input.val() == '') ? null :
			new Date(this._currentYear, this._currentMonth, this._currentDay));
		if (this._get('rangeSelect')) {
			return [startDate, (!this._endYear ? null :
				new Date(this._endYear, this._endMonth, this._endDay))];
		}
		else {
			return startDate;
		}
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateDatepicker: function() {
		var today = new Date();
		today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time
		var showStatus = this._get('showStatus');
		var isRTL = this._get('isRTL');
		// build the date picker HTML
		var clear = (this._get('mandatory') ? '' :
			'<div class="datepicker_clear"><a onclick="jQuery.datepicker._clearDate(' + this._id + ');"' + 
			(showStatus ? this._addStatus(this._get('clearStatus') || '&#xa0;') : '') + '>' +
			this._get('clearText') + '</a></div>');
		var controls = '<div class="datepicker_control">' + (isRTL ? '' : clear) +
			'<div class="datepicker_close"><a onclick="jQuery.datepicker.hideDatepicker();"' +
			(showStatus ? this._addStatus(this._get('closeStatus') || '&#xa0;') : '') + '>' +
			this._get('closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
		var prompt = this._get('prompt');
		var closeAtTop = this._get('closeAtTop');
		var hideIfNoPrevNext = this._get('hideIfNoPrevNext');
		var numMonths = this._get('numberOfMonths');
		var stepMonths = this._get('stepMonths');
		var isMultiMonth = (numMonths != 1);
		numMonths = (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
		// controls and links
		var prev = '<div class="datepicker_prev">' + (this._canAdjustMonth(-1) ? 
			'<a onclick="jQuery.datepicker._adjustDate(' + this._id + ', -' + stepMonths + ', \'M\');"' +
			(showStatus ? this._addStatus(this._get('prevStatus') || '&#xa0;') : '') + '>' +
			this._get('prevText') + '</a>' :
			(hideIfNoPrevNext ? '' : '<label>' + this._get('prevText') + '</label>')) + '</div>';
		var next = '<div class="datepicker_next">' + (this._canAdjustMonth(+1) ?
			'<a onclick="jQuery.datepicker._adjustDate(' + this._id + ', +' + stepMonths + ', \'M\');"' +
			(showStatus ? this._addStatus(this._get('nextStatus') || '&#xa0;') : '') + '>' +
			this._get('nextText') + '</a>' :
			(hideIfNoPrevNext ? '>' : '<label>' + this._get('nextText') + '</label>')) + '</div>';
		var html = (prompt ? '<div class="datepicker_prompt">' + prompt + '</div>' : '') +
			(closeAtTop && !this._inline ? controls : '') +
			'<div class="datepicker_links">' + (isRTL ? next : prev) +
			(this._isInRange(today) ? '<div class="datepicker_current">' +
			'<a onclick="jQuery.datepicker._gotoToday(' + this._id + ');"' +
			(showStatus ? this._addStatus(this._get('currentStatus') || '&#xa0;') : '') + '>' +
			this._get('currentText') + '</a></div>' : '') + (isRTL ? prev : next) + '</div>';
		var minDate = this._getMinDate();
		var maxDate = this._get('maxDate');
		var drawMonth = this._selectedMonth;
		var drawYear = this._selectedYear;
		var showWeeks = this._get('showWeeks');
		for (var row = 0; row < numMonths[0]; row++) {
		for (var col = 0; col < numMonths[1]; col++) {
			var selectedDate = new Date(drawYear, drawMonth, this._selectedDay);
			html += '<div class="datepicker_oneMonth' + (col == 0 ? ' datepicker_newRow' : '') + '">' +
				this._generateMonthYearHeader(drawMonth, drawYear, minDate, maxDate,
				selectedDate, row > 0 || col > 0) + // draw month headers
				'<table class="datepicker" cellpadding="0" cellspacing="0"><thead>' + 
				'<tr class="datepicker_titleRow">' +
				(showWeeks ? '<td>' + this._get('weekHeader') + '</td>' : '');
			var firstDay = this._get('firstDay');
			var changeFirstDay = this._get('changeFirstDay');
			var dayNames = this._get('dayNames');
			var dayNamesShort = this._get('dayNamesShort');
			var dayNamesMin = this._get('dayNamesMin');
			for (var dow = 0; dow < 7; dow++) { // days of the week
				var day = (dow + firstDay) % 7;
				var status = this._get('dayStatus') || '&#xa0;';
				status = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) :
					status.replace(/D/, dayNamesShort[day]));
				html += '<td>' + (!changeFirstDay ? '<span' :
					'<a onclick="jQuery.datepicker._changeFirstDay(' + this._id + ', ' + day + ');"') + 
					(showStatus ? this._addStatus(status) : '') + ' title="' + dayNames[day] + '">' +
					dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</td>';
			}
			html += '</tr></thead><tbody>';
			var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
			this._selectedDay = Math.min(this._selectedDay, daysInMonth);
			var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
			var currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay);
			var endDate = this._endDay ? new Date(this._endYear, this._endMonth, this._endDay) : currentDate;
			var printDate = new Date(drawYear, drawMonth, 1 - leadDays);
			var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
			var beforeShowDay = this._get('beforeShowDay');
			var showOtherMonths = this._get('showOtherMonths');
			var calculateWeek = this._get('calculateWeek') || $.datepicker.iso8601Week;
			var dateStatus = this._get('statusForDate') || $.datepicker.dateStatus;
			for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
				html += '<tr class="datepicker_daysRow">' +
					(showWeeks ? '<td class="datepicker_weekCol">' + calculateWeek(printDate) + '</td>' : '');
				for (var dow = 0; dow < 7; dow++) { // create date picker days
					var daySettings = (beforeShowDay ? beforeShowDay(printDate) : [true, '']);
					var otherMonth = (printDate.getMonth() != drawMonth);
					var unselectable = otherMonth || !daySettings[0] ||
						(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
					html += '<td class="datepicker_daysCell' +
						((dow + firstDay + 6) % 7 >= 5 ? ' datepicker_weekEndCell' : '') + // highlight weekends
						(otherMonth ? ' datepicker_otherMonth' : '') + // highlight days from other months
						(printDate.getTime() == selectedDate.getTime() && drawMonth == this._selectedMonth ?
						' datepicker_daysCellOver' : '') + // highlight selected day
						(unselectable ? ' datepicker_unselectable' : '') +  // highlight unselectable days
						(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
						(printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ?  // in current range
						' datepicker_currentDay' : // highlight selected day
						(printDate.getTime() == today.getTime() ? ' datepicker_today' : ''))) + '"' + // highlight today (if different)
						(unselectable ? '' : ' onmouseover="jQuery(this).addClass(\'datepicker_daysCellOver\');' +
						(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#datepicker_status_' +
						this._id + '\').html(\'' + (dateStatus(printDate, this) || '&#xa0;') +'\');') + '"' +
						' onmouseout="jQuery(this).removeClass(\'datepicker_daysCellOver\');' +
						(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#datepicker_status_' +
						this._id + '\').html(\'&#xa0;\');') + '" onclick="jQuery.datepicker._selectDay(' +
						this._id + ',' + drawMonth + ',' + drawYear + ', this);"') + '>' + // actions
						(otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
						(unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
					printDate.setDate(printDate.getDate() + 1);
				}
				html += '</tr>';
			}
			drawMonth++;
			if (drawMonth > 11) {
				drawMonth = 0;
				drawYear++;
			}
			html += '</tbody></table></div>';
		}
		}
		html += (showStatus ? '<div id="datepicker_status_' + this._id + 
			'" class="datepicker_status">' + (this._get('initStatus') || '&#xa0;') + '</div>' : '') +
			(!closeAtTop && !this._inline ? controls : '') +
			'<div style="clear: both;"></div>' + 
			($.browser.msie && parseInt($.browser.version) < 7 && !this._inline ? 
			'<iframe src="javascript:false;" class="datepicker_cover"></iframe>' : '');
		return html;
	},
	
	/* Generate the month and year header. */
	_generateMonthYearHeader: function(drawMonth, drawYear, minDate, maxDate, selectedDate, secondary) {
		minDate = (this._rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
		var showStatus = this._get('showStatus');
		var html = '<div class="datepicker_header">';
		// month selection
		var monthNames = this._get('monthNames');
		if (secondary || !this._get('changeMonth')) {
			html += monthNames[drawMonth] + '&#xa0;';
		}
		else {
			var inMinYear = (minDate && minDate.getFullYear() == drawYear);
			var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
			html += '<select class="datepicker_newMonth" ' +
				'onchange="jQuery.datepicker._selectMonthYear(' + this._id + ', this, \'M\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(' + this._id + ');"' +
				(showStatus ? this._addStatus(this._get('monthStatus') || '&#xa0;') : '') + '>';
			for (var month = 0; month < 12; month++) {
				if ((!inMinYear || month >= minDate.getMonth()) &&
						(!inMaxYear || month <= maxDate.getMonth())) {
					html += '<option value="' + month + '"' +
						(month == drawMonth ? ' selected="selected"' : '') +
						'>' + monthNames[month] + '</option>';
				}
			}
			html += '</select>';
		}
		// year selection
		if (secondary || !this._get('changeYear')) {
			html += drawYear;
		}
		else {
			// determine range of years to display
			var years = this._get('yearRange').split(':');
			var year = 0;
			var endYear = 0;
			if (years.length != 2) {
				year = drawYear - 10;
				endYear = drawYear + 10;
			}
			else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
				year = drawYear + parseInt(years[0], 10);
				endYear = drawYear + parseInt(years[1], 10);
			}
			else {
				year = parseInt(years[0], 10);
				endYear = parseInt(years[1], 10);
			}
			year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
			endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
			html += '<select class="datepicker_newYear" ' +
				'onchange="jQuery.datepicker._selectMonthYear(' + this._id + ', this, \'Y\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(' + this._id + ');"' +
				(showStatus ? this._addStatus(this._get('yearStatus') || '&#xa0;') : '') + '>';
			for (; year <= endYear; year++) {
				html += '<option value="' + year + '"' +
					(year == drawYear ? ' selected="selected"' : '') +
					'>' + year + '</option>';
			}
			html += '</select>';
		}
		html += '</div>'; // Close datepicker_header
		return html;
	},

	/* Provide code to set and clear the status panel. */
	_addStatus: function(text) {
		return ' onmouseover="jQuery(\'#datepicker_status_' + this._id + '\').html(\'' + text + '\');" ' +
			'onmouseout="jQuery(\'#datepicker_status_' + this._id + '\').html(\'&#xa0;\');"';
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(offset, period) {
		var year = this._selectedYear + (period == 'Y' ? offset : 0);
		var month = this._selectedMonth + (period == 'M' ? offset : 0);
		var day = Math.min(this._selectedDay, this._getDaysInMonth(year, month)) +
			(period == 'D' ? offset : 0);
		var date = new Date(year, month, day);
		// ensure it is within the bounds set
		var minDate = this._getMinDate();
		var maxDate = this._get('maxDate');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		this._selectedDay = date.getDate();
		this._selectedMonth = date.getMonth();
		this._selectedYear = date.getFullYear();
	},

	/* Determine the current minimum date - may be overridden for a range. */
	_getMinDate: function() {
		return this._get('minDate') || this._rangeStart;
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(offset) {
		var date = new Date(this._selectedYear, this._selectedMonth + offset, 1);
		if (offset < 0) {
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		}
		return this._isInRange(date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(date) {
		// during range selection, use minimum of selected date and range start
		var newMinDate = (!this._rangeStart ? null :
			new Date(this._selectedYear, this._selectedMonth, this._selectedDay));
		newMinDate = (newMinDate && this._rangeStart < newMinDate ? this._rangeStart : newMinDate);
		var minDate = newMinDate || this._get('minDate');
		var maxDate = this._get('maxDate');
		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
	},

	/* Format the given date for display. */
	_formatDate: function(day, month, year) {
		if (!day) {
			this._currentDay = this._selectedDay;
			this._currentMonth = this._selectedMonth;
			this._currentYear = this._selectedYear;
		}
		var date = (day ? (typeof day == 'object' ? day : new Date(year, month, day)) :
			new Date(this._currentYear, this._currentMonth, this._currentDay));
		return $.datepicker.formatDate(this._get('dateFormat'), date,
			this._get('dayNamesShort'), this._get('dayNames'),
			this._get('monthNamesShort'), this._get('monthNames'));
	}
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props) {
		if (props[name] == null) {
			target[name] = null;
		}
	}
	return target;
};

/* Attach the date picker to a jQuery selection.
   @param  settings  object - the new settings to use for this date picker instance (anonymous)
   @return jQuery object - for chaining further calls */
$.fn.datepicker = function(settings) {
	return this.each(function() {
		// check for settings on the control itself - in namespace 'date:'
		var inlineSettings = null;
		for (attrName in $.datepicker._defaults) {
			var attrValue = this.getAttribute('date:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				}
				catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = this.nodeName.toLowerCase();
		if (nodeName == 'input') {
			var instSettings = (inlineSettings ? $.extend($.extend({}, settings || {}),
				inlineSettings || {}) : settings); // clone and customise
			var inst = (inst && !inlineSettings ? inst :
				new DatepickerInstance(instSettings, false));
			$.datepicker._connectDatepicker(this, inst);
		} 
		else if (nodeName == 'div' || nodeName == 'span') {
			var instSettings = $.extend($.extend({}, settings || {}),
				inlineSettings || {}); // clone and customise
			var inst = new DatepickerInstance(instSettings, true);
			$.datepicker._inlineDatepicker(this, inst);
		}
	});
};

/* Initialise the date picker. */
$(document).ready(function() {
	$.datepicker = new Datepicker(); // singleton instance
	$(document.body).append($.datepicker._datepickerDiv).
		mousedown($.datepicker._checkExternalClick);
});

})(jQuery);
////////////////  below to end, 4254 - end, jquery.tablesorter.pager.js, edits on default num rows and page navigation display
(function($) {
	$.extend({
		tablesorterPager: new function() {
			
			function updatePageDisplay(c) {
				var s = $(c.cssPageDisplay,c.container).val('Page ' + (c.page+1) + c.seperator + c.totalPages);	
			}
			
			function setPageSize(table,size) {
				var c = table.config;
				c.size = size;
				c.totalPages = Math.ceil(c.totalRows / c.size);
				c.pagerPositionSet = false;
				moveToPage(table);
				fixPosition(table);
			}
			
			function fixPosition(table) {
				var c = table.config;
				if(!c.pagerPositionSet && c.positionFixed) {
					var c = table.config, o = $(table);
					if(o.offset) {
						c.container.css({
							//top: o.offset().top + o.height() + 'px',
							position: 'relative'
						});
					}
					c.pagerPositionSet = true;
				}
			}
			
			function moveToFirstPage(table) {
				var c = table.config;
				c.page = 0;
				moveToPage(table);
			}
			
			function moveToLastPage(table) {
				var c = table.config;
				c.page = (c.totalPages-1);
				moveToPage(table);
			}
			
			function moveToNextPage(table) {
				var c = table.config;
				c.page++;
				if(c.page >= (c.totalPages-1)) {
					c.page = (c.totalPages-1);
				}
				moveToPage(table);
			}
			
			function moveToPrevPage(table) {
				var c = table.config;
				c.page--;
				if(c.page <= 0) {
					c.page = 0;
				}
				moveToPage(table);
			}
						
			
			function moveToPage(table) {
				var c = table.config;
				if(c.page < 0 || c.page > (c.totalPages-1)) {
					c.page = 0;
				}
				
				renderTable(table,c.rowsCopy);
			}
			
			function renderTable(table,rows) {
				
				var c = table.config;
				var l = rows.length;
				var s = (c.page * c.size);
				var e = (s + c.size);
				if(e > rows.length ) {
					e = rows.length;
				}
				
				
				var tableBody = $(table.tBodies[0]);
				
				// clear the table body
				
				$.tablesorter.clearTableBody(table);
				
				for(var i = s; i < e; i++) {
					
					//tableBody.append(rows[i]);
					
					var o = rows[i];
					var l = o.length;
					for(var j=0; j < l; j++) {
						
						tableBody[0].appendChild(o[j]);

					}
				}
				
				fixPosition(table,tableBody);
				
				$(table).trigger("applyWidgets");
				
				if( c.page >= c.totalPages ) {
        			moveToLastPage(table);
				}
				
				updatePageDisplay(c);
			}
			
			this.appender = function(table,rows) {
				
				var c = table.config;
				
				c.rowsCopy = rows;
				c.totalRows = rows.length;
				c.totalPages = Math.ceil(c.totalRows / c.size);
				
				renderTable(table,rows);
			};
			
			this.defaults = {
				size: 10,
				offset: 0,
				page: 0,
				totalRows: 0,
				totalPages: 0,
				container: null,
				cssNext: '.next',
				cssPrev: '.prev',
				cssFirst: '.first',
				cssLast: '.last',
				cssPageDisplay: '.pagedisplay',
				cssPageSize: '.pagesize',
				seperator: " of ",
				positionFixed: true,
				appender: this.appender
			};

			this.construct = function(settings) {
				
				return this.each(function() {	
					
					config = $.extend(this.config, $.tablesorterPager.defaults, settings);
					
					var table = this, pager = config.container;
				
					$(this).trigger("appendCache");
					
					config.size = parseInt($(".pagesize",pager).val());
					
					// -----------------------
					// Added by Bob
					var $this;
										
					// store common expression for speed					
					$this = $(this);

					// apply easy methods that trigger binded events
					$this.bind("update1000",function() {
												
						setPageSize(table,1000);
						return false;
						
					});

					$this.bind("update10",function() {
												
						setPageSize(table,10);
						return false;
						
					});
					$this.bind("update20",function() {
												
						setPageSize(table,20);
						return false;
						
					});
					$this.bind("update15",function() {
												
						setPageSize(table,15);
						return false;
						
					});
					// -----------------------

					$(config.cssFirst,pager).click(function() {
						moveToFirstPage(table);
						return false;
					});
					$(config.cssNext,pager).click(function() {
						moveToNextPage(table);
						return false;
					});
					$(config.cssPrev,pager).click(function() {
						moveToPrevPage(table);
						return false;
					});
					$(config.cssLast,pager).click(function() {
						moveToLastPage(table);
						return false;
					});
					$(config.cssPageSize,pager).change(function() {
						setPageSize(table,parseInt($(this).val()));
						return false;
					});
				});
			};
			
		}
	});
	// extend plugin scope
	$.fn.extend({
        tablesorterPager: $.tablesorterPager.construct
	});
	
})(jQuery);				
