if (typeof CELOXIS == "undefined" || !CELOXIS) {
    var CELOXIS = {};
}

CELOXIS.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=CELOXIS;

        // CELOXIS is implied, so it is ignored if it is included
        for (j=(d[0] == "CELOXIS") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }
}




// BOI, followed by one or more whitespace characters, followed by EOI.
var reWhitespace = /^\s+$/


// BOI, followed by one lower or uppercase English letter, followed by EOI.
var reLetter = /^[a-zA-Z]$/


// BOI, followed by one or more lower or uppercase English letters,
// followed by EOI.
var reAlphabetic = /^[a-zA-Z]+$/


// BOI, followed by one or more lower or uppercase English letters
// or digits, followed by EOI.
var reAlphanumeric = /^[a-zA-Z0-9]+$/


// BOI, followed by one digit, followed by EOI.
var reDigit = /^\d/


// BOI, followed by one lower or uppercase English letter
// or digit, followed by EOI.
var reLetterOrDigit = /^([a-zA-Z]|\d)$/


// BOI, followed by one or more digits, followed by EOI.
var reInteger = /^\d+$/


// BOI, followed by an optional + or -, followed by one or more digits,
// followed by EOI.
var reSignedInteger = /^(\+|-)?\d+$/


// BOI, followed by one of these two patterns:
// (a) one or more digits, followed by ., followed by zero or more digits
// (b) zero or more digits, followed by ., followed by one or more digits
// ... followed by EOI.
var reFloat = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/


// BOI, followed by an optional + or -, followed by one of these two patterns:
// (a) one or more digits, followed by ., followed by zero or more digits
// (b) zero or more digits, followed by ., followed by one or more digits
// ... followed by EOI.
var reSignedFloat = /^(((\+|-)?\d+(\.\d*)?)|((\+|-)?(\d*\.)?\d+))$/

// BOI, followed by one or more characters, followed by @,
// followed by one or more characters, followed by .,
// followed by one or more characters, followed by EOI.
var reEmail = /^.+\@.+\..+$/




// VARIABLE DECLARATIONS

var digits = "0123456789";

var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"

var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// whitespace characters as defined by this sample code
var whitespace = " \t\n\r";


// non-digit characters which are allowed in phone numbers
var phoneNumberDelimiters = "()- ";


// characters which are allowed in US phone numbers
var validUSPhoneChars = digits + phoneNumberDelimiters;


// characters which are allowed in international phone numbers
// (a leading + is OK)
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+";


// non-digit characters which are allowed in
// Social Security Numbers
var SSNDelimiters = "- ";



// characters which are allowed in Social Security Numbers
var validSSNChars = digits + SSNDelimiters;



// U.S. Social Security Numbers have 9 digits.
// They are formatted as 123-45-6789.
var digitsInSocialSecurityNumber = 9;



// U.S. phone numbers have 10 digits.
// They are formatted as 123 456 7890 or (123) 456-7890.
var digitsInUSPhoneNumber = 10;



// non-digit characters which are allowed in ZIP Codes
var ZIPCodeDelimiters = "-";



// our preferred delimiter for reformatting ZIP Codes
var ZIPCodeDelimeter = "-"


// characters which are allowed in Social Security Numbers
var validZIPCodeChars = digits + ZIPCodeDelimiters



// U.S. ZIP codes have 5 or 9 digits.
// They are formatted as 12345 or 12345-6789.
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9


// non-digit characters which are allowed in credit card numbers
var creditCardDelimiters = " "


// CONSTANT STRING DECLARATIONS
// (grouped for ease of translation and localization)

// m is an abbreviation for "missing"

var mPrefix = "You did not enter a value into the "
var mSuffix = " field. This is a required field. Please enter it now."
var iEmail = "This field must be a valid email address (like joe@myisp.com). Please reenter it now."
var iNonnegativeInteger = "This field must be a number greater than zero without decimal points."

var defaultEmptyOK = false

// Attempting to make this library run on Navigator 2.0,
// so I'm supplying this array creation routine as per
// JavaScript 1.0 documentation.  If you're using
// Navigator 3.0 or later, you don't need to do this;
// you can use the Array constructor instead.

function makeArray(n) {
//*** BUG: If I put this line in, I get two error messages:
//(1) Window.length can't be set by assignment
//(2) daysInMonth has no property indexed by 4
//If I leave it out, the code works fine.
//   this.length = n;

// NGD: put the next line cos Mozilla 6.1 gives error
   return new Array();

   /*
   for (var i = 1; i <= n; i++) {
      this[i] = 0
   }
   return this
   */
}



var daysInMonth = makeArray(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;   // must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;




// Valid U.S. Postal Codes for states, territories, armed forces, etc.
// See http://www.usps.gov/ncsc/lookups/abbr_state.txt.

var USStateCodeDelimiter = "|";
var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY|AE|AA|AE|AE|AP"




// Check whether string s is empty.

function isEmpty(s)
{   return ((s == undefined) || (s == null) || (s.length == 0))
}



// Returns true if string s is empty or
// whitespace characters only.

function isWhitespace (s)

{   // Is s empty?
    return (isEmpty(s) || reWhitespace.test(s));
}



// Removes all characters which appear in regexp bag from string s.
// NOTES:
// 1) bag must be a regexp which matches single characters in isolation,
//    i.e. A or B or C or D or 1 or 2 ...
//    e.g. /\d/g  or /[a-zA-Z]/g
// 2) make sure to append the 'g' modifier (for global search & replace)
//    at the end of the regexp
//    e.g. /\d/g  or /[a-zA-Z]/g

function stripCharsInRE (s, bag)

{       return s.replace(bag, "")
}



// Removes all characters which appear in string bag from string s.

function stripCharsInBag (s, bag)

{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }

    return returnString;
}



// Removes all characters which do NOT appear in string bag
// from string s.

function stripCharsNotInBag (s, bag)

{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is in bag, append to returnString.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) returnString += c;
    }

    return returnString;
}



// Removes all whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.

function stripWhitespace (s)

{   return stripCharsInBag (s, whitespace)
}




// WORKAROUND FUNCTION FOR NAVIGATOR 2.0.2 COMPATIBILITY.
//
// The below function *should* be unnecessary.  In general,
// avoid using it.  Use the standard method indexOf instead.
//
// However, because of an apparent bug in indexOf on
// Navigator 2.0.2, the below loop does not work as the
// body of stripInitialWhitespace:
//
// while ((i < s.length) && (whitespace.indexOf(s.charAt(i)) != -1))
//   i++;
//
// ... so we provide this workaround function charInString
// instead.
//
// charInString (CHARACTER c, STRING s)
//
// Returns true if single character c (actually a string)
// is contained within string s.

function charInString (c, s)
{   for (i = 0; i < s.length; i++)
    {   if (s.charAt(i) == c) return true;
    }
    return false
}



// Removes initial (leading) whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.

function stripInitialWhitespace (s)

{   var i = 0;

    while ((i < s.length) && charInString (s.charAt(i), whitespace))
       i++;

    return s.substring (i, s.length);
}

// Removes leading & trailing whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.

function trim (s)
{
    var i = 0;
    while ((i < s.length) && charInString (s.charAt(i), whitespace))
       i++;
    s = s.substring (i, s.length);
    i = s.length-1;
    while ((i > 0) && charInString (s.charAt(i), whitespace))
        i--;
    return s.substring(0, i+1);
}

// Returns true if character c is an English letter
// (A .. Z, a..z).
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isLetter (c)
{   return reLetter.test(c)
}



// Returns true if character c is a digit
// (0 .. 9).

function isDigit (c)
{   return reDigit.test(c)
}



// Returns true if character c is a letter or digit.

function isLetterOrDigit (c)
{   return reLetterOrDigit.test(c)
}



// isInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters in string s are numbers.
//
// Accepts non-signed integers only. Does not accept floating
// point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// By default, returns defaultEmptyOK if s is empty.
// There is an optional second argument called emptyOK.
// emptyOK is used to override for a single function call
//      the default behavior which is specified globally by
//      defaultEmptyOK.
// If emptyOK is false (or any value other than true),
//      the function will return false if s is empty.
// If emptyOK is true, the function will return true if s is empty.
//
// EXAMPLE FUNCTION CALL:     RESULT:
// isInteger ("5")            true
// isInteger ("")             defaultEmptyOK
// isInteger ("-5")           false
// isInteger ("", true)       true
// isInteger ("", false)      false
// isInteger ("5", false)     true

function isInteger (s)

{   var i;

    if (isEmpty(s))
       if (isInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isInteger.arguments[1] == true);

    return reInteger.test(s)
}







// isSignedInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters are numbers;
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// EXAMPLE FUNCTION CALL:          RESULT:
// isSignedInteger ("5")           true
// isSignedInteger ("")            defaultEmptyOK
// isSignedInteger ("-5")          true
// isSignedInteger ("+5")          true
// isSignedInteger ("", false)     false
// isSignedInteger ("", true)      true

function isSignedInteger (s)

{   if (isEmpty(s))
       if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedInteger.arguments[1] == true);


    else {
       return reSignedInteger.test(s)
    }
}




// isPositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer > 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isPositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a positive, not negative, number

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) > 0) ) );
}






// isNonnegativeInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer >= 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNonnegativeInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNonnegativeInteger.arguments.length > 1)
        secondArg = isNonnegativeInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a number >= 0

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) >= 0) ) );
}

function checkNonnegativeInteger (theField, emptyOK)
{   if (checkNonnegativeInteger.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else if (!isNonnegativeInteger(theField.value, false))
       return warnInvalid (theField, iNonnegativeInteger);
    else return true;
}


// isNegativeInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer < 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNegativeInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNegativeInteger.arguments.length > 1)
        secondArg = isNegativeInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a negative, not positive, number

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) < 0) ) );
}






// isNonpositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer <= 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNonpositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNonpositiveInteger.arguments.length > 1)
        secondArg = isNonpositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a number <= 0

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) <= 0) ) );
}




function checkFloat(theField, labelString, emptyOK)
{
   if (!isFloat(theField.value, emptyOK))
   {
       return warnInvalid(theField, labelString + ' must be a positive decimal number');
   }
   return true;
}

// isFloat (STRING s [, BOOLEAN emptyOK])
//
// True if string s is an unsigned floating point (real) number.
//
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isInteger, then call isFloat.
//
// Does not accept exponential notation.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isFloat (s)

{   if (isEmpty(s))
       if (isFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isFloat.arguments[1] == true);

    return reFloat.test(s)
}




function checkSignedFloat(theField, labelString, emptyOK)
{
   if (!isSignedFloat(theField.value, emptyOK))
   {
       return warnInvalid(theField, labelString + ' must be a decimal number');
   }
   return true;
}



// isSignedFloat (STRING s [, BOOLEAN emptyOK])
//
// True if string s is a signed or unsigned floating point
// (real) number. First character is allowed to be + or -.
//
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isSignedInteger, then call isSignedFloat.
//
// Does not accept exponential notation.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isSignedFloat (s)

{   if (isEmpty(s))
       if (isSignedFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedFloat.arguments[1] == true);

    else {
       return reSignedFloat.test(s)
    }
}




// isAlphabetic (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is English letters
// (A .. Z, a..z) only.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isAlphabetic (s)

{   var i;

    if (isEmpty(s))
       if (isAlphabetic.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphabetic.arguments[1] == true);

    else {
       return reAlphabetic.test(s)
    }
}




// isAlphanumeric (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is English letters
// (A .. Z, a..z) and numbers only.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isAlphanumeric (s)

{   var i;

    if (isEmpty(s))
       if (isAlphanumeric.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphanumeric.arguments[1] == true);

    else {
       return reAlphanumeric.test(s)
    }
}
function reformat (s)

{   var arg;
    var sPos = 0;
    var resultString = "";

    for (var i = 1; i < reformat.arguments.length; i++) {
       arg = reformat.arguments[i];
       if (i % 2 == 1) resultString += arg;
       else {
           resultString += s.substring(sPos, sPos + arg);
           sPos += arg;
       }
    }
    return resultString;
}

function setDisplay(idsToDisplay, allIds, useHiddenClass)
{
    var id;
    for (var i = 0; i < allIds.length; i++)
    {
        id = allIds[i];
        var e = document.getElementById(id);
        if (idsToDisplay.indexOf(id) >= 0)
        {
            if (useHiddenClass)
            {
                e.className= '';
            }
            else
            {
                e.style.display= '';
            }
        }
        else
        {
            if (useHiddenClass)
            {
                e.className= 'x-hide-display';
            }
            else
            {
                e.style.display = 'none';
            }
        }
    }
}

//
// toggle_visibility('a','b','c',...)
//
function toggle_visibility()
{
    var len = toggle_visibility.arguments.length;
    for (var i = 0; i < len; i++)
    {
        var e = document.getElementById(toggle_visibility.arguments[i]);
        //var xe = Ext.get(e.id);
        if (e)
        {
            if (e.style.display=="none")
            {
                e.style.display="";
                //xe.fadeIn({duration: 0.4, useDisplay: true, easing: 'easeIn', remove: false});
            }
            else
            {
                e.style.display="none";
                //xe.fadeOut({duration: 0.4, useDisplay: true, easing: 'easeOut', remove: false});
            }
        }
    }
}


// isEmail (STRING s [, BOOLEAN emptyOK])
//
// Email address must be of form a@b.c -- in other words:
// * there must be at least one character before the @
// * there must be at least one character before and after the .
// * the characters @ and . are both required
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isEmail (s)

{   if (isEmpty(s))
       if (isEmail.arguments.length == 1) return defaultEmptyOK;
       else return (isEmail.arguments[1] == true);

    else {
       return reEmail.test(s)
    }
}



function isYear (s)
{
    if (isEmpty(s))
       if (isYear.arguments.length == 1) return defaultEmptyOK;
       else return (isYear.arguments[1] == true);
    if (!isNonnegativeInteger(s)) return false;
    return ((s.length == 2) || (s.length == 4));
}



// isIntegerInRange (STRING s, INTEGER a, INTEGER b [, BOOLEAN emptyOK])
//
// isIntegerInRange returns true if string s is an integer
// within the range of integer arguments a and b, inclusive.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.


function isIntegerInRange (s, a, b)
{   if (isEmpty(s))
       if (isIntegerInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isIntegerInRange.arguments[1] == true);

    // Catch non-integer strings to avoid creating a NaN below,
    // which isn't available on JavaScript 1.0 for Windows.
    if (!isInteger(s, false)) return false;

    // Now, explicitly change the type to integer via parseInt
    // so that the comparison code below will work both on
    // JavaScript 1.2 (which typechecks in equality comparisons)
    // and JavaScript 1.1 and before (which doesn't).
    var num = parseInt (s, 10);
    return ((num >= a) && (num <= b));
}



// isMonth (STRING s [, BOOLEAN emptyOK])
//
// isMonth returns true if string s is a valid
// month number between 1 and 12.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isMonth (s)
{   if (isEmpty(s))
       if (isMonth.arguments.length == 1) return defaultEmptyOK;
       else return (isMonth.arguments[1] == true);

    return isIntegerInRange (s, 1, 12);
}



// isDay (STRING s [, BOOLEAN emptyOK])
//
// isDay returns true if string s is a valid
// day number between 1 and 31.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isDay (s)
{   if (isEmpty(s))
       if (isDay.arguments.length == 1) return defaultEmptyOK;
       else return (isDay.arguments[1] == true);
    return isIntegerInRange (s, 1, 31);
}



// daysInFebruary (INTEGER year)
//
// Given integer argument year,
// returns number of days in February of that year.

function daysInFebruary (year)
{   // February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}



// isDate (STRING year, STRING month, STRING day)
//
// isDate returns true if string arguments year, month, and day
// form a valid date.
//

function isDate (year, month, day)
{   // catch invalid years (not 2- or 4-digit) and invalid months and days.
    if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false))) return false;

    // Explicitly change type to integer to make code work in both
    // JavaScript 1.1 and JavaScript 1.2.
    var intYear = parseInt(year, 10);
    var intMonth = parseInt(month, 10);
    var intDay = parseInt(day, 10);

    // catch invalid days, except for February
    if (intDay > daysInMonth[intMonth]) return false;
    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) return false;

    return true;
}




/* FUNCTIONS TO NOTIFY USER OF INPUT REQUIREMENTS OR MISTAKES. */

// Notify user that required field theField is empty.
// String s describes expected contents of theField.value.
// Put focus in theField and return false.

function warnEmpty (theField, s)
{
    // since theField could be hidden as well!
    if (theField.type == "text")
    {
        theField.focus();
    }
    alert(mPrefix + s + mSuffix);
    return false;
}



// Notify user that contents of field theField are invalid.
// String s describes expected contents of theField.value.
// Put select theField, pu focus in it, and return false.

function warnInvalid (theField, s)
{   theField.focus()
    theField.select()
    alert(s)
    return false
}

// Notify user that contents of the field has exceeded the max length
// of n characters.
// String s describes expected contents of theField.value.
// Put select theField, pu focus in it, and return false.

function warnLength(theField, s, n) {
    theField.focus()
    theField.select()
    alert('Field ' + s + ' has exceeded the maximum of ' + n + ' characters. Please shorten it and re-submit the form.')
    return false
}


/* FUNCTIONS TO INTERACTIVELY CHECK VARIOUS FIELDS. */

//
// checkConfirmFields (TEXTFIELD tf1, TEXTFIELD tf2, string s)
// check if the value in the two fields is the same
//

function checkConfirmFields(tf1, tf2, s) {
    if (tf1.value != tf2.value) {
        return warnInvalid(tf2, s + ' and Confirm ' + s + ' do not match.');
    }
    return true;
}

//
// checkStringLength (TEXTFIELD theField, STRING s, INTEGER n[, BOOLEAN emptyOK==false])
// check if string s is less than n chars
//
function checkStringLength (theField, s, n, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkStringLength.arguments.length == 3) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value) && emptyOK == false) {
        return warnEmpty (theField, s);
    }
    if (theField.value.length > n)
        return warnLength (theField, s, n);
    else return true;
}

//
// Arr : array of (TEXTFIELD, STRING, INTEGER max, emptyOK)
// Check if string is less than max and also empty or not depending on the
// value of emptyOK
//
function checkStringLengthInArr(l)
{
    for (var i = 0; i < l.length ; i++) {
        if (!checkStringLength(l[i][0], l[i][1], l[i][2], l[i][3])) {
            return false;
        }
    }
    return true;
}

// checkString (TEXTFIELD theField, STRING s, [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is not all whitespace.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function checkString (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkString.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value))
       return warnEmpty (theField, s);
    else return true;
}
// checkEmail (TEXTFIELD theField [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is a valid Email.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function checkEmail (theField, emptyOK)
{   if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else if (!isEmail(theField.value, false))
       return warnInvalid (theField, iEmail);
    else return true;
}



// Check that string theField.value is a valid Year.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function checkYear (theField, emptyOK)
{   if (checkYear.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isYear(theField.value, false))
       return warnInvalid (theField, iYear);
    else return true;
}


// Check that string theField.value is a valid Month.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function checkMonth (theField, emptyOK)
{   if (checkMonth.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isMonth(theField.value, false))
       return warnInvalid (theField, iMonth);
    else return true;
}


// Check that string theField.value is a valid Day.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function checkDay (theField, emptyOK)
{   if (checkDay.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isDay(theField.value, false))
       return warnInvalid (theField, iDay);
    else return true;
}



// checkDate (yearField, monthField, dayField, STRING labelString [, OKtoOmitDay==false])
//
// Check that yearField.value, monthField.value, and dayField.value
// form a valid date.
//
// If they don't, labelString (the name of the date, like "Birth Date")
// is displayed to tell the user which date field is invalid.
//
// If it is OK for the day field to be empty, set optional argument
// OKtoOmitDay to true.  It defaults to false.

function checkDate (yearField, monthField, dayField, labelString, OKtoOmitDay)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkDate.arguments.length == 4) OKtoOmitDay = false;
    if (!isYear(yearField.value)) return warnInvalid (yearField, iYear);
    if (!isMonth(monthField.value)) return warnInvalid (monthField, iMonth);
    if ( (OKtoOmitDay == true) && isEmpty(dayField.value) ) return true;
    else if (!isDay(dayField.value))
       return warnInvalid (dayField, iDay);
    if (isDate (yearField.value, monthField.value, dayField.value))
       return true;
    alert (iDatePrefix + labelString + iDateSuffix)
    return false
}



// Get checked value from radio button.

function getRadioButtonValue (radio)
{   for (var i = 0; i < radio.length; i++)
    {   if (radio[i].checked) { return radio[i].value; }
    }
    return null;
}

/////////////////////////////////////
// Form helper functions
/////////////////////////////////////

// form -- Form
// selectedElementName -- Name of select list element
// value -- Value of the selected elelment
function setSelector(selectedElement, value)
{
  var j = 0;
  var elem = selectedElement;
  if (elem != null) {
    for (j = 0; j < elem.options.length; j++) {
      if (elem.options[j].value == value) {
        elem.selectedIndex = j;
        return;
      }
    }
  } else {
    alert("No element " + selectedElementName + " found");
  }
}
function setSelected (form, selectedElementName, value) {
    var elem = findElement(form, selectedElementName);
    setSelector(elem, value);
}

function getSelectedValue (form, elementName) {
    var elem = findElement(form, elementName);
    if (elem != null) {
        return elem.options[elem.selectedIndex].value;
    } else {
        alert("No element " + elementName + " found");
    }
}

function getValue (form, elementName) {
    var elem = findElement(form, elementName);
    if (elem != null) {
        return elem.value;
    } else {
        alert("No element " + elementName + " found");
    }
}

/*
function findElement(form, elementName) {
    var len = form.elements.length;
    var i = 0;
    for (i = 0; i < len; i++) {
        if (form.elements[i].name == elementName) {
            return form.elements[i];
        }
    }
    return null;
}
*/

function findElement(form, elementName) {
        return form[elementName];
}

function setValue(form, elementName, value) {
    var elem = findElement(form, elementName);
    if (elem != null) {
        elem.value = value;
    } else {
        alert("No element " + elementName + " found");
    }
}

function submitAction(form) {
    var act = getSelectedValue(form, "actionLink");
    if (act == '') {
        alert("Please select an action");
        return false;
    }
    form.action = act;
    return true;
}

// This method is required to set the window.location.href property as
// it requires a fully qualified href
// href = action.pl?name=NGD
// returns : http://cvs.celoxis.com/cgi-bin/action.pl?name=NGD
//
function relativeToAbsolute (relative) {

    var proto = window.location.protocol;
    var host  = window.location.host;
    var base  = window.location.pathname;
    var npath = base.replace(/[^\/]+$/,relative);
    return proto + '//' + host + npath;
}
function doNothing() {}

function setPopupAsListActionTarget(form, cbox, name, h, w)
{
    if (checkListActionSelection(cbox))
    {
        popUp('about:blank', name, h, w);
        form.target=name;
        return true;
    }
    return false;

}
//
// A generic popup function to popup windows

// **************************************************
// IE : title must not have any special characters like spaces, so not used
// **************************************************
function popUp(url, title, h, w, options) {
  if (options == null || (trim(options) == "")) {
    options = "directories=no,scrollbars=yes,location=no,menubar=no,personalbar=no,resizable=yes,toolbar=no";
  }
  window.open(url, title, "width=" + w + ",height=" + h + "," + options);
}
function getRadioSelection(radio)
{
    var value = null;
    if (radio.length == null)
    {
       // not an array, happens when only one radio button exists
        if (radio.checked) {
            value = radio.value;
        }
    } else {
        for (var i = 0; i < radio.length; i++) {
            if (radio[i].checked) { value = radio[i].value; }
        }
    }
    return value;
}
function setRadioSelection(radio, value)
{
    if (radio.length == null)
    {
        if (radio.value == value)
        {
            radio.checked = true;
        }
        else
        {
            radio.checked = false;
        }
    }
    else
    {
        for (var i = 0; i < radio.length; i++) {
            radio[i].checked = false;
            if (radio[i].value == value) { radio[i].checked = true; }
        }
    }

}

function checkListActionSelection(cbox)
{
    return checkCheckboxSelection(cbox, 'Please select at least one item');
}
function checkSelectorSelection(select, s)
{
    var v = getSelectedValue(select.form, select.name);
    if (isEmpty(v))
    {
        alert("Value for " + s + " is required. Please make a selection");
        return false;
    }
    return true;
}

// Check if radio button is selected
function checkRadioSelection(radio, s, customMessage)
{
    var isChecked = false;
    if (radio.length == null)
    {
        // not an array, happens when only one radio button exists
        isChecked = radio.checked;
    } else {
        for (var i = 0; i < radio.length; i++) {
            if (radio[i].checked) { isChecked = true; }
        }
    }
    if (!isChecked) {
        if (customMessage && customMessage != '')
        {
            alert(customMessage);
        }
        else
        {
          if (!s)
          {
            alert("Please make a selection");
          }
          else
          {
             alert(s + " is a required field. Please make a selection");
          }
        }
        return false;
    }
    return true;
}

//
// A function to decode a string encoded as a:b:c where each is encoded using
// radix 36
//
function decodeInt(val, separator)
{
  var parts = val.split(separator);
  if (parts == null || parts.length == 0) return new Array(0);

  var ids = new Array(parts.length);
  for (var i = 0; i < parts.length; i++) {
    ids[i] = parseInt(parts[i], 36);
  }
  return ids;
}

//
// Sets the checkbox to be selected or unselected
// Useful when we need CheckAll/UncheckAll feature
//
function setCheckboxState(formName, elementName, checked)
{
    var form = document.forms[formName];
    var len = form.elements.length;
    var i=0;
    for(i=0; i<len; i++) {
      var element = form.elements[i];
      if (element.name == elementName) {
        element.checked = checked;
      }
    }
}

function checkCheckboxSelection(checkbox, message)
{
    var isChecked = false;
    if (checkbox.length)
    {
        for (var i = 0; i < checkbox.length; i++) {
            if (checkbox[i].checked) { isChecked = true; }
        }
    }
    else
    {
        // not an array, happens when only one checkbox button exists
        isChecked = checkbox.checked;
    }
    if (!isChecked) {
        if(message)
            alert (message);
        else
            alert("Please make a selection");
        return false;
    }
    return true;
}

//
// Returns an ARRAY of values
//
function getCheckboxSelection(formName,checkboxName)
{
    var ret = new Array();
    var form = document.forms[formName];
    var len = form.elements.length;
    var i=0;
    for(i=0; i<len; i++) {
      var element = form.elements[i];
      if (element.name == checkboxName)
      {
          if (element.checked)
          {
             ret.push(element.value);
          }
      }
    }
    return ret;
}

function doListAction(form, checkboxName, uri)
{
    if (!checkListActionSelection(form[checkboxName]))
    {
        return;
    }
    form.action=uri;
    form.submit();
}

////////////////////////////////////////////////////////////////////////


function getElementBy (elemTag)     // name OR id
        {
        var elem = document.getElementById (elemTag);

        if (elem)
            return elem;

        var elems = document.getElementsByName (elemTag);

        if (elems.length > 0)
            return elems[0];

        return null;
        }

    function closeElem(elemName)
        {
        var elem = getElementBy (elemName);

        if (elem)
            elem.style.display = "none";
        }

    function openElem(elemName)
        {
        var elem = getElementBy (elemName);

        if (elem)
            elem.style.display = "";
        }

    function openCloseElem(elemName, doOpen)
        {
        var elem = getElementBy (elemName);

        if (!elem)
            return false;

        if (doOpen)
            elem.style.display = "";
        else
            elem.style.display = "none";

        return doOpen;
        }

    function  toggleElem(elemName)
    {
        var elem = getElementBy (elemName);
        if (!elem)
            return false;
        if (elem.style.display == "none")
        {
            elem.style.display = "";
        }
        else
        {
            elem.style.display = "none";
        }
    }

    function hideShowElem(elemName, doShow)
        {
        if (doShow)
            getElementBy (elemName).style.visibility = "visible";
        else
            getElementBy (elemName).style.visibility = "hidden";
        }

    function hideElem(elemName)
        {
        getElementBy (elemName).style.visibility = "hidden";
        }

    function showElem(elemName)
        {
        getElementBy (elemName).style.visibility = "visible";
        }

function checkExpand(imgName, children)
{
  var parts = children.split(",");
  if (parts == undefined || parts == null || parts.length == 0) return;

  var img = getElementBy(imgName);
  var collapse = /.+minus.+/;
  //alert("Here ->" + img.src);
  if (collapse.test(img.src))
  {
    img.src = "images/fsplus.gif";
    for (var i = 0; i < parts.length; i++)
    {
      //alert("Hide ->" + parts[i]);
      var ch = getElementBy(parts[i]);
      var hv = getElementBy("__" + parts[i] + "_state");
      hv.value = "collapse";
      ch.style.display = "none";
    }
  }
  else
  {
    img.src = "images/fsminus.gif";
    for (var i = 0; i < parts.length; i++)
    {
      //alert("Unhide ->" + parts[i]);
      var ch = getElementBy(parts[i]);
      ch.style.display = "";
      var hv = getElementBy("__" + parts[i] + "_state");
      hv.value = "expand";
    }
  }
}


function loadOnConfirm(url, message)
{
    if (confirm(message))
    {
        window.location.href=url;
    }
}

CELOXIS.storeCookie = function(name, value, expires)
{
    var str = name + "=" + encodeURIComponent(value);
    if (expires) {
        str += '; expires=' + expires.toGMTString();
    }
    document.cookie = str;
}

CELOXIS.getCookie = function(name)
{
    var allcookies = document.cookie;
    var pos = allcookies.indexOf(name + "=");
    if (pos != -1) {
         var start = pos + name.length + 1;
         var end = allcookies.indexOf(";", start);
         if (end == -1) end = allcookies.length;
         var value = allcookies.substring(start, end);
         value = decodeURI(value);
         return value;
    }
    return null;
}

CELOXIS.getOS = function()
{
    if (Ext.isLinux)
    {
        return 'Linux';
    }
    else if (Ext.isWindows)
    {
        return 'Windows';
    }
    else if (Ext.isMac)
    {
        return 'Mac';
    }
    else
    {
        return 'Other';
    }
}

CELOXIS.getBrowser = function()
{
    if (Ext.isGecko)
    {
        if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent))
        {
            var ffversion=new Number(RegExp.$1)
            if (ffversion>=3)
            {
                return 'Firefox3';
            }
            else if (ffversion>=2)
            {
                return 'Firefox2';
            }
            else if (ffversion>=1)
            {
                return 'Firefox1';
            }
        }
        return 'Gecko';
    }
    else if (Ext.isSafari)
    {
        return 'Safari';
    }
    else if (Ext.isIE6)
    {
        return 'IE6';
    }
    else if (Ext.isIE7)
    {
        return 'IE7';
    }
    else if (Ext.isOpera)
    {
        return 'Opera';
    }
    return 'Unknown';
}


//
// Show the columns and hide the rest
//
function showColumnsAndHideRest(tableID, columnNumbers)
{
  var tbl  = document.getElementById(tableID);
  var rows = tbl.rows;
  var cels;
  for (var row=0; row<rows.length;row++)
  {
    cels = rows[row].cells;
    _showHideCols(cels, columnNumbers);
    /*
    cels = rows[row].getElementsByTagName('th')
    _showHideCols(cels, columnNumbers);
    */
  }
}

//
//helper function that hides the cells that dont belong to the column numbers
//
function _showHideCols(cels, columnNumbers)
{
    for (var col = 0 ; col < cels.length; col++)
    {
      if (columnNumbers.indexOf(col) >= 0)
      {
        cels[col].style.display='';
      }
      else
      {
        cels[col].style.display='none';
      }
    }
}

/*
   Adds an html hidden input field (dynamically created) to the given HTML form element.
   @param formElement the given HTML form element
   @param fieldName the name of the hidden input field
   @param fieldValue the (string) value of the hidden input field
*/
function addHiddenInputField(formElement, fieldName, fieldValue) {
   var e = Ext.get(formElement).createChild({'tag':'input', 'type':'hidden', 'name':fieldName, 'value': ''});
   e.dom.value = fieldValue;
   return e;
}

/*
 * Adds multiple hidden fields at once. All fields of fieldObject are added.
 */
function addHiddenInputFields(form, fieldObject)
{
  for (f in fieldObject)
  {
    addHiddenInputField(form, f, fieldObject[f]);
  }
}

/*
   Creates an html attribute.
   @param name the name of the attribute.
   @param value the (string) value of the attribute.
   @return the newly created html attribute
*/
function createHtmlAttribute(name, value) {
   var attribute = document.createAttribute(name)
   attribute.nodeValue = value
   return attribute
}

function removeDOMElement(element)
{
  element.parentNode.removeChild(element);
}
// removes all elements of a form
function removeFormElements(form)
{
  while(form.hasChildNodes())
  {
      form.removeChild(form.firstChild);
  }
}

/*
 * NOTE: We cannot call removeChild in the loop because
 * it affects the length and we are looping on that.
 */
function removeFormElementsByName(form, name)
{
    var nodesToRemove = new Array();
    for (var i = 0; i < form.elements.length; i++)
    {
        if (form.elements[i].name == name)
        {
            nodesToRemove.push(form.elements[i]);
        }
    }

    for (var i = 0; i < nodesToRemove.length; i++)
    {
      form.removeChild(nodesToRemove[i]);
    }
}
function getHiddenFieldValuesByName(form, name)
{
  var values = new Array();
  if (form != null)
  {
    for (var i = 0; i < form.elements.length; i++)
    {
        if (form.elements[i].name == name)
        {
            values.push(form.elements[i].value);
        }
    }
  }
  return values;
}

function submitThisPageWithForm(formName, params)
{
    var tpf = document.thisPageForm;
    if (formName != null)
    {
        var f = new Ext.form.BasicForm(document[formName]);
        var fields = f.getValues();
        replaceFormFields(tpf, fields);
    }
    if (params != null)
    {
        replaceFormFields(tpf, params)
    }
    tpf.submit();
}

function replaceFormFields(form, fields)
{
    if (!form) return;
    for (var key in fields)
    {
        if (form.elements[key])
        {
            removeFormElementsByName(form, key);
        }
        var value = fields[key];
        if (value == null || value == undefined)
        {
            value = '';
        }
        if (typeof(value) == "string")
        {
          addHiddenInputField(form, key, value);
        }
        else
        {
            Ext.each(value, function(item, index, all) {
                addHiddenInputField(form, key, item);
            });
        }
    }
}


// generates a 6 digit random number
function randomNumber()
{
    return Math.round(1000000*Math.random());
}
function randomString()
{
    return "x" + randomNumber();
}

// --------------------- String Buffer Class ------------------------
function StringBuffer() {
this.buffer = [];
}

StringBuffer.prototype.append = function append(string) {
this.buffer.push(string);
return this;
};

StringBuffer.prototype.toString = function toString() {
  return this.buffer.join("");
};

/* Example of String Buffer var buf = new StringBuffer(); buf.append("hello"); buf.append("world"); alert(buf.toString()); */

//____________________________________________________________________________
//
//  Date Text Box
//____________________________________________________________________________
//
var dtbReDate = /^\d(\d)?\/\d(\d)?\/(\d\d)?\d\d$/;
var dtbFormatUS = "MM/DD/YYYY";
var dtbFormatIN = "DD/MM/YYYY";
var dtbJSCFmtUS = "MM/DD/YY";
var dtbJSCFmtIN = "DD/MM/YY";
var dtbJSFmt = "DD Mon YY";
var dtbs  = new Object();
var changeToUSFmtMsg = 'To change format to ' + dtbFormatUS + ', edit your profile.';
var changeToINFmtMsg = 'To change format to ' + dtbFormatIN + ', edit your profile.';
var changeToUSFmtMsgWithTime = 'To change format to ' + dtbFormatUS + ' hh:mm ' + ', edit your profile.';
var changeToINFmtMsgWithTime = 'To change format to ' + dtbFormatIN + ' hh:mm ' + ', edit your profile.';

function dtb_validate (props)
{
    datetextfield = props['if'];
    if (!datetextfield)
    {
        datetextfield = document.getElementById(props['ifId']);
        props['if'] = datetextfield;
    }
    hiddenfield = props['hf'];
    if (!hiddenfield)
    {
        hiddenfield = document.getElementById(props['hfId']);
        props['hf'] = hiddenfield;
    }
    label = props['label'];
    isUSStyle = props['isUSStyle'];
    not_before_label = props['notBeforeLabel'];
    not_before = props['notBeforeDate'];
    not_after_label = props['notAfterLabel'];
    not_after = props['notAfterDate'];

    _dtb_clear_hidden(hiddenfield);

    var d = _dtb_get_date(props);
    if (typeof d == "boolean")
    {
        // must be false
        datetextfield.focus();
        return false;
    }

    if (d == null || d == "")
    {
        return true;
    }
    _dtb_set_hidden(hiddenfield, d.getDate(), (d.getMonth() + 1), d.getFullYear(), d.getHours(), d.getMinutes());

    if (not_before != null && d.getTime() < not_before.getTime()) {
        alert (label + ' has to be after ' + not_before_label + ': ' + formatDate(not_before, dtbJSFmt));
        return false;
    }
    if (not_after != null && d.getTime() > not_after.getTime()) {
        alert (label + ' has to be before ' + not_after_label + ': ' + formatDate(not_after, dtbJSFmt));
        return false;
    }
    return true;
}

function _dtb_hf_id(name)
{
    return "id_" + name;
}
function _dtb_if_id(name)
{
    return "id__" + name;
}
function dtb_set_date(name, d, m, y, hh, min)
{
    hfid = _dtb_hf_id(name);
    _dtb_set_hidden(document.getElementById(hfid), d, m, y, hh, min);
}

// e.g. dtb_get_date ('p_deadline', 'Deadline', false)
// if valid date, returns a Date object, else if empty, returns null
// if invalid date, alerts the user and returns false
function dtb_get_date (name, label, isWithTime)
{
    hfId = _dtb_hf_id(name);
    ifId = _dtb_if_id(name);
    props = new Array();
    props['hf'] = document.getElementById(hfId);
    props['if'] = document.getElementById(ifId);
    props['isWithTime'] = isWithTime;
    props['isUSStyle'] = _dynarch_popupCalendar_isUSStyle;
    props['label'] = label;
    return _dtb_get_date(props);
}

// if valid date, returns a Date object, else if empty, returns null
// if invalid date, alerts the user and returns false
function _dtb_get_date (props)
{
    datetextfield = props['if'];
    hiddenfield = props['hf'];
    isUSStyle = props['isUSStyle'];
    isWithTime = props['isWithTime'];
    label = props['label'];

    if (isUSStyle)
    {
        fmt = dtbFormatUS;
        if(isWithTime)
        {
            changeFmt = changeToINFmtMsgWithTime;
        }
        else
        {
            changeFmt = changeToINFmtMsg;
        }
    } else {
        fmt = dtbFormatIN;
        if(isWithTime)
        {
            changeFmt = changeToUSFmtMsgWithTime;
        }
        else
        {
            changeFmt = changeToUSFmtMsg;
        }
    }

    //var s = datetextfield.value.replace(/\s/g, '');
    //datetextfield.value = s;
    var soriginal = datetextfield.value;
    s = soriginal.replace(/[.-]/g, '/');
    if (s.length == 0)
    {
        hiddenfield.value='';
        return null;
    }

    var y, m, d, hours, min;
    var valid = false;

    if(isWithTime)
    {
        var dtbReDateWithTime = /^(\d\d?)\/(\d\d?)\/(\d?\d?\d\d)\s*(\d*):?(\d*)\s*([apPA][mM])?\s*$/;

        if (! dtbReDateWithTime.test(s))
        {
            alert (label + ': format is invalid, it should be ' + fmt + ' hh:mm' + '\n' + changeFmt);
            return false;
        }

        var array = dtbReDateWithTime.exec(s);
        if (isUSStyle)
        {
            y = array[3];
            m = array[1];
            d = array[2];
        } else
        {
            y = array[3];
            m = array[2];
            d = array[1];

        }
        hours = array[4];
        min = array[5];
        ampm = array[6];

        if(ampm == "aM" || ampm == "am" || ampm == "AM" || ampm == "Am")
        {
            ampm = "AM";
        }
        else if(ampm == "pM" || ampm == "pm" || ampm == "PM" || ampm == "Pm")
        {
            ampm = "PM";
        }
        else
        {
            ampm = "";
        }

        if(hours == "")
        {
            hours = "00";
        }

        if(min == "0")
        {
            min = "00";
        }

        var validTime = _dtb_validate_time(hours, min);
        if(!validTime) return;
        if(ampm == "PM" && hours < 12)
        {
            hours = parseInt(hours) + 12;
        }
    }
    else
    {
        var dtbReDate = /^(\d\d?)\/(\d\d?)\/(\d?\d?\d\d)$/;
        if (! dtbReDate.test(s))
        {
            if (label)
            {
            alert (label + ': format is invalid, it should be ' + fmt + '\n' + changeFmt);
            }
            else
            {
                alert ('Format is invalid, it should be ' + fmt + '\n' + changeFmt);
            }
            return false;
        }
        var array = dtbReDate.exec(s);
        if (isUSStyle)
        {
            y = array[3];
            m = array[1];
            d = array[2];
        } else
        {
            y = array[3];
            m = array[2];
            d = array[1];
        }
        hours = "00";
        min = "00";
    }

    if (y.length == 2) { y = '20' + y };

    valid = isDate(y, m, d);
    if (!valid) {
        if (label)
        {
          alert (label + ' is not a valid date. Format is ' + fmt + '\n' + changeFmt);
        }
        else
        {
          alert ('Not a valid date. Format is ' + fmt + '\n' + changeFmt);
        }
        return false;
    }
    // js month is from 0 to 11
    // alert("y:" + y + " m:" + m + " d:" + d);
    var d = new Date(parseInt(y, 10), parseInt(m, 10) - 1, parseInt(d, 10), hours, min, 0, 0);
    return d;
}

// sets the hidden value
function _dtb_clear_hidden(hiddenField)
{
    hiddenField.value = '';
}
function _dtb_set_hidden(hiddenField, d, m, y, hh, min)
{
    var mm = parseInt(m, 10);
    var dd = parseInt(d, 10);
    var yy = parseInt(y, 10);
    var mms = mm + '';
    var dds = dd + '';
    var yys = yy + '';

    //
    // pad with zeros if necessary
    //
    if (mm < 10) {
        mms = '0' + mm;
    }
    if (dd < 10) {
        dds = '0' + dd;
    }
    hiddenField.value = mms + '/' + dds + '/' + yys + ' ' + hh + ':' + min;
    //alert(hiddenField.value);
}
function dtb_calendarCallback(outDate, field)
{
    field.value = outDate;
    dtb_validate(field);
}
function _dtb_validate_time(hour,min)
{
    if(hour > 24 || hour < 0 || hour.length > 2)
    {
        alert("Please enter hours less than 24. e.g 2 or 21");
        return false;
    }
    if(min > 59 || min < 0 || min.length > 2)
    {
        alert("Please enter minutes less than 60. e.g 59 or 00");
        return false;
    }
    return true;
}
//
// This function shows the calendar under the element having the given id.
// It takes care of catching "mousedown" signals on document and hiding the
// calendar if the click was outside.
//
var _dynarch_popupCalendarNoTime = null;
var _dynarch_popupCalendarWithTime = null;
var _dynarch_popupCalendar_dateOnlyFormat = '%Y';
var _dynarch_popupCalendar_dateTimeFormat = '%Y';
var _dynarch_popupCalendar_isUSStyle = false;

function dtb_showCalendar(props)
{
  var el = document.getElementById(props['ifId']);
  var hel = document.getElementById(props['hfId']);
  var isCalendarWithTime = props['isCalendarWithTime'];
  var isWithTime = props['isWithTime'];
  var currCal = null;
  if (isCalendarWithTime)
  {
    currCal = _dynarch_popupCalendarWithTime;
  }
  else
  {
    currCal = _dynarch_popupCalendarNoTime;
  }
  props['isUSStyle'] = _dynarch_popupCalendar_isUSStyle;
  props['if'] = el;
  props['hf'] = hel;
  if (currCal != null)
  {
    //
    // we already have some calendar created
    //
    currCal.hide();  // so we hide it first.
  }
  else
  {
    // first-time call, create the calendar.
    var cal = new Calendar(1, null, dtb_selectedDate, dtb_closeCalendar);
    cal.weekNumbers = false;
    cal.showsOtherMonths = true;
    cal.setRange(1900, 2020); // min/max year allowed.
    if (isCalendarWithTime)
    {
      cal.showsTime = true;
      cal.timeFormat = "12";
    }

    if (isWithTime)
    {
      cal.setDateFormat(_dynarch_popupCalendar_dateTimeFormat);
    }
    else
    {
      cal.setDateFormat(_dynarch_popupCalendar_dateOnlyFormat);
    }

    cal.create();
    cal.setFirstDayOfWeek(_dynarch_popupCalendar_firstDayOfWeek);
    currCal = cal;
  }

  if (isCalendarWithTime)
  {
    _dynarch_popupCalendarWithTime = currCal;
  }
  else
  {
    _dynarch_popupCalendarNoTime = currCal;
  }
  currCal.props = props;
  currCal.parseDate(el.value); // try to parse the text in field
  currCal.sel = el; // inform it what input field we use
  currCal.showAtElement(el, "Br"); // show the calendar
  return false;
}
// This function gets called when the end-user clicks on some date.
function dtb_selectedDate(cal, date)
{
  var f = cal.props['onSelectDate'];
  if (f)
  {
      date = f(cal, date);
  }
  cal.sel.value = date; // just update the date in the input field.
  if (cal.dateClicked)
  {
    // if we add this call we close the calendar on single-click.
    // just to exemplify both cases, we are using this only for the 1st
    // and the 3rd field, while 2nd and 4th will still require double-click.
    cal.callCloseHandler();
  }
}
function dtb_closeCalendar(calendar)
{
    calendar.hide();
    calendar.props['if'].focus();
    dtb_validate(calendar.props);
}
//____________________________________________________________________________
//
//  ADVANCED CEHCK BOX
//____________________________________________________________________________
//
var ischecked = new Object();
function cb_setTF (field,hidden)
{
    ischecked = field.checked
    if (ischecked)
    {
        hidden.value = true
    }
    else
    {
        hidden.value = false
    }
}

//___________________________________________________________________________
//
// SELECTOR AS CHECK BOXES -- Any handler
//___________________________________________________________________________
function any_cb(element)
{
    var anyVal = '';
    var len = element.form.elements.length;
    if (!element.checked)
        return;
    if (element.value == anyVal) // if Any was selected
    {
        // uncheck all except Any
        for (var i = 0; i < len; i++)
        {
          var e = element.form.elements[i];
          if (e.name == element.name && e.checked && e.value != anyVal)
          {
              e.checked = false;
          }
        }
    }
    else if (element.value != anyVal) // if other than any was selected
    {
        // uncheck only Any
        for (var i = 0; i < len; i++)
        {
          var e = element.form.elements[i];
          if (e.name == element.name && e.value == anyVal)
          {
              e.checked = false;
              return;
          }
        }
    }
}
//____________________________________________________________________________
//
//  A convenient function that makes a bunch of checkBoxes behave like
//  Radio buttons. Such functionality is required because once a radio
//  button is selected, it cannot be unselected. Check boxes can.
//  Arguments
//  formName: Name of the form
//  checkBoxNames: The first name is that of the one to be checked
//                 The others are unchecked.
//____________________________________________________________________________
// toggleCheckBox (STRING formName, String check, String uncheck [, String unche ck])
function toggleCheckBox(formName, check, uncheck) {
    var f = document.forms[formName];
    for (var i = 1; i < toggleCheckBox.arguments.length; i++) {
        var box = findElement(f, toggleCheckBox.arguments[i]);
        if (i == 1 && box.checked) {
          box.checked = true;
        } else {
          box.checked = false;
        }
    }
}
//____________________________________________________________________________
//
//  Move the selected item from fromField select list to toField select list
//____________________________________________________________________________

var sets = new Array();
function set_register(field)
{
    sets[sets.length] = field;
}

function set_selectRegistered()
{
    var field;
    for (var i = 0; i < sets.length; i++)
    {
    set_selectAll(sets[i]);
    }
}

function set_selectAll(field)
{
    var sz = field.options.length;
    for (var i = 0; i < sz; i++)
    {
    field.options[i].selected=true;
    }

}
function set_move (fromField, toField)
{
    var toMoveIndex = fromField.selectedIndex;
    if (toMoveIndex < 0)
    {
      alert("Please select an item to move");
      return;
    }

  var txt = fromField.options[toMoveIndex].text;
  var id = fromField.options[toMoveIndex].value;
  fromField.options[toMoveIndex] = null;

  var toSize = toField.options.length;
  toField.options[toSize] = new Option (txt, id, false, false);
  if (fromField.options.length > 0) {
    if (toMoveIndex != 0) {
      fromField.selectedIndex = toMoveIndex - 1;
    } else {
      fromField.selectedIndex = 0;
    }
  }
  toField.selectedIndex = toField.options.length -1 ;
}
//_____________________________________________________________________
//
var section_img_section_registry = new Object();
var section_section_img_registry = new Object();
var section_img_registry = new Object();
var section_close_later_registry = new Array();
var section_img_array = new Array();
var section_img_registry_pos = 0;
// function section_register(imgID [, sectionId1, sectionId2, ...])
function section_register(imgID)
{
    section_img_array.push(imgID);
    section_img_registry[imgID] = section_img_registry_pos;
    section_img_registry_pos++;
    var isr = section_img_section_registry[imgID];
    if (typeof(isr) == 'undefined')
    {
        isr = new Array();
        section_img_section_registry[imgID] = isr;
    }
    for (var i = 1; i < section_register.arguments.length; i++)
    {
        var sect = section_register.arguments[i];
        isr[isr.length] = sect;
        var sir = section_section_img_registry[sect];
        if (typeof(sir) == 'undefined')
        {
            sir = new Array();
            section_section_img_registry[sect] = sir;
        }
        sir[sir.length] = imgID;
    }
}

function section_get_open()
{
    var out = new Array();
    var v;
    for (var i = 0; i < section_img_array.length; i++)
    {
        v = section_img_array[i];
        if (section_is_open(v))
        {
            out.push(v);
        }
    }
    return out;
}

function section_close_later(imgID)
{
    section_close_later_registry.push(imgID);
}

function section_close_saved()
{
    for (var i = 0; i < section_close_later_registry.length; i++)
    {
        section_do(section_close_later_registry[i], false);
    }

    section_close_later_registry = new Array();
}

function section_is_open(imgID)
{
    var img = document.getElementById(imgID);
    return img.src == shs_imageOpen.src;
}
function section_showhide(imgID)
{
    section_do(imgID, !section_is_open(imgID));
}

function section_open()
{
    var x = section_open.arguments;
    for (var i = 0; i < x.length; i++)
    {
        section_do(x[i], true);
    }
}
function section_close()
{
    var x = section_close.arguments;
    for (var i = 0; i < x.length; i++)
    {
        section_do(x[i], false);
    }
}
function section_do(imgID, toOpen)
{
    var newImgSrc = shs_imageClose.src;
    if (toOpen)
    {
        newImgSrc = shs_imageOpen.src;
    }

    var sections = section_img_section_registry[imgID];
    var myImgIndex = section_img_registry[imgID];
    if (typeof(sections) != 'undefined')
    {
        for (var i = 0; i < sections.length; i++)
        {
            //
            // decide whether to open
            // open only those sections that are immediately contained
            // in this img
            // for closing: close everything below
            //
            var imgs = section_section_img_registry[sections[i]];
            if (typeof(imgs) != 'undefined')
            {
                var lastimgID = imgs[imgs.length -1];
                if (!toOpen || lastimgID == imgID)
                {
                  openCloseElem(sections[i], toOpen);
                  for (var j = 0; j < imgs.length; j++)
                  {
                      var tmpImgIndex = section_img_registry[imgs[j]];
                      if (tmpImgIndex >= myImgIndex)
                      {
                        var tmpimg = document.getElementById(imgs[j]);
                        if (tmpimg)
                        {
                          tmpimg.src = newImgSrc;
                        }
                      }
                  }
                }
            }
        }
    }
}

//____________________________________________________________________________
//
//  PERIOD SELECTOR
//____________________________________________________________________________
//
function relativeChanged(relId, durationId, unitId)
{
   var relSel = document.getElementById(relId);
   var durationSel = document.getElementById(durationId);
   var unitSel = document.getElementById(unitId);
   var sel = relSel.options[relSel.selectedIndex].value;
   if (sel == 0) // Any
   {
       //durationSel.selectedIndex = 0;
       durationSel.style.visibility = "hidden";
       //unitSel.selectedIndex = 0;
       unitSel.style.visibility = "hidden";
   }
   else if (sel == 1) // This
   {
       //durationSel.selectedIndex = 1;
       durationSel.style.visibility = "hidden";
       unitSel.style.visibility = "visible";
   }
   else
   {
       durationSel.style.visibility = "visible";
       unitSel.style.visibility = "visible";
   }
}


// Handy functions
noop = function(){}
function noerror() { return true; }

function dualSelOrder(down, col)
{
  sl = col.selectedIndex;
  if (sl != -1 && col.options[sl].value > "") {
    oText = col.options[sl].text;
    oValue = col.options[sl].value;
    if (col.options[sl].value > "" && sl > 0 && down == 0) {
      col.options[sl].text = col.options[sl-1].text;
      col.options[sl].value = col.options[sl-1].value;
      col.options[sl-1].text = oText;
      col.options[sl-1].value = oValue;
      col.selectedIndex--;
    } else if (sl < col.length-1 && col.options[sl+1].value > "" && down == 1) {      col.options[sl].text = col.options[sl+1].text;
      col.options[sl].value = col.options[sl+1].value;
      col.options[sl+1].text = oText;
      col.options[sl+1].value = oValue;
      col.selectedIndex++;
    }
    //doSub();
    setHiddenValue(col);
  } else {
    alert("Please select a value first");
  }
}

function dualSelMove(source, target)
{
  var sourceOptions = source.options;
  var targetOptions = target.options;

  var targetIndex = target.selectedIndex;
  var offset = 0;
  var changed = false;
  for (var i = 0; i < sourceOptions.length; i++)
  {
    var option = sourceOptions[i];
    if (option.selected)
    {

       //if (navigator.family == 'nn4' || navigator.family == 'nn5' || navigator.family == 'gecko')
       if (Ext.isGecko || Ext.isSafari)
       {
           // Can't share options between selects in NN4
           var newOption = new Option(option.text, option.value, false, true);
           sourceOptions[i] = null;
           // Always added to end in NN4
           targetOptions[targetOptions.length] = newOption;
       }
       else
       {
         sourceOptions.remove(i);
         if (targetIndex < 0)
           targetOptions.add(option);
         else
           targetOptions.add(option, targetIndex + offset++);
      }

      i--;
      changed = true;
    }
  }

  if (changed)
  {
      setHiddenValue(source);
      setHiddenValue(target);
  }
}

function dualSelDelete(col)
{
  req = "";
  sl = col.selectedIndex;
  if (sl != -1 && col.options[sl].value > "") {
    if (req.indexOf(col.options[sl].value) > -1) {
      alert ("You may not delete a required value.");
    } else {
      if (confirm("This will delete the selected value.")) {
        if (col.options[sl].value!=".none") {
          if (col.length==1) {
            col.options[0].text="";
            col.options[0].value=".none";
          } else {
            col.options[sl]=null;
          }
          //doSub();
          setHiddenValue(col);
        } else {
          alert("Please select a value first");
        }
      }
    }
  }
}

function doSub()
{
  for (i=0; i < dualSelectors.length; i++)
  {
    col = dualSelectors[i];
    // the L_ and R_ prefixes
    hcol = dualSelectors[i].name.substr(2);
    form = col.form;
    form[hcol].value = makeList(col);
  }
  return true;
}

function setHiddenValue(col)
{
    form = col.form;
    // the L_ and R_ prefixes
    hcol = form[col.name.substr(2)];
    val = "";
    for (j=0; j<col.length; j++)
    {
        if (val > "") { val += ","; }
        if (col.options[j].value > "") val += col.options[j].value;
    }
    hcol.value = val;
}

function makeList(col)
{
  val = "";
  for (j=0; j<col.length; j++) {
    if (val > "") { val += ","; }
    if (col.options[j].value > "") val += col.options[j].value;
  }
  return val;
}

//____________________________________________________________________________
//
//  TIME TEXTBOX
//  components is an optional inout paramter which contains the hours/min
//____________________________________________________________________________
//
function timeTextBoxVerify(field, sep, components)
{
  if (field.value == "")
  {
    return true;
  }

  var hours = fieldToHours(field, sep, components);
  if (hours < 0)
  {
    return false;
  }

  return true;

}

function fieldToHours(field, sep, components)
{
  var hours = stringToHours(field.value, sep, components);
  if (hours < 0)
  {
    alert("Invalid time '" + field.value + "'.\nEnter time as HH:MM. For example, enter 3:45 for 3 hours and 45 minutes.");
    return -1;
  }
  return hours;
}

function stringToHours(strhrs, sep, components)
{
  var tokens = strhrs.split(sep);
  var hours = 0;
  var minutes = 0;

  if (tokens.length >= 1 && tokens[0].length > 0)
  {
    isInteger(tokens[0]) != true ? hours = -1 : hours = tokens[0];
  }

  if (tokens.length >= 2 && tokens[1].length > 0)
  {
    isInteger(tokens[1]) != true ? minutes = -1 : minutes = tokens[1];
  }

  // alert("hour = " + hours + " min=" + minutes);
  if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 24 || minutes < 0 || minutes > 60)
  {
      return -1;
  }

  if (components != undefined)
  {
    components[0] = hours;
    components[1] = minutes;
    //alert(components[0] + " " + components[1]);
  }
  return (Number(hours) + (Number(minutes) / 60));
}

function hoursToString(n)
{
    var hours = Math.floor(n);
    var minutes = Math.round((n - hours) * 60);
    if (minutes == 60)
    {
        hours ++; minutes = 0;
    }
    if (minutes < 10)
    {
        return String(hours + ":" + "0" + minutes);
    }
    else
    {
        return String(hours + ":" + minutes);
    }
}


//________________________________________________________________________
// Load images for section hide/open
//________________________________________________________________________
var shs_imageOpen = new Image();
shs_imageOpen.src = 'images/collapsibleList/nolines_minus.gif';
var shs_imageClose = new Image();
shs_imageClose.src = 'images/collapsibleList/nolines_plus.gif';

//________________________________________________________________________
//
// WATCHER FUNCTIONS
//________________________________________________________________________
function selectAction(name, what)
{
  e = getElementBy(name);
  if (e.options[e.selectedIndex].value && e.options[e.selectedIndex].value != '')
  {
    window.location.href=e.options[e.selectedIndex].value;
  }
  else
  {
     alert('Please select ' + what);
  }
}
function selectListAction(name, what)
{
  e = getElementBy(name);
  if (e.options[e.selectedIndex].value && e.options[e.selectedIndex].value != '')
  {
    eval(e.options[e.selectedIndex].value);
  }
}

function watcher_bulk_remove(formName, checkboxName, objectType)
{
    var ids = getCheckboxSelection(formName, checkboxName);
    CELOXIS.watch(ids, objectType, "remove");
}

function watcher_bulk_add(formName, checkboxName, objectType)
{
    var ids = getCheckboxSelection(formName, checkboxName);
    CELOXIS.watch(ids, objectType, "add");
}
// action is one of add or remove
CELOXIS.watch = function(id, type, action, cb)
{
    var params = new Object();
    params.p_object_id = id;
    params.p_object_type = type
    if (!cb) { cb = noop; }
    CELOXIS.jsonConfirm({
        url: 'watcher.do?bxn=' + action + '.json',
        params: params,
        callback: cb
    });
}

function cx_sortBy(colName, colVal, orderName, orderVal)
{
    var o = new Object();
    o[colName] = colVal;
    o[orderName] = orderVal;
    submitPage(o);
}

/////////////////////////////////////////////////////////////

function ganttMove(formname, ganttstartpn, d, m, y, h, min)
{
  dtb_set_date(ganttstartpn, d, m, y, h, min);
  document[formname].submit();
}
function ganttShift(formname, date_pn, ms)
{
    var d = new Date(ms);
    // note the +1 is for Java
    dtb_set_date(date_pn, d.getDate(), d.getMonth() + 1, d.getFullYear(), 0, 0);
    document[formname].submit();
}



function selectTab(tabContainerID, selectedTabID)
{
    var c = Ext.get(tabContainerID);
    var selectedTab = Ext.get(c.query("li.current")[0]);
    selectedTab.removeClass("current");
    selectedTab = Ext.get(selectedTabID);
    selectedTab.addClass("current");
}

function MultiSelector( list_target, max, paramNamePrefix ){

    // Where to write the list
    this.list_target = list_target;
    // How many elements?
    this.count = 0;
    // How many elements?
    this.id = 0;
    // Is there a maximum?
    if( max ) {
        this.max = max;
    } else {
        this.max = -1;
    }
    this.names = new Object();
    this.paramNamePrefix = paramNamePrefix;
    list_target.selection = new Array();

    /**
     * Add a new file input element
     */
    this.addElement = function( element ){

        // Make sure it is a file input element
        if( element.tagName == 'INPUT' && element.type == 'file' ){

            this.id++;
            // Element name -- what number am I?
            element.name = this.paramNamePrefix + this.id;
            //alert(element.name);

            // Add reference to this object
            element.multi_selector = this;

            // What to do when a file is selected
            element.onchange = function(){

                // check if already in the list
                if (this.multi_selector.names[element.value])
                {
                    alert('This file is already in the list');
                    this.value = '';
                    return false;
                }

                if (this.multi_selector.max > 0 && this.multi_selector.count > this.multi_selector.max)
                {
                    alert('Cannot upload more than ' + this.multi_selector.max + ' at one time');
                    return false;
                }

                this.multi_selector.names[element.value] = 1;

                // New file input
                var new_element = document.createElement( 'input' );
                new_element.type = 'file';
                new_element.className = 'input';
                new_element.size = 50;

                // Add new element
                this.parentNode.insertBefore( new_element, this );

                // Apply 'update' to element
                this.multi_selector.addElement( new_element );

                // Update list
                this.multi_selector.addListRow( this );

                // Hide this: cant use display:none because Safari doesnt like it
                this.style.position = 'absolute';
                this.style.left = '-1000px';

            };
            // If we have reached maximum number, disable input element
            if( this.max > 0 && this.count >= this.max ){
                element.disabled = true;
            };

            // File element counter
            this.count++;
            // Most recent element
            this.current_element = element;

        } else {
            // This can only be applied to file input elements!
            alert( 'Error: not a file input element' );
        };

    };

    /**
     * Add a new row to the list of files
     */
    this.addListRow = function( element ){

        // Row div
        var new_row = document.createElement( 'div' );

        // Row div
        var new_row = document.createElement( 'tr' );
        var new_col_filename = document.createElement( 'td' );
        var new_col_button = document.createElement( 'td' );

        new_col_filename.setAttribute( 'align', 'left');
        new_col_button.setAttribute( 'align', 'left');

        // Delete button
        /*
        var new_row_button = document.createElement( 'input' );
        new_row_button.type = 'button';
        new_row_button.value = 'Delete';
        */
        var new_row_button = document.createElement( 'img' );
        new_row_button.src = 'images/trash.gif';
        new_row_button.setAttribute( 'title', 'Delete');
        new_row_button.setAttribute( 'class', 'clickable');

        new_row.appendChild( new_col_button );
        new_row.appendChild( new_col_filename );
        // References
        new_row.element = element;

        // Delete function
        new_row_button.onclick= function(){

             // Remove row from table
             this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
             //alert(this.parentNode.parentNode.element.value);
             this.parentNode.parentNode.element.multi_selector.names[this.parentNode.parentNode.element.value] = 0;

             // Remove element from form
             this.parentNode.parentNode.element.parentNode.removeChild( this.parentNode.parentNode.element );

            // Decrement counter
            this.parentNode.parentNode.element.multi_selector.count--;

            // Re-enable input element (if it's disabled)
            this.parentNode.parentNode.element.multi_selector.current_element.disabled = false;

            // Appease Safari
            //    without it Safari wants to reload the browser window
            //    which nixes your already queued uploads
            return false;
        };

        // Set row value
        /*
        new_row.innerHTML = element.value;
        new_row.appendChild(document.createTextNode("\u00a0"));
        // Add button
        new_row.appendChild( new_row_button );
        */
        var c = element.value.lastIndexOf('\/'); //For Unix, etc.
        if (c != -1)
            html = element.value.substring(c+1);
        else {
            var c = element.value.lastIndexOf('\\'); //Win
            if (c != -1)
                html = element.value.substring(c+1);
            else
                html = element.value;
        }
        new_col_filename.innerHTML = html;
        new_col_button.appendChild( new_row_button );

        // Add it to the list
        this.list_target.appendChild( new_row );

    };

};

function showHideCustomRange(rangeSelector, customRangeId)
{
  var customRange = document.getElementById(customRangeId);
  if (rangeSelector.getValue() != "CUSTOM")
  {
    customRange.style.visibility = 'hidden';
  }
  else
  {
    customRange.style.visibility = 'visible';
  }
}

CELOXIS.duration_types = new Object();
CELOXIS.duration_types.m='m';
CELOXIS.duration_types.minute='m';
CELOXIS.duration_types.minutes='m';

CELOXIS.duration_types.h='h';
CELOXIS.duration_types.hour='h';
CELOXIS.duration_types.hours='h';

CELOXIS.duration_types.d='d';
CELOXIS.duration_types.day='d';
CELOXIS.duration_types.days='d';

CELOXIS.duration_types.w='w';
CELOXIS.duration_types.week='w';
CELOXIS.duration_types.weeks='w';

CELOXIS.duration_types.mo='mo';
CELOXIS.duration_types.month='mo';
CELOXIS.duration_types.months='mo';

CELOXIS.duration_types.y='y';
CELOXIS.duration_types.year='y';
CELOXIS.duration_types.years='y';

//
// input string is like: 12 days?,12d, 14h?, 2 Weeks
// output is an object: with attrs: canonicalValue
//
CELOXIS.duration_regexp = new RegExp("^(\\d+\\.?\\d*)\\s*([a-zA-Z]*)\\s*([?]?)$");
CELOXIS.parseDuration = function(s)
{
    if (isWhitespace(s))
    {
        var o = new Object();
        o.canonicalValue = '';
        return o;
    }
    var rex = CELOXIS.duration_regexp;
    var m = rex.exec(s);
    if (m == null)
    {
        return null;
    }
    else
    {
        var o = new Object();
        var units = parseFloat(m[1]);
        if (m[2].length == 0)
        {
            m[2] = 'd';
        }
        var type = CELOXIS.duration_types[m[2].toLowerCase()];
        if (type == null)
        {
            return null;
        }
        var estSym = (m[3].length > 0? '?' : '');
        o.canonicalValue = units + type + estSym;
        o.units = units;
        o.type = type;
        o.est = m[3].length > 0;
        return o;
    }
}
CELOXIS.pred_regexp = new RegExp("^(A?\\d+)\\s*([+-]?)\\s*(.*)$");
CELOXIS.parsePredecessors = function(s)
{
    var rex = CELOXIS.pred_regexp;
    if (isWhitespace(s))
    {
        var o = new Object();
        o.canonicalValue = "";
        return o;
    }
    var preds = s.split(",");
    var ps;
    var o = new Object();
    var cvs = new Array();
    var cv;
    for (var i = 0; i < preds.length; i++)
    {
        ps = trim(preds[i]);
        var m = rex.exec(ps);
        if (m == null)
        {
            return null;
        }
        else
        {
            var id = m[1];
            var sym = m[2];
            if (isEmpty(sym)) { sym = '+' ; }
            var dur = m[3];

            cv = id;
            if (!isEmpty(dur))
            {
              d = CELOXIS.parseDuration(dur);
              if (d == null)
              {
                  return null;
              }
              cv = id + sym + d.canonicalValue;
            }
            cvs.push(cv);
        }
    }
    o.canonicalValue = cvs.join(', ');
    return o;
}

//
// matches strings like 100% or 25h and returns o.quantum and o.units
//
CELOXIS.ia_regexp = new RegExp("^\\s*(\\d+\\.?\\d*)\\s*([%h]?)\\s*$");
CELOXIS.parseIndividualAllocation = function(s)
{
    var rex = CELOXIS.ia_regexp;
    if (isWhitespace(s))
    {
        return null;
    }
    var m = rex.exec(s);
    if (m == null)
    {
        return null;
    }
    else
    {
        var o = new Object();
        o.quantum = parseFloat(m[1]);
        if (isEmpty(m[2]))
        {
            m[2] = '%';
        }
        o.units = m[2];
        return o;
    }
}

CELOXIS.namespace('CELOXIS.timeRange');
CELOXIS.timeRange.time_regexp = new RegExp("^\\s*(\\d{1,2})\\s*:\\s*(\\d{2})\\s*$");
CELOXIS.timeRange.MINUTES_IN_DAY = 24*60;
CELOXIS.timeRange.changed = false;
CELOXIS.timeRange.isChanged = function()
{
    return CELOXIS.timeRange.changed;
}
CELOXIS.timeRange.calculateTotal = function(wid, markWidgetAsChanged)
{
    var widget = CELOXIS.timeRange.ranges[wid];
    if (markWidgetAsChanged)
    {
        widget.changed = true;
        CELOXIS.timeRange.changed = true;
    }
    var intervals = widget.intervals;
    var sum = 0;
    for (var i = 0; i < intervals.length; i++)
    {
        var interval = intervals[i];

        var tbfrom = document.getElementById(interval.from);
        var tbto = document.getElementById(interval.to);

        if (isWhitespace(tbfrom.value) && isWhitespace(tbto.value))
        {
            // both are empty continue
            continue;
        }

        var from = null;
        var to = null;
        if (!isWhitespace(tbfrom.value))
        {
          var from = CELOXIS.timeRange.getTime(tbfrom.value);
          if (from == null)
          {
            alert('From is invalid:' + tbfrom.value);
            break;
          }
        }

        if (!isWhitespace(tbto.value))
        {
          var to = CELOXIS.timeRange.getTime(tbto.value);

          if (to == null)
          {
            alert('To is invalid:' + tbto.value);
            break;
          }
        }

        if (from == null || to == null)
        {
            // if any one field was left empty
            continue;
        }

        var fromMinutes = from.hh * 60 + from.mm;
        var toMinutes = to.hh * 60 + to.mm;
        if (fromMinutes > toMinutes)
        {
            alert('From should be less than To');
            break;
        }
        if (fromMinutes > CELOXIS.timeRange.MINUTES_IN_DAY ||
            toMinutes > CELOXIS.timeRange.MINUTES_IN_DAY)
        {
            alert('Time cannot be more than 24:00');
            break;
        }
        sum += toMinutes - fromMinutes;
    }

    var hh = Math.floor(sum/60);
    var mm = sum%60;

    //document.getElementById(widget.sumId).value = hh + ':' + String.leftPad(mm, 2, '0');

    Ext.get(widget.sumId).update(hh + ':' + String.leftPad(mm, 2, '0'));
    //document.getElementById(widget.sumId).value = hh + ':' + String.leftPad(mm, 2, '0');
}

CELOXIS.timeRange.getTime = function(s)
{
    var re = CELOXIS.timeRange.time_regexp;
    var m = re.exec(s);
    if (m == null)
    {
        return null;
    }
    var hh = parseInt(m[1]);
    var mm = parseInt(m[2]);
    var o = new Object();
    o.hh = hh;
    o.mm = mm;
    return o;
}

CELOXIS.namespace('util');
CELOXIS.util.blankWhenEmpty = function(s)
{
    if (isEmpty(s)) { return ''; }
    return s;
}

CELOXIS.namespace('feedback');

Ext.onReady(function() {
    CELOXIS.feedback.ELEMENT = Ext.get('ajaxfeedback');
    CELOXIS.feedback.ELEMENT.enableDisplayMode();
    CELOXIS.feedback.ELEMENT.position("absolute", 1000, 0, 0);
    Ext.Ajax.on('beforerequest', CELOXIS.feedback.showLoading);
    Ext.Ajax.on('requestcomplete', CELOXIS.feedback.clear);
    });

CELOXIS.feedback.show = function(message)
{
    CELOXIS.feedback.ELEMENT.update(message);
    var scroll = Ext.get(document.body).getScroll();
    CELOXIS.feedback.ELEMENT.setLeftTop(scroll.left, scroll.top);
    CELOXIS.feedback.ELEMENT.show();
}
CELOXIS.feedback.clear = function()
{
    CELOXIS.feedback.ELEMENT.hide();
}
CELOXIS.feedback.showLoading = function()
{
    CELOXIS.feedback.show('Loading...');
}

CELOXIS.feedback.showSaving = function()
{
    CELOXIS.feedback.show('Saving...');
}

CELOXIS.contentElement = function()
{
    var cb = Ext.get('container-box');
    return cb ? cb : Ext.get('container-content');
}
/////////////////////////////////////////////////////////////
CELOXIS.namespace('toaster');
CELOXIS.toaster.popup = function (s, isSuccess)
{
    var e = Ext.get('confirmation');
    var ec = Ext.get('confirmation-message');
    ec.removeClass(['success', 'error']);
    ec.addClass('success');
    ec.update(s);
    e.alignTo(CELOXIS.contentElement(), 'c-c');
    e.show().highlight().pause(1).fadeOut({duration: 1.5});
}



/*
 * converts all form data to an object. Returns empty object if form is null
 */
CELOXIS.formToObject = function(form)
{
  var allParams = new Object();
  form != null ? Ext.apply(allParams, Ext.urlDecode(Ext.Ajax.serializeForm(form))) : true;
  return allParams;
}

/*
 * A wrapper on Ext.urlDecode that only decodes if required.
 */
CELOXIS.urlDecode = function(p)
{
  if (typeof p === "string")
  {
      p = Ext.urlDecode(p);
  }
  return p;
}

/*
 * Function that creates a mask.
 * Indicator can be null (no mask), maskBody (masks full body),
 * maskDiv (masks only specified div) or simple (shows indicator in top left corner)
 * Returns: a mask object on which you should call hideMask() to hide the mask
 */
CELOXIS.mask = function(config)
{
  config = config || {};
  config = Ext.applyIf(config, {
      indicator: null,
      indicatorText: 'Loading...',
      divId: null
  });
  var mask = null;

  if (config.divId != null)
  {
    mask = {};
    mask.loadDiv = Ext.get('load-div');
    mask.loadDiv.alignTo(Ext.get(config.divId), 'c');
    mask.hideMask = function ()
      {
        this.loadDiv.setXY([-1000, -1000]);
      }
    return mask;
  }

  if (config.indicator == 'maskBody')
  {
    mask = Ext.getBody();
    mask.mask(config.indicatorText, 'x-mask-loading');
    //maskEl.setXY(maskEl.getCenterXY());
    mask.hideMask = mask.unmask;
    /*
      mask = Ext.MessageBox.wait(config.indicatorText, '', {
          width:240,
          progress:true,
          closable:false
      });
      mask.hideMask = mask.hide;
    */
  }
  else if (config.indicator == 'maskDiv')
  {
    mask = Ext.get(config.divId);
    mask.mask(config.indicatorText);
    mask.hideMask = mask.unmask;
  }
  else if (config.indicator == 'simple')
  {
  }
  else
  {
    mask = {};
    mask.hideMask = noop;
  }
  //mask.indicator = config.indicator;
  return mask;
}

CELOXIS.jsonConfirm = function(config)
{
  config.showConfirmation = true;
  //config.indicator = null;
  CELOXIS.json(config);
}

/*
 * Function that performs json requests.
 * It can handle success/error responses from the URL invoked
 * Specifically useful for submitting forms
 * For simple requests use CELOXIS.ajax
 * Can show confirmation messages, reload div on the page,
 * refresh the same page or even call a callback function with arguments specified
 */
CELOXIS.json = function(config)
{
  config = config || {};
  config = Ext.applyIf(config, {
      url: null, // the url to post to.
      form: null, // the form whose data is serialized and posted.
      showConfirmation: false,
      errorDivContainer: 'global-error-container',
      errorDivMsg: 'global-error-msg',
      replaceDiv: null,
      params: {}, // params to AJAX request.
      reloadDiv: null, // div to reload after successful request.
      reloadParams: {}, // params for reloading div.
      refreshPage: null, // whether to refresh page after json call.
      scripts: true,
      indicator: null,
      indicatorText: 'Loading...',
      callback: null,
      callback_args: null,
      successUrl: null,
      popupOpts: null,
      callerId: null
  });

  var allParams = CELOXIS.formToObject(config.form);
  Ext.apply(allParams, CELOXIS.urlDecode(config.params));

  var url = config.url;
  if (url == null)
  {
      url = this.config.form.action;
  }

  var mask = CELOXIS.mask({
    indicator: config.indicator,
    indicatorText: config.indicatorText
  });

  //
  // perform common cleanup of success/failure etc.
  //
  doCleanup = function() {
    mask.hideMask();
  }

  // clear the error div if exists
  if (config.errorDivContainer)
  {
      Ext.get(config.errorDivMsg).update('');
      Ext.get(config.errorDivContainer).setDisplayed(false);
  }
  allParams["json"] = true;


  Ext.Ajax.request({
      url : url,
      method: 'post',
      showLoadIndicator: false,
      //text: config.loadingText,
      params: allParams,
      success: function (result, request) {
          var jsonHeader = 'x' + result.getResponseHeader["Json-Success"];
          jsonHeader = jsonHeader.trim();
          var response = result.responseText;
          if (jsonHeader)
          {
              response = Ext.decode(response);
          }

          if (jsonHeader == 'x1')
          {
              // success
              //CELOXIS.feedback.clear();
              if (config.showConfirmation && !isEmpty(response.json.successMessage))
              {
                  CELOXIS.toaster.popup(response.json.successMessage);
              }

              if (config.replaceDiv)
              {
                  // update the div
                  //Ext.get(config.replaceDiv).getUpdater().showLoadIndicator = config.showLoading;
                  Ext.get(config.replaceDiv).update(response.text, config.scripts);
              }

              if (config.reloadDiv)
              {
                  // reload the div
                  config.reloadParams = Ext.applyIf(config.reloadParams, {params: {}});
                  config.reloadParams.params['ni.use_session'] = true;
                  updateEnclDivOrThisPage(config.reloadDiv, config.reloadParams);
              }

              if (config.refreshPage)
              {
                  //CELOXIS.feedback.showLoading();
                  //submitPage({}, null, config.form.name);
                  //document.thisPageForm.submit();
                  window.location.reload(true);
                  return;
              }

              var goToUrl = null;
              if (config.successUrl != null)
              {
                  goToUrl = config.successUrl;
              }
              else if (!isEmpty(response.json.successUrl))
              {
                  goToUrl = response.json.successUrl;
              }

              if (goToUrl != null)
              {
                  // is a popup?
                  if (config.popupOpts != null)
                  {
                      popUp(goToUrl, config.popupOpts.title, config.popupOpts.height, config.popupOpts.width, config.popupOpts.options);
                  }
                  // is in a tab?
                  else if (isUsingTabs())
                  {
                      // can we get current tab?
                      if (config.callerId != null)
                      {
                        //var myTab = Ext.fly(config.callerId).up("div[id^=docs-]");
                        //CELOXIS.MainPanel.closeTab(myTab);
                          CELOXIS.MainPanel.remove(CELOXIS.MainPanel.activeTab, true);
                      }
                      CELOXIS.MainPanel.loadContent(goToUrl+'&ni.ajax=true', randomString());
                  }
                  // change current location
                  else
                  {
                      window.location.href = goToUrl;
                      return;
                  }
              }

              if (config.callback)
              {
                  var cb = config.callback;
                  cb(response, config.callback_args);
              }

              doCleanup();
          }
          else
          {
              // failure
              if (config.errorDivContainer)
              {
                  var el =  Ext.get(config.errorDivMsg);
                  el.update(response.errorMessage);
                  Ext.get(config.errorDivContainer).setDisplayed(true);
                  Ext.get(config.errorDivContainer).dom.scrollIntoView();
              }

              // restore the original content of the div
              // that was to be replaced
              //if (config.replaceDiv) { Ext.get(config.replaceDiv).update(originalContent); }

              doCleanup();
          }

      },

      failure: function (transport) {
          //CELOXIS.feedback.clear();
      }
  });
}

/*
 * Convenience function that performs simple ajax requests that replaces main content
 */
CELOXIS.ajaxBody = function(config)
{
  config.replaceDiv = 'container';
  CELOXIS.ajax(config);
}

/*
 * Function that performs simple ajax requests that replaces div's
 * It does not handle success/error responses from the URL invoked
 * Use json/jsonConfirm for that.
 */
CELOXIS.ajax = function(config)
{
  config = config || {};
  config = Ext.applyIf(config, {
      url: null,
      form: null,
      replaceDiv: null,
      params: {}, // params to AJAX request.
      scripts: true,
      indicator: 'maskDiv',
      indicatorText: 'Loading...'
  });

  config.params["ni.ajax"] = true;
  config.params["ni.data_only"] = true;
  var allParams = CELOXIS.formToObject(config.form);
  Ext.apply(allParams, CELOXIS.urlDecode(config.params));

  var url = config.url;
  if (url == null)
  {
      url = this.config.form.action;
  }

  var mask = CELOXIS.mask({
    indicator: config.indicator,
    indicatorText: config.indicatorText,
    divId: config.replaceDiv
  });

  if (config.replaceDiv)
  {
      var rd = Ext.get(config.replaceDiv);
      var updater = rd.getUpdater();
      updater.showLoadIndicator = false; // we handle show loading ourselves
      updater.update({
          url: url,
          method: 'post',
          params: allParams,
          scripts: config.scripts,
          callback: function(el) {
            mask.hideMask();
          }
      });
  }
}

/*
 * submits a form to the url of an enclosing div with class "tile"
 * Used by filters, sort, pagination, pick cols etc to post to the enclosing div
 * e.g My Projects/My Tasks etc
 */
function updateEnclDivOrThisPage(domEl, config)
{
  config = config || {};
  config = Ext.applyIf(config, {
      form: null,
      params: {}
  });
  var extEl = null;
  var div = null;
  if (domEl != null) extEl = Ext.get(domEl);
  if (extEl != null)
  {
    div = extEl.up("div.tile");
  }

  if (div == null)
  {
    /*
     * Trying to use the form if it was passed, gave recursion errors.
     */
    var f = Ext.fly(document.body).createChild({tag:'form', method:'post', action: window.location.href}).dom;
    config.form != null ? replaceFormFields(f, Ext.urlDecode(Ext.Ajax.serializeForm(config.form))) : true;
    replaceFormFields(f, config.params);
    f.submit();
  }
  else
  {
      var extEl = Ext.get(domEl);
      var div = extEl.up("div.tile");
      if (div != null && div != undefined)
      {
        config.replaceDiv = div.dom.getAttribute('id');
        config.url = div.dom.getAttribute('url');
        config.params['ni.self'] = true;
        CELOXIS.ajax(config);
      }
  }
}

/*
 * A class that allows flexible creation of "pop-ups" using a layer
 * The content of the layer is obtained from an existing div in the page
 * Used for multi-user selector, on plan page etc.
 */
CELOXIS.namespace('layer');
CELOXIS.layer.get = function(contentId)
{
    return Ext.get(contentId).dom.layer;
}
CELOXIS.layer.createOrGet = function(config)
{
    var content = Ext.get(config.contentId);
    var layer = content.dom.layer;
    if (layer == null)
    {
        return new CELOXIS.layer.Layer(config);
    }
    return layer;
}

CELOXIS.layer.Layer = function(config) {
    config = config || {};
    config = Ext.applyIf(config, {
        anchorId: null,
        anchorLoc: 'tl-bl?',
        contentId: null,
        shadow: false,
        zindex: 21000,
        autoHide: false,
        modal: false
    });

    Ext.applyIf(this, config);

    this.loaded = false;
    this.content = Ext.get(this.contentId);
    this.content.dom.layer = this; // keep this object associated with its content

    this.layer = new Ext.Layer({
        id: 'l_' + this.contentId,
        shadow: this.shadow,
        zindex: this.zindex
    });

    var panelId = Ext.id();
    this.layer.insertHtml('afterBegin', '<table><tr><td><div id="' + panelId + '"></div></td></tr></table>');

    config.panelCfg = config.panelCfg || {};
    var panelCfg = {
        renderTo: panelId,
        hideCollapseTool: true,
        titleCollapse: false,
        collapsible: false,
        layout: 'fit',
        autoShow: true,
        contentEl: this.contentId,
        frame: config['frame'],
        autoScroll: true,
        buttons: config['buttons']
    }

    var panelCfg = Ext.applyIf(config.panelCfg, panelCfg);
    if (config['title'])
    {
        panelCfg['title'] = config['title'];
    }
    if (config['height'])
    {
        panelCfg['height'] = config['height'];
    }

    this.panel = new Ext.Panel(panelCfg);

    // use this way to set width to fix the horizontal scroll bar
    // problem in IE
    /*
    if (config['width'])
    {
        //Ext.get(this.contentId).setWidth(config['width'], false);
    }
    */

    /*
     * The foll are functions of this to operate on the layer.
     *
     */
    CELOXIS.layer.Layer.prototype.getPanel = function() {
        return this.panel;
    }

    CELOXIS.layer.Layer.prototype.hideListener = function(e) {
        if(!this.layer.contains(e.target) || e.target.tagName.toLowerCase() === 'a')
        {
            this.hide();
        }
    }

    CELOXIS.layer.Layer.prototype.show = function() {
        var url = this.content.getAttributeNS("", 'url');
        var cacheContent = this.content.getAttributeNS("", 'cache');
        if (url != undefined && url != "" && (!this.loaded || cacheContent === 'false'))
        {
            // need foll for IE. prob bec the div is hidden and it does not like to
            // have loading text on it.
            this.content.getUpdater().showLoadIndicator = false;
            this.content.load({
                url: url,
                method: 'get',
                scripts: true,
                scope: this.content,
                callback: function() {
                    this.dom.layer._show();
                }
            });
        }
        else
        {
            this._show();
        }
    }

    CELOXIS.layer.Layer.prototype.setAnchorId = function(v)
    {
        this.anchorId = v;
    }

    CELOXIS.layer.Layer.prototype._show = function() {
        this.isVisible = true;
        this.loaded = true;
        if (this.anchorId != null)
        {
          //this.layer.anchorTo(Ext.get(this.anchorId), this.anchorLoc);
          this.layer.alignTo(Ext.get(this.anchorId), this.anchorLoc);
        }
        else
        {
            this.layer.setXY(this.layer.getCenterXY());
        }
        if(this.modal)
        {
            if (this.mask == null)
            {
                this.mask = Ext.getBody().createChild({cls:"ext-el-mask"});
                //this.mask.setStyle('z-index', 9000);
            }
            this.mask.enableDisplayMode("block");
            var pos = Ext.getBody().getScroll();
            this.mask.setLeftTop(pos.left, pos.top);
            this.mask.show();
        }
         //Ext.isIE ? this.layer.setWidth(this.panel.getInnerWidth() + this.panel.getFrameWidth()) : true;
         this.layer.setWidth(Ext.get(this.contentId).getWidth());
        this.layer.show(false);
        if (this.autoHide)
        {
            Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.hideListener, this, {delay: 1000});
        }
    }

    CELOXIS.layer.Layer.prototype.hide = function() {
        this.isVisible = false;
        this.layer.hide(false);
        if(this.modal) {
            this.mask.hide();
        }
        if (this.autoHide)
        {
            Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.hideListener);
        }
    }

    CELOXIS.layer.Layer.prototype.toggle = function() {
        if (this.isVisible)
        {
            this.hide();
        }
        else
        {
            this.show();
        }
    }
}

CELOXIS.openInTab = function(config)
{
  config = config || {};
  config = Ext.applyIf(config, {
      id: null,
      title: null,
      autoLoad: null,
      title: null,
      //iconCls: 'tabs',
      //html: '<h2>This is Tab 2</h2>',
      closable:true,
      scripts: true,
      indicator: 'maskDiv',
      indicatorText: 'Loading...'
  });

  config.autoLoad.params = {'ni.data_only' : true};
  var mainTabs = Ext.getCmp('mainTabs');
  var p = mainTabs.add(new Ext.Panel(config));
  mainTabs.setActiveTab(p);
}

CELOXIS.namespace('string');
// truncate and put ellipsis if length is more then the passed in length
CELOXIS.string.truncate = function(s, len)
{
  if (isWhitespace(s))
  {
    return '';
  }
  s = '' + s;
  if (s.length <= len)
  {
      return s;
  }
  return s.substr(0, len) + '...';
}

/*
 * Matrix widget function that returns the name of a cell
 */
function getMatrixCellName(cellPrefix, row, col)
{
    return cellPrefix + row + "_" + col;
}


function refreshPage()
{
    window.location.reload(true);
}

CELOXIS.switchView =function()
{
    if (confirm("Any changes on this screen will be lost. Are you sure you want to continue?")) { document.switchForm.submit(); }

}

DocPanel = Ext.extend(Ext.Panel, { closable: true, autoScroll: true, initComponent: function()
    { var ps = this.cclass; this.title = ps; DocPanel.superclass.initComponent.call(this); }});

MainPanel = function() {
    MainPanel.superclass.constructor.call(this, {
        id:'main-body',
        region:'center',
        margins:'0 5 5 0',
        resizeTabs: true,
        minTabWidth: 160,
        tabWidth: 160,
        //plugins: new Ext.ux.TabCloseMenu(),
        enableTabScroll: true,
        activeTab: 0,
        defaults: {autoScroll: true},
        items: {
            id:'welcome-panel',
            title: 'My Home',
            autoLoad: {url: 'user.do?ni.ajax=true', scope: this, scripts: true},
            iconCls:'icon-docs',
            autoScroll: true
        }
    });
};

Ext.extend(MainPanel, Ext.TabPanel, {

    initEvents : function(){
        MainPanel.superclass.initEvents.call(this);
        //this.body.on('click', this.onClick, this);
    },

    xonClick: function(e, target){
            e.stopEvent();
            alert(target);
            this.loadContent(target.href + '&ni.ajax=true', randomString());
    },

    loadContent : function(href, pageId) {
        var id = 'docs-' + pageId;
        var tab = this.getComponent(id);
        if(tab) {
            this.setActiveTab(tab);
        } else {
            var autoLoad = {url: href, scripts: true};
            var p = this.add(new DocPanel({
                id: id,
                cclass : pageId,
                autoLoad: autoLoad
                //iconCls: Docs.icons[cls]
            }));
            this.setActiveTab(p);
        }
    },

    closeTab : function(tab) {
        this.remove(tab);
    }
});

function isUsingTabs()
{
    return false;
}


CELOXIS.adjustTaskTypeState = function(pcTb, ttsSel)
{

      if (trim(pcTb.value) == 100)
      {
          ttsSel.selectedIndex = ttsSel.options.length - 1;
      }
      else if (ttsSel.selectedIndex == ttsSel.options.length - 1)
      {
          ttsSel.selectedIndex = 0;
      }
}
CELOXIS.adjustTaskPc = function(ttsSel, pcTb)
{
      if (ttsSel.selectedIndex == ttsSel.options.length - 1)
      {
          pcTb.value = 100;
      }
      else if (trim(pcTb.value) == 100)
      {
          pcTb.value = '';
      }
}

CELOXIS.popUp = function(config, loadConfig)
{
  config = config || {};
  config = Ext.applyIf(config, {
      width: 600,
      height: 500,
      closeAction: 'hide',
      //plain: true,
      autoScroll: true,
      id: config.contentEl + '-id' // if no id is passed create one 
  });

  var win = Ext.getCmp(config.id);
  if (win != null)
  {
      win.setVisible(true);
      return;
  }

  win = new Ext.Window(config);
  win.setVisible(true);
  win.show();

  if (loadConfig)
  {
      loadConfig = loadConfig || {};
      loadConfig = Ext.applyIf(loadConfig, {
          scripts: true,
          discardUrl: true
      });
      win.load(loadConfig);
  }
}

function runReport(url, id)
{
    popUp(url, "report_" + id, "800", "800");
}

CELOXIS.selectRow = function(cb)
{
    if (cb.checked)
    {
        Ext.get(cb).up('tr').addClass('sel');
    }
    else
    {
        Ext.get(cb).up('tr').removeClass('sel');
    }
}

CELOXIS.hideTip = function(divId, pn, callback)
{

    var e = Ext.get(divId);
    e.enableDisplayMode('');
    e.hide();

    if (callback) { callback(); }

    var params = new Object();
    params['to_hide'] = pn;

    CELOXIS.ajax({
        url: 'user.do?bxn=hidetip',
        params: params,
        indicator: null,
        replaceDiv: divId
    });
}

CELOXIS.openTask = function(id)
{
    popUp('work.do?ni.page_type=4&bxn=wview&p_w_id=' + id, 'task_' + id, 540, 840);
}

// saves the scroll position of a div
CELOXIS.saveScrollPos = function(divId)
{
    var e = document.getElementById("scroll-pos-id");
    var divToSave = document.getElementById(divId);
    if (!e || !divToSave)
    {
        return;
    }
    e.c_scrollTop = divToSave.scrollTop;
    e.c_scrollDivId =  divId;
}

// restores the scroll position of the saved div
CELOXIS.restoreScrollPos = function()
{
    var divId = document.getElementById("scroll-pos-id").c_scrollDivId;
    if (divId)
    {
        document.getElementById(divId).scrollTop = document.getElementById("scroll-pos-id").c_scrollTop;
    }
}

CELOXIS.requestProgressUpdate = function(id) {
    var params = new Object();
    params['id'] = id;
    CELOXIS.jsonConfirm({
        url: 'pm.do?axn=requestprogressupdate',
        params: params
    });
}

CELOXIS.markComplete = function(id, cb) {
    var params = new Object();
    params['id'] = id;
    if (!cb) { cb = noop; }
    CELOXIS.jsonConfirm({
        url: 'pm.do?axn=markComplete',
        params: params,
        callback: cb
    });
}

CELOXIS.namespace('alert');
CELOXIS.alert.info = function(msg)
{
    //Ext.Msg.show({ title : 'Alert', maxWidth: 320, minWidth: 240, msg: msg, buttons: Ext.Msg.OK, icon: Ext.MessageBox.INFO });
    alert(msg);
}
CELOXIS.alert.warning = function(msg)
{
    //Ext.Msg.show({ title : 'Alert', maxWidth: 320, minWidth: 240, msg: msg, buttons: Ext.Msg.OK, icon: Ext.MessageBox.WARNING });
    alert(msg);
}
CELOXIS.setPreferences = function(keyValues, noConfirmation)
{
    CELOXIS.json({ url: 't.do?', params: keyValues, showConfirmation: !noConfirmation });
}
CELOXIS.resizeCurrentTab = function()
{
    if (CELOXIS.currentTab)
    {
        CELOXIS.currentTab.setWidth(CELOXIS.contentElement().getBox().width - 30);
    }
}
CELOXIS.VPR = function(config) {
     var Impl = function() { Impl.superclass.constructor.call(this, config); this.addEvents('viewportready'); };
     Ext.extend(Impl, Ext.util.Observable, { doit: function() {  this.fireEvent('viewportready'); } }); 
     return new Impl();
}();
CELOXIS.onReady = function(handler) { CELOXIS.VPR.on('viewportready', handler); }
CELOXIS.onReady(CELOXIS.resizeCurrentTab);

CELOXIS.checkFileExtension = function (filename, extensions)
{
    var parts = filename.split(".");
    var ext = null;
    if (parts.length > 0)
    {
        ext = parts[parts.length - 1];
    }
    if (ext)
    {
        ext = ext.toLowerCase().trim();
    }
    if (!ext || extensions.indexOf(ext) < 0)
    {
        alert("File does not have any of the valid extensions : " + extensions);
        return false;
    }
    return true;
}
