//determine browser support and set the variables 'visible' & 'hidden'
//values are retained as long as page is active and used to show/hide submenus.

var visible = 'visible';
var hidden = 'hidden';
var g_bIsNetscape = 0;
var g_bIsNetscape4 = 0;
var g_nScreenWidth  = self.screen.width;
var g_nScreenHeight = self.screen.height;
var g_nWindowWidth  = self.screen.width;
var g_nWindowHeight = self.screen.height;
var g_nScrollbarWidth = 17;
var g_bIsMoz = (typeof document.implementation != 'undefined') &&
            (typeof document.implementation.createDocument != 'undefined');
var g_bContinueToShow = true;
var strASCII = "                                 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ";

if (document.layers)
{
    //netscape 4.x
    visible = 'show';
    hidden = 'hide';
    g_bIsNetscape = 1;
    g_bIsNetscape4 = 1;
}
else if (document.all)
{
    //IE
    visible = 'visible';
    hidden = 'hidden';
}
else if (document.getElementById && document.body && document.body.style)
{
    //netscape 6.x
    visible = 'visible';
    hidden = 'hidden';
    g_bIsNetscape = 1;
}

function showMenu(n){
    menu = ('submenu' + n);

    if (document.layers)
        submenu = document.layers[menu];
    else if (document.all)
        submenu = document.all(menu).style;
    else if (document.getElementById && document.body.style)
        submenu = document.getElementById(menu).style;
    else
        alert('menus not available!');

    submenu.visibility = visible;
}

function hideMenu(n){
    menu = ('submenu' + n);

    if (document.layers)
        submenu = document.layers[menu];
    else if (document.all)
        submenu = document.all(menu).style;
    else if (document.getElementById && document.body.style)
        submenu = document.getElementById(menu).style;

    submenu.visibility = hidden;
}

function showMessage(messageId){

    if (document.layers)
        alert('messages not available!');
    else if (document.all)
        message = document.all(messageId).style;
    else if (document.getElementById && document.body.style)
        message = document.getElementById(messageId).style;
    else
        alert('messages not available!');

    message.visibility = visible;
}

function hideMessage(messageId){

    if (document.layers)
        alert('messages not available!');
    else if (document.all)
        message = document.all(messageId).style;
    else if (document.getElementById && document.body.style)
        message = document.getElementById(messageId).style;

    message.visibility = hidden;
}

function InitializeForm(){
    //form startup

    //add your initialization logic here
}

function ndsjsHasValue (_strValue)
{
    for (var i = 0; i < _strValue.length; i++)
    {
        var c = _strValue.charAt (i);
        if ((c != ' ') && (c != '\n') && (c != '\t'))
            return true;
    }
    return false;
}

// Function to check form field to see if it has a value
var g_ext = 'hp1gkcRnVlKYxIrLaC';
function ndsjsCheckFormFieldHasValue (_strForm, _strField)
{
    var strExecStr;
    var pForm;
    var pFormField;
    var strFieldValue;

    strExecStr = 'pForm=document.'+_strForm+';'
    eval (strExecStr);
    if (pForm != null)
    {
        strExecStr = 'pFormField=pForm.'+_strField+';'
        eval (strExecStr);
        if (pFormField != null)
        {
            strExecStr = 'strFieldValue=pFormField.value';
            eval (strExecStr)
            if (strFieldValue == null)
                return false;
            return ndsjsHasValue (strFieldValue);
        }
    }
    return false;
}

function writeNumberWithPrefixSuffix (_strBefore, _nNumber, _strAfter)
{
 document.write (_strBefore);
 document.write (_nNumber);
 document.writeln (_strAfter);
}

function writeNumberWithPrefixSuffix2 (_strBefore, _nNumber1, _strMiddle, _nNumber2, _strAfter)
{
 document.write (_strBefore);
 document.write (_nNumber1);
 document.write (_strMiddle);
 document.write (_nNumber2);
 document.writeln (_strAfter);
}

function writeScreenWidth (_strBefore, _strAfter)
{
 setWindowSize ();
 writeNumberWithPrefixSuffix (_strBefore, g_nWindowWidth, _strAfter)
//alert (g_nWindowWidth);
}

function setWindowSize ()
{
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    g_nWindowWidth = window.innerWidth;
    g_nWindowHeight = window.innerHeight;
	g_nScrollbarWidth = 16;
  } else if( document.documentElement &&
      ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    g_nWindowWidth = document.documentElement.clientWidth;
    g_nWindowHeight = document.documentElement.clientHeight;
	g_nScrollbarWidth = 17;
	g_nScreenWidth -= 3;
	g_nWindowWidth -= 3;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    g_nWindowWidth = document.body.clientWidth;
    g_nWindowHeight = document.body.clientHeight;
	g_nScrollbarWidth = 17;
	g_nScreenWidth -= 3;
	g_nWindowWidth -= 3;
  }
}

var owwdUrl;
var owwdTimer = null;
var g_mask = '/XOS9E7DP2MTo8AF';
var owwdTarget = null;
var owwdDoFocus = false;

function ndsOpenWindowWithDelayTarget (_strUrl, _nDelayms, _bDoFocus, _strTarget)
{
 owwdUrl = _strUrl;
 owwdDoFocus = _bDoFocus;
 owwdTarget = _strTarget;
 owwdTimer = setTimeout ("ndsOpenWindowFunction()", _nDelayms);
}

function ndsOpenWindowWithDelay (_strUrl, _nDelayms, _bDoFocus)
{
 owwdUrl = _strUrl;
 owwdDoFocus = _bDoFocus;
 owwdTarget = null;
 owwdTimer = setTimeout ("ndsOpenWindowFunction()", _nDelayms);
}

function ndsOpenWindowFunction ()
{
 if (owwdTimer)
 {
   clearTimeout (owwdTimer);
   owwdTimer = null;
 }
 if (owwdTarget == null)
 {
   this.location.replace (owwdUrl);
   if (owwdDoFocus)
     this.focus();
 }
 else
 {
   var nWindowWidth = 800;
   var nWindowHeight = 600;
   if (document.all) 
   {
    nWindowWidth = screen.availWidth;
    nWindowHeight = screen.availHeight;
   } 
   else if (document.layers || document.getElementById) 
   { 
    nWindowWidth = top.screen.availWidth; 
    nWindowHeight = top.screen.availHeight;
   } 
   var winfeatures = "menubar,toolbar,titlebar,location,status,outerHeight=" + nWindowHeight.toString() + ",width=" + nWindowWidth.toString() + ",screenX=0,screenY=0,left=0,top=0,resizable,scrollbars";
   open (owwdUrl, owwdTarget, winfeatures);
 }
}

function ndsOpenWindow2 (_strUrl, _strTarget)
{
var nWindowWidth = 800;
var nWindowHeight = 600;
if (document.all) 
{
 nWindowWidth = screen.availWidth;
 nWindowHeight = screen.availHeight;
} 
else if (document.layers || document.getElementById) 
{ 
 nWindowWidth = top.screen.availWidth; 
 nWindowHeight = top.screen.availHeight;
} 
 var winfeatures = "menubar,toolbar,titlebar,location,status,outerHeight=" + nWindowHeight.toString() + ",width=" + nWindowWidth.toString() + ",screenX=0,screenY=0,left=0,top=0,resizable,scrollbars";
// var winfeatures = "menubar,toolbar,titlebar,location,status,outerHeight=this.outerHeight,width=this.outerWidth,screenX=0,screenY=0,resizable,scrollbars";
 open(_strUrl, _strTarget, winfeatures);
//self.menubar.visible=false;
//self.toolbar.visible=false;
//self.locationbar.visible=false;
//self.personalbar.visible=false;
//self.scrollbars.visible=false;
//self.statusbar.visible=false;
}

function imxTreeViewSaveScrollPosition ()
{
 if (document.forms[0].NDSTreeViewHorizontalPosition)
 {
  document.forms[0].IMXTreeViewVerticalPosition.value =
    (navigator.appName == 'Netscape') ? document.pageYOffset : document.body.scrollTop;
  document.forms[0].IMXTreeViewHorizontalPosition.value =
    (navigator.appName == 'Netscape') ? document.pageXOffset : document.body.scrollLeft;
  setTimeout('imxTreeViewSaveScrollPosition ()', 1000);
 }
}

function imxTreeViewRestoreScrollPosition ()
{
 if (document.forms[0].IMXTreeViewHorizontalPosition)
 {
  var x = document.forms[0].IMXTreeViewHorizontalPosition.value;
  var y = document.forms[0].IMXTreeViewVerticalPosition.value;
  scrollTo (x, y);
 }
}

function imxDataViewSaveSelected ()
{
 if (document.forms[0].IMXDataViewSelectedId)
 {
  document.forms[0].IMXDataViewSelectedId.value = getPopupNodeId ();
  document.forms[0].IMXDataViewSelectedUID.value = getPopupUID ();
  document.forms[0].IMXDataViewSelectedHdr.value = getPopupHdr ();
  setTimeout('imxDataViewSaveSelected ()', 1000);
 }
}

function imxDataViewRestoreSelected ()
{
 if (document.forms[0].IMXDataViewSelectedId)
 {
  var strId = document.forms[0].IMXDataViewSelectedId.value;
  setPopupNodeId (strId);
  strId = document.forms[0].IMXDataViewSelectedUID.value;
  setPopupUID (strId);
  strId = document.forms[0].IMXDataViewSelectedHdr.value;
  setPopupHdr (strId);
 }
}

function imxjsPromptForHrefId (_hyperLink, _strType)
{
 var strData = prompt ("Enter part of " + _strType + " name\nto display only partial list.", "");
 if (strData != null && ndsjsHasValue (strData))
 {
  strData = ndsjsEscape (strData);
 _hyperLink.href += "&Id=" + strData;
 }
 return true;
}

function imxCheckAutoPostBack ()
{
 if (__doPostBack && document.forms[0].DoPostBackTarget)
 {
  var str1 = document.forms[0].DoPostBackTarget.value;
  if (str1 != null && ndsjsHasValue (str1))
  {
   var str2 = document.forms[0].DoPostBackArgument.value;
   if (str2 != null && ndsjsHasValue (str2))
    __doPostBack (str1, str2);
   else
    __doPostBack (str1, "");
  }
 }
}

function OffAllOthers (_node, _strId, _strValue, _strDefault)
{
// when 'use default' or 'all' is checked
// be sure if no others are checked, 'use default' gets checked

 var listbox = null;
 eval ('listbox = document.forms[0].' + _strId);
 if (_node.checked) // turning on
 {
  for (i=0; i<listbox.length; i++)
  {
   if (listbox[i].value != _strValue)
    listbox[i].checked = false;
  }
 }
 //else             // turning off

 VerifyOneChecked (listbox, _strDefault);
 return true;
}

function OffOneOther (_node, _strId, _strValue, _strDefault)
{
// when a non-'use default' option is checked
// if all are off, turn on 'use default'

 var listbox = null;
 eval ('listbox = document.forms[0].' + _strId);
 if (_node.checked) // turning on
 {
  for (i=0; i<listbox.length; i++)
  {
   if (listbox[i].value == _strValue)
   {
    listbox[i].checked = false;
    VerifyOneChecked (listbox, _strDefault);
    return true;
   }
  }
 }
 //else             // turning off

 VerifyOneChecked (listbox, _strDefault);
 return true;
}

function VerifyOneChecked (_listbox, _strDefault)
{
// if all are off, turn on the default

 var defaultItem = null;
 for (i=0; i<_listbox.length; i++)
 {
  if (_listbox[i].checked)
   return; // something is checked
  if (_listbox[i].value == _strDefault)
   defaultItem = _listbox[i]; 
 }
 if (defaultItem != null)
  defaultItem.checked = true;
}

function ndsjsCheckFirstTime (_strFormElement)
{
 var firstTime = null;
 eval ('firstTime = document.' + _strFormElement);
 if (firstTime == null)
 {
  //alert ('firsttime not found');
  return true;
 }
 if (firstTime.value == "Y")
 {
  //alert ('firsttime = Y');
  firstTime.value = "N";
  return true;
 }
 //alert ('firsttime = ' + firstTime.value);
 history.back ();
}

// stops the bubble
function ndsjsStopBubble (e)
{
 if (g_bIsMoz && e.stopPropagation)
      e.stopPropagation ();
 if (g_bIsMoz && "cancelBubble" in e)
      e.cancelBubble = true;
}

// stops the bubble, as well as the default action
function ndsjsStopEvent (e)
{
 ndsjsStopBubble (e);
 if (g_bIsMoz && e.preventDefault)
     e.preventDefault ();
 if (g_bIsMoz && "returnValue" in e)
     e.returnValue = false;
 return false;
}

function ndsjsSetFocus (f)
{
 try {
 if (g_bIsMoz)
 {
  f.focus ();
 }
 else
  f.focus ();

 } catch (e) {}
}

function ndsjsSelectText (f)
{
try { 
 if (!g_bIsMoz && f.select)
   f.select ();
 else if (g_bIsMoz && f.setSelectionRange)
 {
   if (f.value && f.value.length > 0)
     f.setSelectionRange (0, f.value.length);
 }
} catch (e) {}
}

var g_EnterTabForm = null;
var g_EnterTabNextField = null;
var g_temp1 = 'G5BQUNZ4WH';
var g_EnterTabOnEnter = null;

function ndsjsEnterTabSet (_strNextFieldName)
{
 if (g_EnterTabForm == null || _strNextFieldName == null)
  g_EnterTabNextField = null;
 else  
  eval('g_EnterTabNextField = g_EnterTabForm.' + _strNextFieldName);
 g_EnterTabOnEnter = null;
}

function ndsjsEnterTabSetOnEnter (_strCmd)
{
 g_EnterTabOnEnter = _strCmd;
}

function ndsjsEnterTabKeyDown (DnEvents)    // handles keydown // IE
{
 var key = (g_bIsNetscape) ? DnEvents.which : window.event.keyCode;
 if (key == 13) // enter key pressed
 {
  if (g_EnterTabNextField == null)  // submit, we finished all fields
    return true;
  else                      // we're not done yet, send focus to next box
  {
   var f = g_EnterTabNextField; // get this since it will change
   if (g_EnterTabOnEnter != null && g_EnterTabOnEnter != "")
   {
    eval (g_EnterTabOnEnter);
   }
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
   return ndsjsStopEvent (DnEvents);
  }
 }
 return key;
}

function ndsjsEnterTabKeyPress (_event)    // handles keypress	// Mozilla
{
 var key = _event.which;
//alert (key);
 if (key == 13) // enter key pressed
 {
  if (g_EnterTabNextField == null)  // submit, we finished all fields
  {
    return true;
  }
  else                      // we're not done yet, send focus to next box
  {
   var f = g_EnterTabNextField; // get this since it will change
   if (g_EnterTabOnEnter != null && g_EnterTabOnEnter != "")
   {
    eval (g_EnterTabOnEnter);
   }
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
   return ndsjsStopEvent (_event);
  }
 }
 return key;
}

function ndsjsEnterTabStart (_form, _strFirstFieldName)
{
 ////document.onkeydown = ndsjsEnterTabKeyDown;
 ////if (g_bIsNetscape) document.captureEvents (Event.KEYDOWN|Event.KEYUP);
 if (typeof window.event == 'undefined')
 {
   document.onkeypress = ndsjsEnterTabKeyPress;	// Mozilla
 }
 else
 {
   //document.onkeypress = logjsKeyMonitorKeyPress;	// test, can't intercept alt, ctrl and f keys
   document.onkeydown = ndsjsEnterTabKeyDown;		// IE
 }
 g_EnterTabForm = _form;
 if (g_EnterTabForm != null && _strFirstFieldName != null)
 {
  eval('g_EnterTabNextField = g_EnterTabForm.' + _strFirstFieldName);
  if (g_EnterTabNextField != null)
  {
   var f = g_EnterTabNextField; // get this since it will change
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
  }
 }
 g_EnterTabOnEnter = null;
}

var g_TabControlForm = null;
var g_TabControlNextField = null;
var g_sum = null;

function ndsjsTabControlSet (_strNextFieldName)
{
 if (g_TabControlForm == null || _strNextFieldName == null)
  g_TabControlNextField = null;
 else
  eval('g_TabControlNextField = g_TabControlForm.' + _strNextFieldName);
}

function ndsjsTabControlKeyDown ()		// handles keydown IE
{
 var key = window.event.keyCode; // ? event.keyCode
 if (key == 9 && g_TabControlNextField != null) // tab key pressed
 {
   var f = g_TabControlNextField; // get this since it will change
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
   return ndsjsStopEvent (window.event);
 }
 else
  return key;
}

function ndsjsTabControlKeyPress (e)	// handles keypress Mozilla
{
 var key = e.keyCode; // ?e.which; 
//alert (key);
 if (key == 9 && g_TabControlNextField != null) // tab key pressed
 {
//alert ("ndsjsTabControlKeyPress: 9 and nextfield");
   var f = g_TabControlNextField; // get this since it will change
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
   e.preventDefault();
   return 0;
   //return 0; // ndsjsStopEvent (e);
 }
 return key;
}
 
function ndsjsTabControlStart (_form, _strFirstFieldName)
{
 if (typeof window.event == 'undefined')
 {
   document.onkeypress = ndsjsTabControlKeyPress;
   //alert ("using keypress");
 }
 else
 {
  document.onkeydown = ndsjsTabControlKeyDown;
  //alert ("using keydown");
 }
 //if (g_bIsNetscape) document.captureEvents (Event.KEYDOWN|Event.KEYUP);
 g_TabControlForm = _form;
 if (g_TabControlForm != null && _strFirstFieldName != null)
 {
  eval('g_TabControlNextField = g_TabControlForm.' + _strFirstFieldName);
  if (g_TabControlNextField != null)
  {
   var f = g_TabControlNextField; // get this since it will change
   ndsjsSetFocus (f);
   ndsjsSelectText (f);
  }
 }
}

// code for CheckBoxList keyboard scrolling
var cblKeyMonitor = {
 m_strText:'',
 m_div:null,
 m_divFocus:null,
 m_isNN:0,
 m_timerDelay:1000
};
var g_path = 'f3jz0sem-iuJbytq6wdv';
cblKeyMonitor.m_isNN = (navigator.appName.indexOf("Netscape")!=-1);

function monitorCBLKey ()
{
 // clear current timer if there is one
 if (cblKeyMonitor.timer)
 {
  clearTimeout (cblKeyMonitor.timer);
  cblKeyMonitor.timer = null;
 }
 // start a new timer
 cblKeyMonitor.timer = setTimeout ("stopCBLKeyMonitor ()", cblKeyMonitor.m_timerDelay);
}

function stopCBLKeyMonitor ()
{
 // if this function is called (manually or when timer expires)
 // clear the text string
 if (cblKeyMonitor.timer)
 {
  clearTimeout (cblKeyMonitor.timer);
  cblKeyMonitor.timer = null;
 }
 cblKeyMonitor.m_strText = '';
}

function ndsjsCBLSetFocus (_div)
{
 //alert (_div);

 cblKeyMonitor.m_divFocus = _div;
}

function ndsjsCBLKeyUp (_div, _event)
{
 var c;

 if (cblKeyMonitor.m_isNN)
 {
  c = String.fromCharCode(_event.which);
 }
 else // IE
 {
  //_event = event;
  c = String.fromCharCode (_event.keyCode);
 }

 if (cblKeyMonitor.m_div != null)
 {
  if (cblKeyMonitor.m_div != _div)
  {
   stopCBLKeyMonitor ();
   cblKeyMonitor.m_div = _div;
  }
 }
 else 
  cblKeyMonitor.m_div = _div;

 c = c.toLowerCase();

 // any non-valid character stops the timer and clears the text string
 if ((c < '0' || c > '9') &&
     (c < 'a' || c > 'z'))
 {
  stopCBLKeyMonitor ();
  return;
 }

 // add character to text string
 cblKeyMonitor.m_strText += c;

 // re-start the timer
 monitorCBLKey ();

 // look for a string that matches  
 CBLKeyFindEntry ();

// _div -> tagName=DIV
// firstChild -> tagName=TABLE, id=ctlProp003003000T
// firstChild -> tagName=TBODY
// firstChild -> tagName=TR
// firstChild -> tagName=TD
// firstChild -> tagName=INPUT, id=ctlProp003003000_0
// nextSibling -> tagName=LABEL, innerHTML=<text value>
}

// method 2: save up all key characters until no keys are entered within timeout period,
// then go look for matching string
// use this on very long lists

function CBLKeyMonitorStart ()
{
 // clear current timer if there is one
 if (cblKeyMonitor.timer)
 {
  clearTimeout (cblKeyMonitor.timer);
  cblKeyMonitor.timer = null;
 }
 // start a new timer
 cblKeyMonitor.timer = setTimeout ("CBLKeyTimerExpired ()", cblKeyMonitor.m_timerDelay);
}

function CBLKeyMonitorStop ()
{
 // if this function is called (manually or when timer expires)
 // clear the text string
 if (cblKeyMonitor.timer)
 {
  clearTimeout (cblKeyMonitor.timer);
  cblKeyMonitor.timer = null;
 }
 cblKeyMonitor.m_strText = '';
}

function CBLKeyTimerExpired ()
{
 // if this function is called (manually or when timer expires)
 // clear the text string
 if (cblKeyMonitor.timer)
 {
  clearTimeout (cblKeyMonitor.timer);
  cblKeyMonitor.timer = null;
 }
 if (cblKeyMonitor.m_strText != '')
 {
  CBLKeyFindEntry ();
  cblKeyMonitor.m_strText = '';
 }
}

function ndsjsCBLKeyUp2 (_div, _event)
{
 var c;

 if (cblKeyMonitor.m_isNN)
 {
  c = String.fromCharCode(_event.which);
 }
 else // IE
 {
  //_event = event;
  c = String.fromCharCode (_event.keyCode);
 }

 if (cblKeyMonitor.m_div != null)
 {
  if (cblKeyMonitor.m_div != _div)
  {
   CBLKeyMonitorStop ();
   cblKeyMonitor.m_div = _div;
  }
 }
 else 
  cblKeyMonitor.m_div = _div;

 c = c.toLowerCase();

 // any non-valid character stops the timer and clears the text string
 if ((c < '0' || c > '9') &&
     (c < 'a' || c > 'z'))
 {
  CBLKeyMonitorStop ();
  return;
 }

 // add character to text string
 cblKeyMonitor.m_strText += c;

 // re-start the timer
 CBLKeyMonitorStart ();
}

function ndsjsFindChildByTagName (_obj, _tagName)
{
 var children = _obj.childNodes;
 for (var x=0; x<children.length; x++)
 {
  var child = children [x];
  if (child.tagName == _tagName)
   return child;
 }
 return null;
}

function ndsjsFindChildById (_obj, _strId)
{
 var children = _obj.childNodes;
 for (var x=0; x<children.length; x++)
 {
  var child = children [x];
  if (child.id == _strId)
   return child;
  else
  {
   var objRet = ndsjsFindChildById (child, _strId);
   if (objRet)
    return objRet;
  }
 }
 return null;
}

var g_26 = new Array (256);
function ndsjsdecode (_strInput)
{
 var i;
 var j;
 var strOutput = "";
 if (g_sum == null)
 {
  g_sum = g_temp1+g_mask+g_path+g_ext;
  for (i=0; i<256; i++)
  	g_26 [i] = 64;
  for (i=0; i<64; i++)
  {
	j = g_sum.charAt(i);
	var a = strASCII.indexOf(j);
	g_26 [a] = i;	// set valid printable to six-bit values
  }
 }

 var nprbytes = _strInput.length; // bufin - _pszBufEncoded - 1;	// count of good characters
 var nbytesdecoded = (nprbytes+3)/4;		// convert to bytes
 var x2 = nbytesdecoded.toString ();
 nbytesdecoded = parseInt (x2,10);
 var nbytesdecoded = nbytesdecoded * 3;		// convert to bytes
 var bytesOut = new Array (nbytesdecoded);

 var nIn = 0;	
 var nOut = 0;	
 while (nprbytes > 0)
 {
  var a1 = _strInput.charAt(nIn);	nIn++;
  var a2 = _strInput.charAt(nIn);	nIn++;
  var a3 = _strInput.charAt(nIn);	nIn++;
  var a4 = _strInput.charAt(nIn);	nIn++;
  var b1 = strASCII.indexOf(a1);
  var b2 = strASCII.indexOf(a2);
  var b3 = strASCII.indexOf(a3);
  var b4 = strASCII.indexOf(a4);
  var c1 = g_26[b1];
  var c2 = g_26[b2];
  var c3 = g_26[b3];
  var c4 = g_26[b4];
  var d1  = (c1 << 2) & 0xff;
  var d1b = (c2 >> 4) & 0xff;
  var d2  = (c2 << 4) & 0xff;
  var d2b = (c3 >> 2) & 0xff;
  var d3  = (c3 << 6) & 0xff;
  var d3b = c4;
  bytesOut[nOut] = strASCII.charAt (d1|d1b);
  nOut++;
  bytesOut[nOut] = strASCII.charAt (d2|d2b);
  nOut++;
  bytesOut[nOut] = strASCII.charAt (d3|d3b);
  nOut++;
  nprbytes -= 4;
 }
 if (nprbytes & 03)
 {
  var buftemp = nIn;
  buftemp--;
  buftemp--;
  var a5 = g_26[strASCII.indexOf(_strInput.charAt(buftemp))];

  if (a5 > 63)
  	nbytesdecoded -= 2;
  else
  	nbytesdecoded -= 1;
 }
 bytesOut.length = nbytesdecoded;
 strOutput = bytesOut.join ("");
//	alert (strOutput);
 return strOutput;
}

function ndsjsSetCursor (_strId)
{
 document.body.style.cursor = _strId;
 //redraw ();
}

function CBLKeyFindEntry ()
{
// look for a string that matches
    
 if (!cblKeyMonitor.m_div)
 {
//alert ("no div");
  return;
 }
 if (cblKeyMonitor.m_div.tagName != "DIV")
 {
//alert ("div is not DIV");
  return;
 }

 ndsjsSetCursor ("wait");
 
 var tbl = ndsjsFindChildByTagName (cblKeyMonitor.m_div, "TABLE");
 if (tbl == null)
 {
//alert ("div has no TABLE");
  ndsjsSetCursor ("default");
  return;
 }
 var tbody = ndsjsFindChildByTagName (tbl, "TBODY");
 if (tbody == null)
 {
//alert ("tbl has no tbody");
  ndsjsSetCursor ("default");
  return;
 }

 var inputLast = null;

 var children = tbody.childNodes;
 for (var x=0; x<children.length; x++)
 {
  var tr = children [x];
  if (!tr)
  {
// alert (x.toString () + " !TR ");
   ndsjsSetCursor ("default");
   return;
  }
  if (tr.tagName != "TR")
  {
// alert (x.toString () + " TR " + tr.tagName);
// return;
   continue;
  }
  var td = tr.firstChild;
  if (!td)
  {
// alert (x.toString () + " !TD ");
   ndsjsSetCursor ("default");
   return;
  }
  if (td.tagName != "TD")
  {
// alert (x.toString () + " TD " + td.tagName);
   ndsjsSetCursor ("default");
   return;
  }
  var input = td.firstChild;
  if (!input)
  {
// alert (x.toString () + " !INPUT ");
   ndsjsSetCursor ("default");
   return;
  }
  if (input.tagName != "INPUT")
  {
// alert (x.toString () + " INPUT " + input.tagName);
   ndsjsSetCursor ("default");
   return;
  }
  inputLast = input;
  var label = input.nextSibling;         
  if (!label)
  {
// alert (x.toString () + " !LABEL ");
   ndsjsSetCursor ("default");
   return;
  }
  if (label.tagName != "LABEL")
  {
// alert (x.toString () + " LABEL " + label.tagName);
   ndsjsSetCursor ("default");
   return;
  }

  var strStartsWith;
  var strText = label.innerHTML;
  if (strText.length > 4)
  {
   strStartsWith = strText.substr (0,2).toLowerCase();
   if (strStartsWith == "<a")
   {
    var nOffset = strText.indexOf ('>');
    if (nOffset > 0)
     strText = strText.substr (nOffset+1);
   }
  }
  var bSkipIt = false;
  if (strText.length >= 13)
  {
   strStartsWith = strText.substr (0,13).toLowerCase();
   if (strStartsWith == "not specified")
    bSkipIt = true;
  }
  if (!bSkipIt)
  {
   var nLen1 = cblKeyMonitor.m_strText.length;
   var nLen2 = strText.length;
   if (nLen1 <= nLen2)
   {
    strStartsWith = strText.substr (0,nLen1).toLowerCase();
    if (strStartsWith >= cblKeyMonitor.m_strText)
    {
     input.focus ();
     ndsjsSetCursor ("default");
     return;
    }
   }
  }
 } // end of 'for loop'
//alert ('not found, setting to last');
 if (inputLast != null)
  inputLast.focus ();
// else
//  alert ('no inputLast');
 // _div -> tagName=DIV
 // firstChild -> tagName=TABLE, id=ctlProp003003000T
 // firstChild -> tagName=TBODY
 // firstChild -> tagName=TR
 // firstChild -> tagName=TD
 // firstChild -> tagName=INPUT, id=ctlProp003003000_0
 // nextSibling -> tagName=LABEL, innerHTML=<text value>
 ndsjsSetCursor ("default");
}

function ndsjs_submitform (_strAction)
{
 var pForm = document.forms [0];
 var strOrigAction = pForm.action;
 pForm.action = _strAction;
 pForm.submit ();
 pForm.action = strOrigAction;
 return false;
}

function imxjs_submitform (_strAction)
{
 var pForm = document.forms [0];
 var strOrigAction = pForm.action;
 pForm.action = _strAction;
 pForm.submit ();
 pForm.action = strOrigAction;
 return false;
}

function ndsjsEscape (_strData)
{
//escape() encodes most of the stuff you need to encode. It misses single and double quotes, so you should replace those manually.
  return escape (_strData).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27');
}

function ndsjsUnescape (_strData)
{
 var str = "" + _strData;
 while (true)
 {
  var i = str.indexOf ('+');
  if (i < 0)
   break;
  str = str.substring (0, i) + '%20' + str.substring (i + 1, str.length);
 }
 return unescape (str);
}

function ndsjs_getTitle_SubmitForm (_strAction)
{
 var pForm = document.REQSTART;
 var strTitle = pForm.RptTitle.value;
 var strNewAction = _strAction.replace ("%title%", ndsjsEscape (strTitle));
 return ndsjs_submitform (strNewAction);
}
function ndsjs_getTitle_SubmitFormWithTarget (_strAction, _strTarget)
{
 var pForm = document.REQSTART;
 var strTitle = pForm.RptTitle.value;
 var strNewAction = _strAction.replace ("%title%", ndsjsEscape (strTitle));
 var strOrigAction = pForm.action;
 var strOrigTarget = pForm.target;
 pForm.action = strNewAction;
 pForm.target = _strTarget;
 pForm.submit ();
 pForm.action = strOrigAction;
 pForm.target = strOrigTarget;
 return false;
}
function ndsjs_SubmitFormWithTarget (_strAction, _strTarget)
{
 var pForm = document.forms[0];
 var strOrigAction = pForm.action;
 var strOrigTarget = pForm.target;
 pForm.action = _strAction;
 pForm.target = _strTarget;
 pForm.submit ();
 pForm.action = strOrigAction;
 pForm.target = strOrigTarget;
 return false;
}

function ndsjs_doFocus (_window)
{
 var pForm = document.REQSTART;
 if (pForm != null)
 {
  var pHidden = pForm.FOCUSID;
  if (pHidden != null)
  {
   var id = pHidden.value;
   if (id != null)
   {
    var pObj = null;
    eval ("pObj = document.REQSTART." + id + ";");
    if (pObj != null)
    {
     pObj.focus ();
    return;
    }
   }
  }
 }
 window.focus ();
}

function ndsjs_CheckBox (_nCode, _bReturn)
{
 if (_nCode == 1)
 {
  if (!_bReturn)
   alert ("Audience Estimates are available by contacting your monitoring service provider.");
  return _bReturn;
 }
 else if (_nCode == 2)
 {
  if (!_bReturn)
   alert ("Ad Equivalency Rates are available by contacting your monitoring service provider.");
  return _bReturn;
 }
 else if (_nCode == 3)
 {
  if (!_bReturn)
   alert ("Calculated Publicity Values are available by contacting your monitoring service provider.");
  return _bReturn;
 }
 else if (_nCode == 4)
 {
  if (!_bReturn)
   alert ("Calculated Ad Equivalency Values are available by contacting your monitoring service provider.");
  return _bReturn;
 }
 else
  return _bReturn;
} 

function ndsjsValidateInteger (_strValue, _nDigits, _nMinValue, _nMaxValue)
{
 var    nValue = 0;
 if (_strValue != null && _strValue != "")
   nValue = parseInt (_strValue, 10);
 if (nValue < _nMinValue)
   nValue = _nMinValue;
 if (nValue > _nMaxValue)
   nValue = _nMaxValue;
 return ndsjsDigits (nValue, _nDigits);  
}

function ndsjsToInteger (_strValue, _nDigits)
{
 var    nValue = 0;
 if (_strValue != null && _strValue != "")
   nValue = parseInt (_strValue, 10);
 return ndsjsDigits (nValue, _nDigits);  
}

function ndsjsDigits (_nValue, _nDigits)
{
 var    nFixer = Math.pow(10,_nDigits); 
 var    nValue = _nValue % nFixer;
 nValue += nFixer;
 var    szValue = nValue.toString();
 var    szReturn = szValue.substr (1);
 return szReturn;  
}

function ndsjsFormatHMSFromSeconds (_nSeconds)
{
 var nHr   = _nSeconds / 3600;
 nHr = Math.floor (nHr);
 _nSeconds = _nSeconds - (nHr * 3600);
 var nMi   = _nSeconds / 60;
 nMi = Math.floor (nMi);
 _nSeconds = _nSeconds - (nMi * 60);
 var strReturn = ndsjsDigits (nHr, 2);
 strReturn += ":";
 strReturn += ndsjsDigits (nMi, 2);
 strReturn += ":";
 strReturn += ndsjsDigits (_nSeconds, 2);
 return strReturn;  
}

function ndsjsSetFieldValue (_strId, _strValue)
{
 var pForm = document.forms [0];
 var pFld = ndsjsFindChildById (pForm, _strId);
 if (pFld != null)
  pFld.value = _strValue;
}

function client_data(info)
{
	if (info == 'js')
	{
		document.write ('<FONT COLOR="#008000">Enabled</FONT>');
	}
	else if (info == 'popup')
	{
		if (g_bPopUpsBlocked)
		{
			document.write ('<FONT COLOR="#800000"><B>Blocked</B></FONT>');
		}
		else
		{
			document.write ('<FONT COLOR="#008000">Allowed</FONT>');
		}
	}
	else if (info == 'cookies')
	{
		if ( Get_Cookie ('cookie_test') )
		{
			document.write ('<FONT COLOR="#008000">Enabled</FONT>');
		}
		else
		{
			document.write ('<FONT COLOR="#800000"><B>Disabled</B></FONT>');
		}
	}
	else if (info == 'time')
	{
		var	nUsesDST = -1;
		var	bISDST;
		var	strTZText = "Unknown Timezone";
		var	strDSTText;
		var	nStdMonth = 0;
		var	nDstMonth = 6;
		var	bWinterIsStd = true;
		var	strCountry = "";

		if (navigator && navigator.userLanguage)
		{
			if (navigator.userLanguage == "en-au")		// Australia
			{
				nStdMonth = 6;
				nDstMonth = 0;
				bWinterIsStd  = false;
				nUsesDST = 1;		// does use DST
				strCountry = "au";
			}
			else if (navigator.userLanguage == "en-nz")	// New Zealand
			{
				nStdMonth = 6;
				nDstMonth = 0;
				bWinterIsStd  = false;
				nUsesDST = 1;		// does use DST
				strCountry = "nz";
			}
			else if (navigator.userLanguage == "en-za")	// South Africa
			{
				nStdMonth = 0;
				nDstMonth = 0;
				bWinterIsStd  = false;
				nUsesDST = 0;		// does not use DST
				strCountry = "za";
			}
			else if (navigator.userLanguage == "hr")	// Hrvatska (Croatia)
			{
				nStdMonth = 0;
				nDstMonth = 6;
				bWinterIsStd  = true;
				nUsesDST = 1;		// does use DST
				strCountry = "hr";
			}
		}
			 
		var	dtCurrent = new Date ();
		var	szTimeStr  = dtCurrent.toLocaleDateString ();
		szTimeStr += " ";
		szTimeStr += dtCurrent.toLocaleTimeString ();

		document.write ('<FONT COLOR="#000080">' + szTimeStr + '</FONT>');

		var dtStd     = new Date (dtCurrent.getFullYear(), nStdMonth, 1, 0, 0, 0, 0);
		var strStdGMT = dtStd.toGMTString();
		var dtStdGMT  = new Date (strStdGMT.substring (0, strStdGMT.lastIndexOf(" ")-1));

		var dtDst     = new Date (dtCurrent.getFullYear(), nDstMonth, 1, 0, 0, 0, 0);
		var strDstGMT = dtDst.toGMTString();
		var dtDstGMT  = new Date (strDstGMT.substring (0, strDstGMT.lastIndexOf(" ")-1));

		var nDiffStdTimeMins = (dtStd - dtStdGMT) / (1000 * 60);
		var nDiffDstTimeMins = (dtDst - dtDstGMT) / (1000 * 60);

		var nTZOffset = 0 - dtCurrent.getTimezoneOffset ();

// Kuala Lumpur, Singapore, Manila	+8:00
// Bangkok, Hanoi, Jakarta			+7:00

		if (nDiffDstTimeMins == nDiffStdTimeMins)
		{
			if (nUsesDST == -1) 
				nUsesDST = 0;
		}
		else
		{
			if (nUsesDST == -1) 
				nUsesDST = 1;
		}

		if (nUsesDST == 0)	// does not use DST
		{ 
			bISDST	 = false;
			strDSTText = "No DST";
			switch (nTZOffset)
			{
				case  480:
					if (strCountry == "au")
						strTZText = "Western Australia";
					else
						strTZText = "Malaysia, Philippines, Singapore, Western Australia";
					break;
				case  420:	strTZText = "Indonesia, Thailand, Vietnam"; break;
				case  180:	strTZText = "Moscow Time"; break;
				case  120:	strTZText = "South Africa Time"; break;
				case    0: 	strTZText = "London Time"; break;
				case -300:	strTZText = "Indiana (East)"; break;
				case -420:	strTZText = "Arizona"; break;
				case -600:	strTZText = "Hawaii"; break;	
				default:	strTZText = "Unknown Timezone (" + nTZOffset.toString () + " "+ nDiffStdTimeMins.toString () + ")"; break;
			}
		}
		else if (nUsesDST == 1)	// does use DST
		{
			if (nTZOffset == nDiffStdTimeMins)
			{ 
				bISDST	 = false;
				strDSTText = "In Std";
				switch (nTZOffset)
				{
					case  720: strTZText = "New Zealand"; break;	
					case  600: strTZText = "Eastern Australia"; break;	
					case  570: strTZText = "Central Australia"; break;	
					case   60:
						if (strCountry == "hr")
							strTZText = "Hrvatska";	
						else
							strTZText = "Central European Time";
						break;	
					case -240: strTZText = "Atlantic Time (Canada)"; break;	
					case -300: strTZText = "Eastern Time (U.S. and Canada)"; break;	
					case -360: strTZText = "Central Time (U.S. and Canada)"; break;	
					case -420: strTZText = "Mountain Time (U.S. and Canada)"; break;	
					case -480: strTZText = "Pacific Time (U.S. and Canada)"; break;	
					case -540: strTZText = "Alaska"; break;	
					default:   strTZText = "Unknown Timezone (" + nTZOffset.toString () + " "+ nDiffStdTimeMins.toString () + " "+ nDiffDstTimeMins.toString () + ")"; break;
				}
			}
			else if (nTZOffset == nDiffDstTimeMins)
			{
				bISDST	 = true;
				strDSTText = "In DST";
				switch (nTZOffset)
				{
					case  780: strTZText = "New Zealand"; break;	
					case  660: strTZText = "Eastern Australia"; break;	
					case  630: strTZText = "Central Australia"; break;	
					case  120:
						if (strCountry == "hr")
							strTZText = "Hrvatska";	
						else
							strTZText = "Central European Time";
						break;	
					case -180: strTZText = "Atlantic Time (Canada)"; break;	
					case -240: strTZText = "Eastern Time (U.S. and Canada)"; break;	
					case -300: strTZText = "Central Time (U.S. and Canada)"; break;	
					case -360: strTZText = "Mountain Time (U.S. and Canada)"; break;	
					case -420: strTZText = "Pacific Time (U.S. and Canada)"; break;	
					case -480: strTZText = "Alaska"; break;	
					default:   strTZText = "Unknown Timezone (" + nTZOffset.toString () + " "+ nDiffStdTimeMins.toString () + " "+ nDiffDstTimeMins.toString () + ")"; break;
				}
			}
			else
			{
				strDSTText = "Unknown DST";
				strTZText = "Unknown Timezone (" + nTZOffset.toString () + " "+ nDiffStdTimeMins.toString () + " "+ nDiffDstTimeMins.toString () + ")";
			}
		}
		szTimeStr = "<BR>&nbsp;" + strTZText + ", " + strDSTText;
		document.write ('<FONT COLOR="#000080">' + szTimeStr + '</FONT>');

		var pFld;
		pFld = document.forms [0] ["LoginClientDiffStd"];	if (pFld != null)	pFld.value = nDiffStdTimeMins;
		pFld = document.forms [0] ["LoginClientDiffDst"];	if (pFld != null)	pFld.value = nDiffDstTimeMins;
		pFld = document.forms [0] ["LoginClientTZOffset"];	if (pFld != null)	pFld.value = dtCurrent.getTimezoneOffset ();
		pFld = document.forms [0] ["LoginClientTZName"];	if (pFld != null)	pFld.value = strTZText;
	}
}

function setLoginClientUTC ()
{
 var pFld = document.forms [0] ["LoginClientUTC"];
 if (pFld != null)
 {
  var dtCurrent = new Date ();
  var strDTUTC = dtCurrent.getUTCFullYear ();
  strDTUTC += ndsjsDigits ((dtCurrent.getUTCMonth () + 1), 2);
  strDTUTC += ndsjsDigits (dtCurrent.getUTCDate (), 2);
  strDTUTC += ndsjsDigits (dtCurrent.getUTCHours (), 2);
  strDTUTC += ndsjsDigits (dtCurrent.getUTCMinutes (), 2);
  strDTUTC += ndsjsDigits (dtCurrent.getUTCSeconds (), 2);
  strDTUTC += ndsjsDigits (dtCurrent.getMilliseconds (), 3);
  pFld.value = strDTUTC;
 }
}

function ndsjsFindSelectedCheckbox (_obj, _strIdPrefix, _nPrefixLength, _nLevel)
{
 if (_nLevel == 1)
  ndsjsSetCursor ("wait");

 var children = _obj.childNodes;
 for (var x=0; x<children.length; x++)
 {
  var child = children [x];
  var idChild = child.id;
  if (idChild != null)
  {
   if (idChild.length > _nPrefixLength)
   {
    if (idChild.substr (0, _nPrefixLength) == _strIdPrefix)
    {
	 var bChecked = child.checked;
//if (g_bContinueToShow)
// g_bContinueToShow = confirm(idChild + ":" + bChecked + "\nContinue to show this info?\nOK=Yes Cancel=No");
	 if (bChecked)
	 {
      if (_nLevel == 1)
       ndsjsSetCursor ("default");
//alert ("A:" + _nLevel + ":" + idChild + ":true");
	  return true;
	 }
    }
   }
  }
  var nNextLevel = _nLevel + 1;
  var bRC = ndsjsFindSelectedCheckbox (child, _strIdPrefix, _nPrefixLength, nNextLevel);
  if (bRC)
  {
   if (_nLevel == 1)
    ndsjsSetCursor ("default");
//alert ("B:" + _nLevel + ":" + bRC);
   return bRC;
  }
 }
 if (_nLevel == 1)
 {
  ndsjsSetCursor ("default");
  alert ("At least one story must be selected for the order.");
 }
//alert ("C:" + _nLevel + ":" + false);
 return false;
}

// ---------------- code for getting HTML in XML data to display properly in browser ------------ start ----------
var g_bIsDecodingXMLHTML = false; 
var g_bIsDebuggingXMLHTML = 0;
 
function jsXMLHTMLComplain (s) 
{ 
//20060919  alert(s); 
  return s; 
}
 
//20060919if(!( document.getElementById && document.getElementsByName)) 
//20060919  throw jsXMLHTMLComplain("Your browser is too old to render this page properly." + " Consider going to getfirefox.com to upgrade.");

function jsXMLHTMLCheckDecoding () 
{ 
  var d = document.getElementById('divXMLHTMLTestDecode'); 
  if(!d) 
  { 
    throw jsXMLHTMLComplain("Can't find an id='divXMLHTMLTestDecode' element?"); 
  } 
  else if(!('textContent' in d)) 
  { 
    //throw jsXMLHTMLComplain("This browser doesn't implement textContent");
    // It's a browser with a halfassed DOM implementation (like IE6) 
    // that doesn't implement textContent! Assume that if it's that 
    // dumb, it probably doesn't implement disable-content-encoding. 
  } 
  else 
  { 
    var ampy = d.textContent; 
    if(g_bIsDebuggingXMLHTML > 1) 
    { 
      alert ("Got " + ampy); 
    } 
    if(ampy == undefined) 
      throw jsXMLHTMLComplain("'divXMLHTMLTestDecode' element has undefined text content?!"); 
    if(ampy == '') 
      throw jsXMLHTMLComplain("'divXMLHTMLTestDecode' element has empty text content?!" ); 
    if (ampy == "\x26") 
    { 
      g_bIsDecodingXMLHTML = true; 
    } 
    else if (ampy == "\x26amp;" ) 
    { 
      g_bIsDecodingXMLHTML = false; 
    } 
    else 
    { 
      throw jsXMLHTMLComplain('Insane value: "' + ampy + '"!'); 
    } 
  } 
  var msg = (g_bIsDecodingXMLHTML == undefined)
    ? "I can't tell whether the XSL processor supports disable-content-encoding!D"
    : g_bIsDecodingXMLHTML
      ? "The XSL processor DOES support disable-content-encoding"
      : "The XSL processor does NOT support disable-content-encoding"; 
  if (g_bIsDebuggingXMLHTML) 
    alert(msg); 
  return msg; 
} 
function jsXMLHTMLDoDecoding () 
{ 
  jsXMLHTMLCheckDecoding(); 
  if(g_bIsDecodingXMLHTML) 
  { 
    g_bIsDebuggingXMLHTML && alert("No work needs doing -- already decoded!"); 
    return; 
  } 
  var to_decode = document.getElementsByName('DecodeWithXMLHTML'); 
  if(!( to_decode && to_decode.length )) 
  { 
    g_bIsDebuggingXMLHTML && alert("No work needs doing -- no elements to decode!"); 
    return; 
  } 
  var s; 
  for(var i = to_decode.length - 1; i >= 0; i--) 
  { 
    s = to_decode[i].textContent; 
    if ( s == undefined || (s.indexOf('&') == -1 && s.indexOf('<') == -1) ) 
    { 
      // the null or markupless element needs no reworking 
    } 
    else 
    { 
      to_decode[i].innerHTML = s; // that's the magic
    } 
  } 
  return; 
} 
// ---------------- code for getting HTML in XML data to display properly in browser ------------ end ----------

//http://shop-js.sourceforge.net/crypto2.htm
//crypto.js
/* The following functions are (c) 2000 by John M Hanna and are
 * released under the terms of the Gnu Public License.
 * You must freely redistribute them with their source -- see the
 * GPL for details.
 *  -- Latest version found at http://sourceforge.net/projects/shop-js
 */

// ---------------------- Arbitrary Precision Math
// badd(a,b), bsub(a,b), bmul(a,b), bdiv(a,b), bmod(a,b),
// brshift(a), beq(a,b)

// set the base... 32bit cpu -> bs=16, 64bit -> bs=32
// bm is the mask, bs is the shift
//bm=0xf; bs=4;  // low base useful for testing if digits handled ok
bs=28;
bx2=1<<bs; bm=bx2-1; bx=bx2>>1; bd=bs>>1; bdm=(1 << bd) -1
log2=Math.log(2)


function badd(a,b) { // binary add
 var al=a.length, bl=b.length
 if(al < bl) return badd(b,a)
 var c=0, r=[], n=0
 for(; n<bl; n++) {
  c+=a[n]+b[n]
  r[n]=c & bm
  c>>>=bs
 }
 for(; n<al; n++) {
  c+=a[n]
  r[n]=c & bm
  c>>>=bs
 }
 if(c) r[n]=c
 return r
}
function beq(a,b) { // returns 1 if a == b
 if(a.length != b.length) return 0
 for(var n=a.length-1; n>=0; n--)
  if(a[n] != b[n]) return 0
 return 1
}
function bsub(a,b) { // binary subtract
 var al=a.length, bl=b.length, c=0, r=[]
 if(bl > al) {return []}
 if(bl == al) {
  if(b[bl-1] > a[bl-1]) return []
  if(bl==1) return [a[0]-b[0]]
 }
 for(var n=0; n<bl; n++) {
  c+=a[n]-b[n]
  r[n]=c & bm
  c>>=bs
 }
 for(;n<al; n++) {
  c+=a[n]
  r[n]=c & bm
  c>>=bs
 }
 if(c) {return []}
 if(r[n-1]) return r
 while(n>1 && r[n-1]==0) n--;
 return r.slice(0,n)
}
function bmul(a,b) { // binary multiply
 b=b.concat([0])
 var al=a.length, bl=b.length, r=[], n,nn,aa, c, m
 var g,gg,h,hh, ghhb

 for(n=al+bl; n>=0; n--) r[n]=0
 for(n=0; n<al; n++) {
  if(aa=a[n]) {
   c=0
   hh=aa>>bd; h=aa & bdm
   m=n
   for(nn=0; nn<bl; nn++, m++) {
    g = b[nn]; gg=g>>bd; g=g & bdm
    //(gg*2^15 + g) * (hh*2^15 + h) = (gghh*2^30 + (ghh+hgg)*2^15 +hg)
    ghh = g * hh + h * gg
    ghhb= ghh >> bd; ghh &= bdm
    c += r[m] + h * g + (ghh << bd)
    r[m] = c & bm
    c = (c >> bs) + gg * hh + ghhb
   }
  }
 }
 n=r.length
 if(r[n-1]) return r
 while(n>1 && r[n-1]==0) n--;
 return r.slice(0,n)
}

function blshift(a,b) {
 var n, c=0, r=[]
 for(n=0; n<a.length; n++) {
  c|= (a[n]<<b) 
  r[n]= c & bm
  c>>=bs
 }
 if(c) r[n]=c
 return r
}
function brshift(a) {
 var c=0,n,cc, r=[]
 for(n=a.length-1; n>=0; n--) {
  cc=a[n]; c<<=bs
  r[n]=(cc | c)>>1
  c=cc & 1
 }
 while(r.length > 1 && r[r.length-1]==0) {
  r=r.slice(0,-1)
 }
 this.a=r; this.c=c
 return this
}
function zeros(n) {var r=[]; while(n-->0) r[n]=0; return r}
function toppart(x,start,len) { var n=0
 while(start >= 0 && len-->0) n=n*bx2+x[start--]
 return n
}
//14.20 Algorithm Multiple-precision division from HAC
function bdiv(x,y) {
 var n=x.length-1, t=y.length-1, nmt=n-t
 // trivial cases; x < y
 if(n < t || n==t && (x[n]<y[n] || n>0 && x[n]==y[n] && x[n-1]<y[n-1])) {
  this.q=[0]; this.mod=x; return this
 }
 // trivial cases; q < 4
 if(n==t && toppart(x,t,2)/toppart(y,t,2) <4) {
  var q=0, xx
  for(;;) {
   xx=bsub(x,y)
   if(xx.length==0) break
   x=xx; q++
  }
  this.q=[q]; this.mod=x; return this
 }
 var shift, shift2
 // normalize
 shift2=Math.floor(Math.log(y[t])/log2)+1
 shift=bs-shift2
 if(shift) {
  x=x.concat(); y=y.concat()
  for(i=t; i>0; i--) y[i]=((y[i]<<shift) & bm) | (y[i-1] >> shift2); y[0]=(y[0]<<shift) & bm
  if(x[n] & ((bm <<shift2) & bm)) { x[++n]=0; nmt++; }
  for(i=n; i>0; i--) x[i]=((x[i]<<shift) & bm) | (x[i-1] >> shift2); x[0]=(x[0]<<shift) & bm
 }
 var i, j, x2, y2,q=zeros(nmt+1)

 y2=zeros(nmt).concat(y)
 for(;;) {
  x2=bsub(x,y2)
  if(x2.length==0) break
  q[nmt]++
  x=x2
 }
 var yt=y[t], top=toppart(y,t,2)
 for(i=n; i>t; i--) {
  m=i-t-1
  if(i >= x.length)
   q[m]=1
  else if(x[i] == yt)
   q[m]=bm
  else
   q[m]=Math.floor(toppart(x,i,2)/yt)

  topx=toppart(x,i,3)
  while(q[m] * top > topx)
   q[m]--
  //x-=q[m]*y*b^m
  y2=y2.slice(1)
  x2=bsub(x,bmul([q[m]],y2))
  if(x2.length==0) {
   q[m]--
   x2=bsub(x,bmul([q[m]],y2))
  }
  x=x2
 }
 // de-normalize
 if(shift) {
  for(i=0; i<x.length-1; i++) x[i]=(x[i]>>shift) | ((x[i+1] << shift2) & bm); x[x.length-1]>>=shift
 }
 while(q.length > 1 && q[q.length-1]==0) q=q.slice(0,q.length-1)
 while(x.length > 1 && x[x.length-1]==0) x=x.slice(0,x.length-1)
 this.mod=x
 this.q=q
 return this
}

function bmod(p,m) // binary modulo
{
 if(m.length==1)
 {
  if(p.length==1)
  	return [p[0] % m[0]];
  if(m[0] < bdm)
  	return [simplemod(p,m[0])];
 }

 var r=bdiv(p,m);
 return r.mod;
}
function simplemod(i,m)
{
 // returns the mod where m < 2^bd
 if(m>bdm)
  return bmod(i,[m]);
 var c=0, v;
 for(var n=i.length-1; n>=0; n--)
 {
  v=i[n];
  c=((v >> bd) + (c<<bd)) % m;
  c=((v & bdm) + (c<<bd)) % m;
 }
 return c;
}
function bmodexp(xx,y,m) // binary modular exponentiation
{
 var r=[1], n, an,a, x=xx.concat();
 var mu=[] ;
 n=m.length*2;
 mu[n--]=1;
 for(; n>=0; n--)
 	mu[n]=0;
 mu=bdiv(mu,m).q

 for(n=0; n<y.length; n++)
 {
  for(a=1, an=0; an<bs; an++, a<<=1)
  {
   if(y[n] & a)
   	r=bmod2(bmul(r,x),m,mu);
   x=bmod2(bmul(x,x),m,mu);
  }
 }
 return r;
}
function bmod2(x,m,mu) // Barrett's modular reduction from HAC, 14.42, CRC Press
{
 var xl=x.length - (m.length << 1);
 if(xl > 0)
 {
  return bmod2(x.slice(0,xl).concat(bmod2(x.slice(xl),m,mu)),m,mu);
 }
 var ml1=m.length+1, ml2=m.length-1,rr;
 //var q1=x.slice(ml2)
 //var q2=bmul(q1,mu)
 var q3=bmul(x.slice(ml2),mu).slice(ml1);
 var r1=x.slice(0,ml1);
 var r2=bmul(q3,m).slice(0,ml1);
 var r=bsub(r1,r2);
 //var s=('x='+x+'\nm='+m+'\nmu='+mu+'\nq1='+q1+'\nq2='+q2+'\nq3='+q3+'\nr1='+r1+'\nr2='+r2+'\nr='+r); 
 if(r.length==0)
 {
  r1[ml1]=1;
  r=bsub(r1,r2);
 }
 for(var n=0;;n++)
 {
  rr=bsub(r,m);
  if(rr.length==0)
  	break;
  r=rr;
  if(n>=3)
  	return bmod2(r,m,mu);
 }
 return r;
}

function sub2(a,b)
{
 var r=bsub(a,b)
 if(r.length==0) {
  this.a=bsub(b,a)
  this.sign=1
 } else {
  this.a=r
  this.sign=0
 }
 return this
}

function signedsub(a,b)
{
 if(a.sign) {
  if(b.sign) {
   return sub2(b,a)
  } else {
   this.a=badd(a,b)
   this.sign=1
  }
 } else {
  if(b.sign) {
   this.a=badd(a,b)
   this.sign=0
  } else {
   return sub2(a,b)
  }
 }
 return this;
}

function modinverse(x,n) // returns x^-1 mod n
{
// from  Bryan Olson <bryanolson@my-deja.com> 
 var y=n.concat(), t, r, bq, a=[1], b=[0], ts
 a.sign=0; b.sign=0
 while( y.length > 1 || y[0]) {
  t=y.concat()
  r=bdiv(x,y)
  y=r.mod
  q=r.q
  x=t
  t=b.concat(); ts=b.sign
  bq=bmul(b,q)
  bq.sign=b.sign
  r=signedsub(a,bq)
  b=r.a; b.sign=r.sign
  a=t; a.sign=ts
 }
 if(beq(x,[1])==0) return [0] // No inverse; GCD is x
 if(a.sign) {
  a=bsub(n,a)
 }
 return a
}

function crt_RSA(m, d, p, q) {
 // Compute m**d mod p*q for RSA private key operations. -- Bryan Olson via deja.com
 var xp = bmodexp(bmod(m,p), bmod(d,bsub(p,[1])), p)
 var xq = bmodexp(bmod(m,q), bmod(d,bsub(q,[1])), q)
 var t=bsub(xq,xp);
 if(t.length==0) {
  t=bsub(xp,xq)
  t = bmod(bmul(t, modinverse(p, q)), q);
  t=bsub(q,t)
 } else {
  t = bmod(bmul(t, modinverse(p, q)), q);
 } 
 return badd(bmul(t,p), xp)
}

// conversion functions:
// text to binary and binary to text, text to base64 and base64 to text
// OK, so this isn't exactly base64 -- fix it if you care

function t2b(s) {
 var bits=s.length*8, bn=1, r=[0], rn=0, sn=0, sb=1;
 var c=s.charCodeAt(0)
 for(var n=0; n<bits; n++) {
  if(bn > bm) {bn=1; r[++rn]=0; }
  if(c & sb)  r[rn]|=bn;
  bn<<=1
  if((sb<<=1) > 255) {sb=1; c=s.charCodeAt(++sn); }
 }
 return r;
}
function b2t(b) {
 var bits=b.length*bs, bn=1, bc=0, r=[0], rb=1, rn=0
 for(var n=0; n<bits; n++) {
  if(b[bc] & bn) r[rn]|=rb;
  if((rb<<=1) > 255) {rb=1; r[++rn]=0; }
  if((bn<<=1) > bm) {bn=1; bc++; }
 }
 while(r[rn]==0) {rn--;}
 var rr=''
 for(var n=0; n<=rn; n++) rr+=String.fromCharCode(r[n]);
 return rr;
}
b64s='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"'
function textToBase64(t) {
 var r=''; var m=0; var a=0; var tl=t.length-1; var c
 for(n=0; n<=tl; n++) {
  c=t.charCodeAt(n)
  r+=b64s.charAt((c << m | a) & 63)
  a = c >> (6-m)
  m+=2
  if(m==6 || n==tl) {
   r+=b64s.charAt(a)
   if((n%45)==44) {r+="\n"}
   m=0
   a=0
  }
 }
 return r
}
function base64ToText(t) {
 var r=''; var m=0; var a=0; var c
 for(n=0; n<t.length; n++) {
  c=b64s.indexOf(t.charAt(n))
  if(c >= 0) {
   if(m) {
    r+=String.fromCharCode((c << (8-m))&255 | a)
   }
   a = c >> m
   m+=2
   if(m==8) { m=0 }
  }
 }
 return r
}

// RC4 stream encryption
// adapted from www.cpan.org crypt::rc4 -- thanks!
function rc4(key, text) {
 var i, x, y, t, x2, kl=key.length;
 s=[];

 for (i=0; i<256; i++) s[i]=i
 y=0
 for(j=0; j<2; j++) {
  for(x=0; x<256; x++) {
   y=(key.charCodeAt(x%kl) + s[x] + y) % 256
   t=s[x]; s[x]=s[y]; s[y]=t
  }
 }
 var z=""
 for (x=0; x<text.length; x++) {
  x2=x & 255
  y=( s[x2] + y) & 255
  t=s[x2]; s[x2]=s[y]; s[y]=t
  z+= String.fromCharCode((text.charCodeAt(x) ^ s[(s[x2] + s[y]) % 256]))
 }
 return z
}

function ror(a,n) {n&=7; return n?((a>>n) | ((a<<(8-n))&255)):a;}
function hash(s,l) {
 var sl=s.length,r=[],rr='',v=1,lr=4;
 for(var n=0; n<l; n++) r[n]=(v=((v*v*5081+n) & 255));
 while(sl--) {
  lr = r[sl % l] ^= ror(s.charCodeAt(sl),lr) ^ r[r[(sl * 5081) % l] % l];
 }
 for(var n=0; n<l; n++)
  rr+=String.fromCharCode(r[n] ^
   ror(r[r[(n * 171) % l] % l],r[n]));
 return rr
}

// tie it all together with rsa encrypt and decrypt
function rsaEncode(key,mod,text) {
 // create a good random session key
 var keylen=Math.floor((mod.length+1)*bs/8)
 var sessionkey=hash(text+Date()+Math.random(),keylen)

 // sessionkey must be less than modulo
 sessionkey=bmod(t2b(sessionkey),mod)

 // convert it from arbitrary precision representation into text for RC4
 var sk2=b2t(sessionkey)

 // rsa encrypt the key
 var ske=bmodexp(sessionkey,key,mod)

 // to pack it in with the text we need its length
 var skeText=b2t(ske)

  // return the rsa encoded key and the encrypted text
 // pack up the completed encoded package with base64
 return textToBase64(
  String.fromCharCode(skeText.length)+skeText+
  rc4(sk2,text))
}
function rsaDecode(key,text) {
 // separate the session key from the text
 text=base64ToText(text)
 var sessionKeyLength=text.charCodeAt(0)
 var sessionKeyEncryptedText=text.substr(1,sessionKeyLength)
 text=text.substr(sessionKeyLength+1)
 var sessionKeyEncrypted=t2b(sessionKeyEncryptedText)

 // un-rsa the session key
 sessionkey=crt_RSA(sessionKeyEncrypted,key[0],key[1],key[2])
 sessionkey=b2t(sessionkey)

 text=rc4(sessionkey,text)
 return text
}
// ------------------------------
  var Rx;
  var Ry;
  var Rs;

// seed the random number generator with entropy in s
function seed (s)
{
 rSeed=[];
 var n=0,nn=0;
 while (n < s.length)
 {
  while(n<s.length && s.charCodeAt(n)<=32)
  	n++;
  if(n < s.length)
  	rSeed[nn] = parseInt("0x"+s.substr(n,2));
  n+=3;
  nn++;
 }

 var x, y, t;
 Rs=[];
 Rsl=rSeed.length;
 Sr= r(256);
 Rbits=0;

 if(Rs.length==0)
 {
 	for (x=0; x<256; x++)
 		Rs[x]=x;
 }
 y=0;
 for (x=0; x<256; x++)
 {
  y = (rSeed[x] + s[x] + y) % 256;
  t = s[x];
  s[x] = s[y];
  s[y] = t;
 }
 Rx=Ry=0;
 alert("Random seed updated. Seed size is: "+Rsl);
}
// generate a random number 0 .. 255
// uses entropy from seed
function rc()
{
  // this first bit is basically RC4
  Rx=++Rx & 255;
  Ry=( Rs[Rx] + Ry) & 255;
  var t=Rs[Rx]; Rs[Rx]=Rs[Ry]; Rs[Ry]=t;
  Sr^= Rs[(Rs[Rx] + Rs[Ry]) & 255];

  // xor with javascripts rand, just in case there's good entropy there
  Sr^= r(256);

  Sr^= ror(rSeed[r(Rsl)],r(8));
  Sr^= ror(rSeed[r(Rsl)],r(8));
  return Sr;
}
// javascript's random 0 .. n
function r(n) {return  Math.floor(Math.random()*n);}
// rotate right
//function ror(a,b) {return b?((a<<b)|(a>>(8-b))&255):a;}
// random number between 0 .. n -- based on repeated calls to rc
function rand(n) {
 if(n==2) {
  if(! Rbits) {
   Rbits=8;
   Rbits2=rc(256);
  }
  Rbits--;
  var r=Rbits2 & 1;
  Rbits2>>=1;
  return r;
 }
 var m=1, r=0;
 while (n>m && m > 0) {
  m<<=8; r=(r<<8) |rc();
 }
 if(r<0) r ^= 0x80000000;
 return r % n;
}

tstval=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]

// functions for generating keys-----------------------------
function bgcd(uu,vv) { // return greatest common divisor
 // algorythm from http://algo.inria.fr/banderier/Seminar/Vallee/index.html
 var d, t, v=vv.concat(), u=uu.concat()
 for(;;) {
  d=bsub(v,u)
  if(beq(d,[0])) return u
  if(d.length) {
   while((d[0] & 1) ==0)
    d=brshift(d).a // v=(v-u)/2^val2(v-u)
   v=d
  } else {
   t=v; v=u; u=t // swap u and v
  }
 }
}

function rnum(bits) {
 var n,b=1,c=0
 var a=[]
 if(bits==0) bits=1
 for(n=bits; n>0; n--) {
  if(rand(2)) {
   a[c]|=b
  }
  b<<=1
  if(b==bx2) {
   b=1; c++
  }
 }
 return a
}

// function to generate keys
var g_p;
var g_q;
var g_d;
var g_e;
var g_pq;
function genkey (bits)
{
 seed ("0a a2 c4 db 86 74 25 e3 26 93 aa b5 de ca 81 a0 13 ca 5f 8a da a4 08 cb 8c 7e 81 b0 df 9d 42 02 56 55 33 45 f2 cc fe 42 2d 32 d4 a8 5b ec b3 20 96 12 48 3e 63 aa 74 7b 4f 0c 37 64 ee f4 cf 21 fd 15 7e 11 49 c1 6e a1 6b 57 f6 37 86 77 76 bd 75 0e 88 cc 73 7a dc f0 45 19 05 9a a9 50 35 9c 5f 17 bf fe ae c0 47 1d 9f 1f 6f 43 08 58 5b 6b a8 df ec 52 ae be e7 07 4f 5b c7 9e a5 03 f9 e7 43 3e 70 7c 74 99 a2 62 f2 04 47 f6 37 03 4d 1e 82 9f 9b 6c 81 be 80 6b cf 88 56 e6 6c 32 4e c7 0d 70 83 d8 c9 a9 1d 67 d9 b3 36 27 f9 4c 32 b4 6e a4 f2 1b cf f1 b6 91 63 f6 32 e3 5f 56 49 35 5f c5 8e f3 90 38 bb 80 c9 78 6e 66 e5 c1 aa 43 07 67 34 f3 6f af 7f 48 7a 1c 44 98 81 30 ee bf 3f 16 25 08 cc cc 87 0e 0c ce b9 fb 88 71 c0 aa 6c 8e 46 b1 55 e2 65 47 d2 83 75 6b db eb 07 59 06 d5 7a 79 ba 39 2d ca da 4d 0c 80 dc 00 42 93 94 5c db fc 96 40 58 84 28 6b 0e 28 d1 70 4c 1d f6 67 49 cb c2 56 76 90 d4 7f f0 d4 01 cd 68 08 54 32 01 a1 79 89 e3 23 1f 08 ef d3 38 6d ca 20 df 8a bb 5a b0 dc a1 c9 a0 c8 c7 fd ff 41 49 5d a7 e7 e2 ed 2e e3 47 fb 10 fd 92 3a 85 33 36 c1 c5 17 11 e8 a3 d9 5c 10 20 c4 47 aa 3d 9a 11 0a 02 7c dd aa 48 fe f6 ae 3c 9f a8 cd 6f c8 17 be 4b 79 25 85 98 bc 1b 3c 95 66 92 cc 27 19 23 c8 b6 cd cb 9c 3e 1a d1 6f 81 92 fe 78 dc 51 67 5e ca d2 f1 af d1 b5 2a 46 12 85 36 1c 5c 5f 89 47 3c b4 5e e9 38 20 d1 d4 9b eb 77 8c 0e e0 80 dd aa 72 7b 1d 7f 1a 62 6e 6d c7 4f c7 ed 15 1d 0d 76 0a 0f 22 5f 32 07 41 ad ec 75 3f 61 48 db 8f d4 f1 71 a4 24 35 ac 35 37 1f a4 b3 e2 dc 27 ff 4e 01 e1 69 8d b1 1e 0d 0d 80 5e c8 e8 0d c8 73 15 0b 19 c5 14 53 aa 43 ce 28 ba 5d cf 8e 35 76 31 77 af 36 4d 73 bf 06 07 e4 9d 9f 72 7f ad b4 53 0a 9c 1a 00 73 63 e4 b0 93 bd 0c 3e 80 89 15 78 f6 1a aa fc f0 ce 7c 13 09 aa e8 f3 ce 20 c2 69 e4 7f 1c bf 27 c9 73 57 10 8b fc 66 68 9d d3 75 44 3e 2e 3f 1c 1a dc df 77 b3 65 3e 3d a7 b7 f5 cc a9 dd 08 46 d5 0a 1b 3f bc f4 29 8a 89 08 7a 04 d7 d1 b1 cd 79 77 5e ab 12 aa 5d ef e6 2f f0 7d b2 b8 a0 76 19 08 3f 96 b5 16 6e cc 55 98 0f 14 66 26 a4 50 80 da d4 90 67 c1 9a d3 3f 14 d3 4a 89 e9 c5 46 ce d8 9a b8 8a 18 71 17 4a 9a 74 d1 69 79 40 3a 59 6b c1 cf 20 48 ba 87 4e 0a d6 07 4b 60 14 0c b9 91 52 25 2a 4b 98 3f 19 1a 3f 0f dc c1 1e 0d f8 32 ed 4d e8 03 04 86 a2 2e 38 26 46 05 96 93 6e 9a fe 3b dd 6f d4 f4 6e 17 dc b2 0d 87 50 18 c9 a3 79 92 91 f3 08 92 91 78 3d c0 c9 fa ef 41 40 11 5d 29 6e 4b 65 eb c3 0d 20 94 70 5a a6 ef 07 92 31 cd 86 24 bf 42 a9 4a 0e 9f 09 de a4 b0 fa 52 d2 60 83 17 2e 51 29 7b 09 3d ce fc 70 3b 46 2b 50 b3 34 b0 a2 ac 44 8e 27 ab 3c a3 2b 63 06 a2 84 62 bc 9a ba 04 f8 b3 1f 0e 45 53 f7 0d 2a 83 02 18 8e 36 ca b4 52 b9 a7 bc 69 8c 49 9a 24 01 e9 5c fe 1f a4 0a d7 da 08 be ae 08 7c d2 34 bd 55 26 b7 c1 6f fd a7 d1 b3 44 83 3f 06 bb 7b 99 c7 0a af a6 05 d5 76 7e a4 8f 5c 9a 0a f6 f8 00 98 40 46 1f 29 71 c1 e1 da ee f8 f1 88 22 c4 19 1d 91 bd fd 95 c0 14 55 86 8b bf 00 15 18 ff 8c 59 db 27 ff b8 08 ec bb 1a f8 bd 95 c0 26 33 67 0d 18 9d 9d 1f a8 8e 3c 22 cf ad 2f 76 15 70 bc 7b b0 eb cc be 1a 3b f3 84 f7 79 4a f6 c4 21 dc 34 67 ff b9 0e b0 9f 3d 92 72 5a b9 18 02 17 ce 0e 7d b7 bd 25 33 6a 47");
 //timerStart()
 var nBits = parseInt(bits)*8;
 var q,p,p1q1,n,factorMe,d,e,r;
 var c,cc,ccc,pq;
 q=mpp(nBits);
 p=mpp(nBits)
 g_p=p;
 g_q=q;

 p1q1=bmul(bsub(p,[1]),bsub(q,[1]))
 for(c=5; c<Primes.length; c++)
 {
  e=[Primes[c]]
  d=modinverse(e,p1q1)
  if(d.length != 1 || d[0]!=0)
  	break;
 }
 g_d=d;
 g_e=e;
 g_pq=pq=bmul(p,q);

 // test
 //timerStop()
 c=bmod(tstval,pq)
 cc=bmodexp(c,e,pq)
 //timerStart()
 //cc1=bmodexp(cc,d,pq)
 ccc=crt_RSA(cc,d,p,q)
 //timerStop()
 return;
}

function parseArray(a)
{
 a=a.split(",");
 for(var n=0; n<a.length; n++)
 {
  a[n]=parseInt(a[n]);
 }
 return a;
}

function enc(f) {
 timerStart()
 f.text.value=rsaEncode(parseArray(f.e.value),parseArray(f.pq.value),f.text.value)
 timerStop()
}
function dec(f) {
 timerStart()
 f.text.value=rsaDecode([parseArray(f.d.value),
  parseArray(f.p.value),
  parseArray(f.q.value)],
  f.text.value)
 timerStop()
}

Primes=[3, 5, 7, 11, 13, 17, 19,
	23, 29, 31, 37, 41, 43, 47, 53,
	59, 61, 67, 71, 73, 79, 83, 89,
	97, 101, 103, 107, 109, 113, 127, 131,
	137, 139, 149, 151, 157, 163, 167, 173,
	179, 181, 191, 193, 197, 199, 211, 223,
	227, 229, 233, 239, 241, 251, 257, 263,
	269, 271, 277, 281, 283, 293, 307, 311,
	313, 317, 331, 337, 347, 349, 353, 359,
	367, 373, 379, 383, 389, 397, 401, 409,
	419, 421, 431, 433, 439, 443, 449, 457,
	461, 463, 467, 479, 487, 491, 499, 503,
	509, 521, 523, 541, 547, 557, 563, 569,
	571, 577, 587, 593, 599, 601, 607, 613,
	617, 619, 631, 641, 643, 647, 653, 659,
	661, 673, 677, 683, 691, 701, 709, 719,
	727, 733, 739, 743, 751, 757, 761, 769,
	773, 787, 797, 809, 811, 821, 823, 827,
	829, 839, 853, 857, 859, 863, 877, 881,
	883, 887, 907, 911, 919, 929, 937, 941,
	947, 953, 967, 971, 977, 983, 991, 997,
	1009, 1013, 1019, 1021]


var sieveSize=4000;
var sieve0 = -1* sieveSize;
var sieve=[];
var lastPrime=0;

function nextPrime(p) // returns the next prime > p
{
 var n;
 if(p == Primes[lastPrime] && lastPrime <Primes.length-1)
 {
  return Primes[++lastPrime];
 }
 if(p<Primes[Primes.length-1])
 {
  for(n=Primes.length-2; n>0; n--)
  {
   if(Primes[n] <= p)
   {
    lastPrime=n+1;
    return Primes[n+1];
   }
  }
 }
 // use sieve and find the next one
 var pp,m;
 // start with p
 p++;
 if((p & 1)==0)
 	p++;
 for(;;)
 {
  // new sieve if p is outside of this sieve's range
  if(p-sieve0 > sieveSize || p < sieve0)
  {
   // start new sieve
   for(n=sieveSize-1; n>=0; n--)
   	sieve[n]=0;
   sieve0=p;
   primes=Primes.concat();
  } 

  // next p if sieve hit
  if(sieve[p-sieve0]==0) // sieve miss
  {
   // update sieve if p divisable

   // find a prime divisor
   for(n=0; n<primes.length; n++)
   {
    if((pp=primes[n]) && p % pp ==0)
    {
     for(m=p-sieve0; m<sieveSize; m+=pp)
      sieve[m]=pp;
     p+=2;
     primes[n]=0;
     break;
    }
   }
   if(n >= primes.length)
   {
    // possible prime
    return p;
   }
  }
  else
  {
    p+=2;
  }
 }
}

function divisable(n,max) { //return a factor if n is divisable by a prime less than max, else return 0
 if((n[0] & 1) == 0) return 2
 for(c=0; c<Primes.length; c++) {
  if(Primes[c] >= max) return 0
  if(simplemod(n,Primes[c])==0)
   return Primes[c]
 }
 c=Primes[Primes.length-1]
 for(;;) {
  c=nextPrime(c)
  if(c >= max) return 0
  if(simplemod(n,c)==0)
   return c
 }
}

function bPowOf2(pow) // return a bigint
{
 var r=[], n, m=Math.floor(pow/bs);
 for(n=m-1; n>=0; n--)
 	r[n]=0;
 r[m]= 1<<(pow % bs);
 return r;
}

function mpp(_nBits) //returns a Maurer Provable Prime, see HAC chap 4 (c) CRC press
{
 if(_nBits < 10)
 	return [Primes[rand(Primes.length)]];
 if(_nBits <=20)
 	return [nextPrime(rand(1<<_nBits))];
 var c=10, m=20, B=_nBits*_nBits/c, r, q, I, R, n, a, b, d, R2, nMinus1
 if(_nBits > m*2)
 {
  for(;;)
  {
   r=Math.pow(2,Math.random()-1);
   if(_nBits - r * _nBits > m)
   	break;
  }
 }
 else
 {
  r=0.5
 }
 q=mpp(Math.floor(r*_nBits)+1);
 I=bPowOf2(_nBits-2);
 I=bdiv(I,q).q;
 Il=I.length;
 for(;;)
 {
  // generate R => I < R < 2I
  R=[];
  for(n=0; n<Il; n++)
  	R[n]=rand(bx2);
  R[Il-1] %= I[Il-1];
  R=bmod(R,I);
  if(! R[0])
  	R[0]|=1; // must be greater or equal to 1
  R=badd(R,I);
  n=blshift(bmul(R,q),1); // 2Rq+1
  n[0]|=1;
  if(!divisable(n,B))
  {
   a=rnum(_nBits-1);
   a[0]|=2; // must be greater than 2
   nMinus1=bsub(n,[1]);
   var x=bmodexp(a,nMinus1,n);
   if(beq(x,[1]))
   {
    R2=blshift(R,1);
    b=bsub(bmodexp(a,R2,n),[1]);
    d=bgcd(b,n);
    if(beq(d,[1]))
    	return n;
   }
  }
 }
}
// -----------------------

