  function openLicenseAppletWindow(){
    var url = "?ACTION=applet&todo=appletShowLicense";
    location.href=url;
  }

  function openAppletWindow(){
    var url = "?ACTION=applet&todo=applet";
    location.href=url;
  }
  
  function openLoginWindow(url){
    var rnd = Math.round(Math.random()*1000000);
    var newName = 'newWindow'+rnd;
    
    var x = 220;
    var y = 200;
    var left = (screen.availWidth - x)/2;
    var top = (screen.availHeight - y)/2;

    newWindow=window.open(url,newName,'menubar=no,status=no,resizable=yes,scrollbars=0,location=no,top='+top+',left='+left+',width=' + x + ',height=' + y);
    newWindow.focus();
  }

  function openEditWindow(obj, getElem){
    var rnd = Math.round(Math.random()*1000000);
    var newName = 'newWindow'+rnd;
    var url = "?ACTION=edit_object&classname=" + obj + "&CompanyId="+companyId;
    if (getElem){
      url += "&ID=" + document.getElementById(obj).value;
    }
    var x = 500;
    var y = 200;
    newWindow=window.open(url,newName,'menubar=no,status=no,resizable=yes,location=no,width=' + x + ',height=' + y);
    newWindow.focus();
  }

  function openAddWindow(obj){
    var rnd = Math.round(Math.random()*1000000);
    var newName = 'newWindow'+rnd;
    var url = "?ACTION=addObject&classname=" + obj + "&CompanyId="+companyId;
    var x = 500;
    var y = 200;
    newWindow=window.open(url,newName,'menubar=no,status=no,resizable=yes,location=no,width=' + x + ',height=' + y);
    newWindow.focus();
  }

  function selectCompany(formname, idfieldname, namefieldname, text, tickersearch){
    if (!tickersearch) {
      var tickersearch = false;
    }
    if (text.length < 3 && !tickersearch){
      if (!confirm('You entered less than 3 symbols.\r\nThe result list can be very long.\r\nContinue?')){
        return;
      }
    }
    var rnd = Math.round(Math.random()*1000000);
    var newName = 'newWindow'+rnd;
    var url = "./index.php?ACTION=select_company&formname="+formname+"&idfieldname="+idfieldname+"&namefieldname="+namefieldname+"&text="+text+"&tickersearch="+tickersearch;
    var x = 500;
    var y = 500;
    newWindow=window.open(url,newName,'scrollbars=yes,menubar=no,status=no,resizable=yes,location=no,width=' + x + ',height=' + y);
    newWindow.focus();
  }

  function selectSingleCompany(formname, idfieldname, namefieldname, text){
  script = document.createElement('script');
  script.src="?ACTION=select_company&formname="+formname+"&idfieldname="+idfieldname+"&namefieldname="+namefieldname+"&text="+text+"&ajax=1";
  document.appendChild(script);
  }

  function ShowSelectCompany(fieldname, visible){
    var td = document.getElementById(fieldname+'_selectcompany');
    if (visible){
      td.style.visibility = 'visible';
    }else{
      td.style.visibility = 'hidden';
    }
  }

  function companyInfo(CompanyId){
    var url = "?todo=viewCompany&CompanyId=" + CompanyId;
    parent.location.href=url;
  }

// Check browser version
var isNav4 = false, isNav5 = false, isIE4 = false
var strSeperator = "/";
// If you are using any Java validation on the back side you will want to use the / because
// Java date validations do not recognize the dash as a valid date separator.
var vDateType = 1; // Global value for type of date format
//                1 = mm/dd/yyyy
//                2 = yyyy/dd/mm  (Unable to do date check at this time)
//                3 = dd/mm/yyyy
var vYearType = 4; //Set to 2 or 4 for number of digits in the year for Netscape
var vYearLength = 2; // Set to 4 if you want to force the user to enter 4 digits for the year before validating.
var err = 0; // Set the error code to a default of zero
if(navigator.appName == "Netscape") {
  if (navigator.appVersion < "5") {
    isNav4 = true;
    isNav5 = false;
  }else if (navigator.appVersion > "4") {
    isNav4 = false;
    isNav5 = true;
  }
}else {
  isIE4 = true;
}

function DateFormat(vDateName, vDateValue, e, dateCheck, dateType) {
  vDateType = dateType;

  // vDateName = object name
  // vDateValue = value in the field being checked
  // e = event
  // dateCheck
  // True  = Verify that the vDateValue is a valid date
  // False = Format values being entered into vDateValue only
  // vDateType
  // 1 = mm/dd/yyyy
  // 2 = yyyy/mm/dd
  // 3 = dd/mm/yyyy
  //Enter a tilde sign for the first number and you can check the variable information.
  if (vDateValue == "~") {
    alert("AppVersion = "+navigator.appVersion+" \nNav. 4 Version = "+isNav4+" \nNav. 5 Version = "+isNav5+" \nIE Version = "+isIE4+" \nYear Type = "+vYearType+" \nDate Type = "+vDateType+" \nSeparator = "+strSeperator);
    vDateName.value = "";
    vDateName.focus();
    return true;
  }
  var whichCode = (window.Event) ? e.which : e.keyCode;
  // Check to see if a seperator is already present.
  // bypass the date if a seperator is present and the length greater than 8
  if (vDateValue.length > 8 && isNav4) {
    if ((vDateValue.indexOf("-") >= 1) || (vDateValue.indexOf("/") >= 1))
      return true;
  }
  //Eliminate all the ASCII codes that are not valid
  var alphaCheck = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-";
  if (alphaCheck.indexOf(vDateValue) >= 1) {
    if (isNav4) {
      vDateName.value = "";
      vDateName.focus();
      vDateName.select();
      return false;
    }else {
    vDateName.value = vDateName.value.substr(0, (vDateValue.length-1));
    return false;
    }
  }
  if (whichCode == 8) //Ignore the Netscape value for backspace. IE has no value
    return false;
  else {
    //Create numeric string values for 0123456789/
    //The codes provided include both keyboard and keypad values
    var strCheck = '47,48,49,50,51,52,53,54,55,56,57,58,59,95,96,97,98,99,100,101,102,103,104,105';
    if (strCheck.indexOf(whichCode) != -1) {
      if (isNav4) {
        if (((vDateValue.length < 6 && dateCheck) || (vDateValue.length == 7 && dateCheck)) && (vDateValue.length >=1)) {
          alert("Invalid Date\nPlease Re-Enter");
          vDateName.value = "";
          vDateName.focus();
          vDateName.select();
          return false;
        }
        if (vDateValue.length == 6 && dateCheck) {
          var mDay = vDateName.value.substr(2,2);
          var mMonth = vDateName.value.substr(0,2);
          var mYear = vDateName.value.substr(4,4)
          //Turn a two digit year into a 4 digit year
          if (mYear.length == 2 && vYearType == 4) {
            var mToday = new Date();
            //If the year is greater than 30 years from now use 19, otherwise use 20
            var checkYear = mToday.getFullYear() + 30;
            var mCheckYear = '20' + mYear;
            if (mCheckYear >= checkYear)
              mYear = '19' + mYear;
            else
              mYear = '20' + mYear;
          }
          var vDateValueCheck = mMonth+strSeperator+mDay+strSeperator+mYear;
          if (!dateValid(vDateValueCheck)) {
            alert("Invalid Date\nPlease Re-Enter");
            vDateName.value = "";
            vDateName.focus();
            vDateName.select();
            return false;
          }
          return true;
        }else {
        // Reformat the date for validation and set date type to a 1
          if (vDateValue.length >= 8  && dateCheck) {
            if (vDateType == 1){ // mmddyyyy
              var mDay = vDateName.value.substr(2,2);
              var mMonth = vDateName.value.substr(0,2);
              var mYear = vDateName.value.substr(4,4)
              vDateName.value = mMonth+strSeperator+mDay+strSeperator+mYear;
            }
            //Create a temporary variable for storing the DateType and change
            //the DateType to a 1 for validation.
            var vDateTypeTemp = vDateType;
            vDateType = 1;
            var vDateValueCheck = mMonth+strSeperator+mDay+strSeperator+mYear;
            if (!dateValid(vDateValueCheck)) {
              alert("Invalid Date\nPlease Re-Enter");
              vDateType = vDateTypeTemp;
              vDateName.value = "";
              vDateName.focus();
              vDateName.select();
              return false;
            }
            vDateType = vDateTypeTemp;
            return true;
          }else {
            if (((vDateValue.length < 8 && dateCheck) || (vDateValue.length == 9 && dateCheck)) && (vDateValue.length >=1)) {
              alert("Invalid Date\nPlease Re-Enter");
              vDateName.value = "";
              vDateName.focus();
              vDateName.select();
              return false;
            }
          }
        }
      }else {
  // Non isNav Check
  if (((vDateValue.length < 8 && dateCheck) || (vDateValue.length == 9 && dateCheck)) && (vDateValue.length >=1)) {
  alert("Invalid Date\nPlease Re-Enter");
  vDateName.value = "";
  vDateName.focus();
  return true;
  }
  // Reformat date to format that can be validated. mm/dd/yyyy
  if (vDateValue.length >= 8 && dateCheck) {
  // Additional date formats can be entered here and parsed out to
  // a valid date format that the validation routine will recognize.
  if (vDateType == 1) // mm/dd/yyyy
  {
  var mMonth = vDateName.value.substr(0,2);
  var mDay = vDateName.value.substr(3,2);
  var mYear = vDateName.value.substr(6,4)
  }
  if (vYearLength == 4) {
  if (mYear.length < 4) {
  alert("Invalid Date\nPlease Re-Enter");
  vDateName.value = "";
  vDateName.focus();
  return true;
     }
  }
  // Create temp. variable for storing the current vDateType
  var vDateTypeTemp = vDateType;
  // Change vDateType to a 1 for standard date format for validation
  // Type will be changed back when validation is completed.
  vDateType = 1;
  // Store reformatted date to new variable for validation.
  var vDateValueCheck = mMonth+strSeperator+mDay+strSeperator+mYear;
  if (mYear.length == 2 && vYearType == 4 && dateCheck) {
  //Turn a two digit year into a 4 digit year
  var mToday = new Date();
  //If the year is greater than 30 years from now use 19, otherwise use 20
  var checkYear = mToday.getFullYear() + 30;
  var mCheckYear = '20' + mYear;
  if (mCheckYear >= checkYear)
  mYear = '19' + mYear;
  else
  mYear = '20' + mYear;
  vDateValueCheck = mMonth+strSeperator+mDay+strSeperator+mYear;
  // Store the new value back to the field.  This function will
  // not work with date type of 2 since the year is entered first.
  if (vDateTypeTemp == 1) // mm/dd/yyyy
  vDateName.value = mMonth+strSeperator+mDay+strSeperator+mYear;
  if (vDateTypeTemp == 3) // dd/mm/yyyy
  vDateName.value = mDay+strSeperator+mMonth+strSeperator+mYear;
  }
  if (!dateValid(vDateValueCheck)) {
  alert("Invalid Date\nPlease Re-Enter");
  vDateType = vDateTypeTemp;
  vDateName.value = "";
  vDateName.focus();
  return true;
  }
  vDateType = vDateTypeTemp;
  return true;
  }
  else {
  if (vDateType == 1) {
  if (vDateValue.length == 2) {
  vDateName.value = vDateValue+strSeperator;
  }
  if (vDateValue.length == 5) {
  vDateName.value = vDateValue+strSeperator;
     }
  }
  if (vDateType == 2) {
  if (vDateValue.length == 4) {
  vDateName.value = vDateValue+strSeperator;
  }
  if (vDateValue.length == 7) {
  vDateName.value = vDateValue+strSeperator;
     }
  }
  if (vDateType == 3) {
  if (vDateValue.length == 2) {
  vDateName.value = vDateValue+strSeperator;
  }
  if (vDateValue.length == 5) {
  vDateName.value = vDateValue+strSeperator;
     }
  }
  return true;
     }
  }
  if (vDateValue.length == 10&& dateCheck) {
  if (!dateValid(vDateName)) {
  // Un-comment the next line of code for debugging the dateValid() function error messages
  //alert(err);
  alert("Invalid Date\nPlease Re-Enter");
  vDateName.focus();
  vDateName.select();
     }
  }
  return false;
  }
  else {
  // If the value is not in the string return the string minus the last
  // key entered.
  if (isNav4) {
  vDateName.value = "";
  vDateName.focus();
  vDateName.select();
  return false;
  }
  else
  {
  vDateName.value = vDateName.value.substr(0, (vDateValue.length-1));
  return false;
           }
        }
     }
}
function dateValid(objName) {
  var strDate;
  var strDateArray;
  var strDay;
  var strMonth;
  var strYear;
  var intday;
  var intMonth;
  var intYear;
  var booFound = false;
  var datefield = objName;
  var strSeparatorArray = new Array("-"," ","/",".");
  var intElementNr;
  // var err = 0;
  var strMonthArray = new Array(12);
  strMonthArray[0] = "Jan";
  strMonthArray[1] = "Feb";
  strMonthArray[2] = "Mar";
  strMonthArray[3] = "Apr";
  strMonthArray[4] = "May";
  strMonthArray[5] = "Jun";
  strMonthArray[6] = "Jul";
  strMonthArray[7] = "Aug";
  strMonthArray[8] = "Sep";
  strMonthArray[9] = "Oct";
  strMonthArray[10] = "Nov";
  strMonthArray[11] = "Dec";
  //strDate = datefield.value;
  strDate = objName;
  if (strDate.length < 1) {
  return true;
  }
  for (intElementNr = 0; intElementNr < strSeparatorArray.length; intElementNr++) {
  if (strDate.indexOf(strSeparatorArray[intElementNr]) != -1) {
  strDateArray = strDate.split(strSeparatorArray[intElementNr]);
  if (strDateArray.length != 3) {
  err = 1;
  return false;
  }
  else {
  strDay = strDateArray[0];
  strMonth = strDateArray[1];
  strYear = strDateArray[2];
  }
  booFound = true;
     }
  }
  if (booFound == false) {
  if (strDate.length>5) {
  strDay = strDate.substr(0, 2);
  strMonth = strDate.substr(2, 2);
  strYear = strDate.substr(4);
     }
  }
  //Adjustment for short years entered
  if (strYear.length == 2) {
  strYear = '20' + strYear;
  }
  strTemp = strDay;
  strDay = strMonth;
  strMonth = strTemp;
  intday = parseInt(strDay, 10);
  if (isNaN(intday)) {
  err = 2;
  return false;
  }
  intMonth = parseInt(strMonth, 10);
  if (isNaN(intMonth)) {
  for (i = 0;i<12;i++) {
  if (strMonth.toUpperCase() == strMonthArray[i].toUpperCase()) {
  intMonth = i+1;
  strMonth = strMonthArray[i];
  i = 12;
     }
  }
  if (isNaN(intMonth)) {
  err = 3;
  return false;
     }
  }
  intYear = parseInt(strYear, 10);
  if (isNaN(intYear)) {
  err = 4;
  return false;
  }
  if (intMonth>12 || intMonth<1) {
  err = 5;
  return false;
  }
  if ((intMonth == 1 || intMonth == 3 || intMonth == 5 || intMonth == 7 || intMonth == 8 || intMonth == 10 || intMonth == 12) && (intday > 31 || intday < 1)) {
  err = 6;
  return false;
  }
  if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && (intday > 30 || intday < 1)) {
  err = 7;
  return false;
  }
  if (intMonth == 2) {
  if (intday < 1) {
  err = 8;
  return false;
  }
  if (LeapYear(intYear) == true) {
  if (intday > 29) {
  err = 9;
  return false;
     }
  }
  else {
  if (intday > 28) {
  err = 10;
  return false;
        }
     }
  }
  return true;
}
function LeapYear(intYear) {
  if (intYear % 100 == 0) {
  if (intYear % 400 == 0) { return true; }
  }
  else {
  if ((intYear % 4) == 0) { return true; }
  }
  return false;
}
  function addCommas(elem){
    elem.value += '';
    x = elem.value.split('.');
    x0 = x[0].split(',');
    x1 = x0.join('');
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    elem.value = x1 + x2;
  }

function strip_zeros(s) {
  while (s.charAt(0) == '0') {
    s = s.slice(1);
  }
    return s;
}

function check_date(date) {
  maxdays = [
  31,
  28,
  31,
  30,
  31,
  30,
  31,
  31,
  30,
  31,
  30,
  31];

  d = date.split('/');
  month = eval(strip_zeros(d[0]))-1;
  day   = eval(strip_zeros(d[1]));
  year  = eval(strip_zeros(d[2]));

  if (LeapYear(year))
  {
    maxdays[2]=29;
  }

  if (month>11 || month<0)
  {
    alert ('Month #'+(month+1)+' is illegal');
    return false;
  }
  if (maxdays[month]<day || day<1)
  {
    alert ('it seems like in #'+(month+1)+' month should not be #'+day+' day!');
    return false;
  }
  return true;
}

function split_date(date) {
  d = date.split('/');
  month = eval(d[0])-1;
  day   = eval(d[1]);
  year  = eval(d[2]);
    return {'month': month, 'day': day, 'year': year};
}

function xmlrpc_getCompanyData(text, tickersearch, exactly) {
  xmlrpc = importModule('xmlrpc');
  
  var tickersearch = (tickersearch) ? 1 : 0;

  var get_data = new xmlrpc.XMLRPCMethod("xmlrpcServer.php","getCompanyId"); // the method name do NOT supply parameters with method?arg1=foo&arg2=bar

  var args = {
    'text' : text,
    'tickersearch' : tickersearch,
    'exactly' : exactly
  };
  return get_data(args);
}

function xmlrpc_getCompanyDataByName(text, tickersearch, exactly) {
  xmlrpc = importModule('xmlrpc');
  
  var tickersearch = (tickersearch) ? 1 : 0;

  var get_data = new xmlrpc.XMLRPCMethod("xmlrpcServer.php","getCompanyIdByName"); // the method name do NOT supply parameters with method?arg1=foo&arg2=bar

  var args = {
    'text' : text,
    'tickersearch' : tickersearch,
    'exactly' : exactly
  };
  //alert(args.text + ', ' + args.tickersearch + ', ' +  args.exactly);
  return get_data(args);
}


function xmlrpc_getCompanyId(formname, idfieldname, namefieldname, searchfieldname, text, tickersearch) {
  var result = xmlrpc_getCompanyData(text, tickersearch, true);
  
  if (result){
    var idfield   = eval('document.'+formname+'["'+idfieldname+'"]');
    var namefield = eval('document.'+formname+'["'+namefieldname+'"]');
    idfield.value = result.CompanyID;
    namefield.value = result.CompanyName;
  }else{
    selectCompany(formname, idfieldname, namefieldname, text, tickersearch);
  }
}


function xmlrpc_getCompanyIdAddCompanyByName(formname, idfieldname, namefieldname, text, tickersearch, exactly) {
  var exactly = (exactly) ? exactly : 0;
  var result = xmlrpc_getCompanyDataByName(text, tickersearch, exactly);

  if (result){
    addCompany(formname, idfieldname, result.CompanyID, result.CompanyName);
  }else{
    selectCompany(formname, idfieldname, namefieldname, text, tickersearch);
  }
}


function xmlrpc_getCompanyRedirect(action, formname, idfieldname, namefieldname, searchfieldname, text, tickersearch) {
  var result = xmlrpc_getCompanyData(text, tickersearch, true);

  if (result){
    window.location.href='index.php?ACTION='+action+'&'+idfieldname+'='+result.CompanyID+'&'+searchfieldname+'='+text;
  }else{
    selectCompany(formname, idfieldname, namefieldname, text, tickersearch);
  }
}

function xmlrpc_getCompanyIdAddCompany(formname, idfieldname, namefieldname, text, tickersearch, exactly) {
  var exactly = (exactly) ? exactly : 0;
  var result = xmlrpc_getCompanyData(text, tickersearch, exactly);
  if (result){
    addCompany(formname, idfieldname, result.CompanyID, result.CompanyName);
  }else{
    selectCompany(formname, idfieldname, namefieldname, text, tickersearch);
  }
}



  function addCompany(formname, idfieldname, id, name) {
    
    var idfield = eval('document.'+formname+'["'+idfieldname+'"]');
    if (idfield.value.match("," + id + ",")){
      alert(name + ' is already selected!');
    }else{
      idfield.value += id + ',';
      addRowToTable(formname, idfieldname, id, name);
    }
  }

  function addRowToTable(formname, idfieldname, id, name) {
    var tbl = document.getElementById('companiesTable');
    var lastRow = tbl.rows.length;
    var row = document.createElement("tr");
    row.id = id;

    //cell with company name
    var cellName = document.createElement("td");
    var el = document.createTextNode(name);
    cellName.appendChild(el)
    row.appendChild(cellName);

    //cell with Delete link    
    var cellDelete = document.createElement("td");
    var el = document.createElement('a');
    el.href = "javascript:deleteCompany('"+formname+"','"+idfieldname+"',"+id+")";
    el.innerHTML = 'Delete';
    cellDelete.appendChild(el);
    row.appendChild(cellDelete);
    tbl.tBodies[0].appendChild(row);
  }

  function emptyCompanies(form) {
    form.companies.value=',';
    form.companies_searchstring.value='';  
    var table = document.getElementById('companiesTable');

    var rows = table.getElementsByTagName('tr');
    var c = rows.length;
    for (var i=0;i<c;i++){
      table.tBodies[0].removeChild(rows[0]);
    }
  }

  function deleteCompany(formname, idfieldname, id) {
    var idfield = eval('document.'+formname+'["'+idfieldname+'"]');

    idfield.value = idfield.value.replace(','+id+',', ',');

    var table = document.getElementById('companiesTable');
    var row = document.getElementById(id);
    if (row) table.tBodies[0].removeChild(row);
  }
  
//----- eventMaps------  
  
  function querySend(params,handler) {
      jQuery.ajax({url: "./index.php?ACTION=jquery",type: "POST",data: (params), dataType: "json",
        success: function(response){
          if(jQuery.isFunction(handler)) handler.call(this,response);
            }
      });
    }
    
  function portfolioCompaniesList(form, idfieldname, id, checked, func) {
      querySend([{name:'todo',value:'getPortfolioCompanies'},{name:'portfolioId',value:id},{name:'checked',value:checked}], function(response) {
        if(response.added) {
          for (var i=0;i<jQuery(response.added).size();i++) {
            var company = response.added[i];
            addCompany(jQuery(form).attr('name'), idfieldname, company.id, company.name);
          }
          if (func) eval(func);
        }
        if(response.deleted) {
          for (var i=0;i<jQuery(response.deleted).size();i++) {
            var companyId = response.deleted[i];
            deleteCompany(jQuery(form).attr('name'), idfieldname, companyId);
          }
        }
      });
    }
    
//----- eventMaps------    
  
  /*
 * Date Format 1.2.2
 * (c) 2007-2008 Steven Levithan <stevenlevithan.com>
 * MIT license
 * Includes enhancements by Scott Trenda <scott.trenda.net> and Kris Kowal <cixar.com/~kris.kowal/>
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 */
var dateFormat = function () {
  var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
    timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
    timezoneClip = /[^-+\dA-Z]/g,
    pad = function (val, len) {
      val = String(val);
      len = len || 2;
      while (val.length < len) val = "0" + val;
      return val;
    };

  // Regexes and supporting functions are cached through closure
  return function (date, mask, utc) {
    var dF = dateFormat;

    // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
    if (arguments.length == 1 && (typeof date == "string" || date instanceof String) && !/\d/.test(date)) {
      mask = date;
      date = undefined;
    }

    // Passing date through Date applies Date.parse, if necessary
    date = date ? new Date(date) : new Date();
    if (isNaN(date)) throw new SyntaxError("invalid date");

    mask = String(dF.masks[mask] || mask || dF.masks["default"]);

    // Allow setting the utc argument via the mask
    if (mask.slice(0, 4) == "UTC:") {
      mask = mask.slice(4);
      utc = true;
    }

    var _ = utc ? "getUTC" : "get",
      d = date[_ + "Date"](),
      D = date[_ + "Day"](),
      m = date[_ + "Month"](),
      y = date[_ + "FullYear"](),
      H = date[_ + "Hours"](),
      M = date[_ + "Minutes"](),
      s = date[_ + "Seconds"](),
      L = date[_ + "Milliseconds"](),
      o = utc ? 0 : date.getTimezoneOffset(),
      flags = {
        d:    d,
        dd:   pad(d),
        ddd:  dF.i18n.dayNames[D],
        dddd: dF.i18n.dayNames[D + 7],
        m:    m + 1,
        mm:   pad(m + 1),
        mmm:  dF.i18n.monthNames[m],
        mmmm: dF.i18n.monthNames[m + 12],
        yy:   String(y).slice(2),
        yyyy: y,
        h:    H % 12 || 12,
        hh:   pad(H % 12 || 12),
        H:    H,
        HH:   pad(H),
        M:    M,
        MM:   pad(M),
        s:    s,
        ss:   pad(s),
        l:    pad(L, 3),
        L:    pad(L > 99 ? Math.round(L / 10) : L),
        t:    H < 12 ? "a"  : "p",
        tt:   H < 12 ? "am" : "pm",
        T:    H < 12 ? "A"  : "P",
        TT:   H < 12 ? "AM" : "PM",
        Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
        o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
        S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
      };

    return mask.replace(token, function ($0) {
      return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
    });
  };
}();

// Some common format strings
dateFormat.masks = {
  "default":      "ddd mmm dd yyyy HH:MM:ss",
  shortDate:      "m/d/yy",
  mediumDate:     "mmm d, yyyy",
  longDate:       "mmmm d, yyyy",
  fullDate:       "dddd, mmmm d, yyyy",
  shortTime:      "h:MM TT",
  mediumTime:     "h:MM:ss TT",
  longTime:       "h:MM:ss TT Z",
  isoDate:        "yyyy-mm-dd",
  isoTime:        "HH:MM:ss",
  isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
  isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// Internationalization strings
dateFormat.i18n = {
  dayNames: [
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
  ],
  monthNames: [
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
  ]
};

// For convenience...
Date.prototype.format = function (mask, utc) {
  return dateFormat(this, mask, utc);
};
