/****************************
Roboshrub Inc.
http://roboshrub.blogspot.com
*****************************/

// Returns the element
function g(a) {
  return document.getElementById(a);
}

// Substitution/Polybius Square ciphers. 24^2 characters per array.
var key1=new Array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','!','@','#','$','%','^','&','*','(',')','<','>',',','.','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','-','=','_','+','[',']',';',':','{','}','|','`','\'','~','?','/','"',' ','§','¶','‘','’','“','”','—','♪','♫','€','Ø','ø','æ','ð','¥','£','†','‡','©','®','‰','™','¼','½','¾','«','»','А','Б','В','Г','Д','Е','Ж','З','И','Й','К','Л','М','Н','О','П','Р','С','Т','У','Ф','Х','Ц','Ч','Ш','Щ','Ь','Ы','Э','Ю','Я','а','б','в','г','д','е','ж','з','и','й','к','л','м','н','о','п','р','с','т','у','ф','х','ц','ч','ш','щ','ъ','ы','ь','э','ю','я','ä','à','À','Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö','×','Ù','Ú','Û','Ü','Ý','Þ','ß','à','á','â','ã','ä','å','ç','è','é','ê','ë','ì','í','î','ï','ñ','ò','ó','ô','õ','ö','÷','ù','ú','û','ü','ý','þ','ÿ','Ā','ā','Ă','ă','Ą','ą','Ć','ć','Ĉ','ĉ','Ċ','ċ','Č','č','Ď','ď','Đ','đ','Ē','ē','Ĕ','ĕ','Ė','ė','Ę','ę','Ě','ě','Ĝ','ĝ','Ğ','ğ','Ġ','ġ','Ģ','ģ','Ĥ','ĥ','Ħ','ħ','Ĩ','ĩ','Ī','ī','Ĭ','ĭ','Į','į','İ','ı','Ĳ','ĳ','Ĵ','ĵ','Ķ','ķ','ĸ','Ĺ','ĺ','Ļ','ļ','Ľ','ľ','Ŀ','ŀ','Ł','ł','Ń','ń','Ņ','ņ','Ň','ň','ŉ','Ŋ','ŋ','Ō','ō','Ŏ','ŏ','Ő','ő','Œ','œ','Ŕ','ŕ','Ŗ','ŗ','Ř','ř','Ś','ś','Ŝ','ŝ','Ş','ş','Š','š','Ţ','ţ','Ť','ť','Ŧ','ŧ','Ũ','ũ','Ū','ū','Ŭ','ŭ','Ů','ů','Ű','ű','Ų','ų','Ŵ','ŵ','Ŷ','ŷ','Ÿ','Ź','ź','Ż','ż','Ž','∂','∆','∏','∑','−','•','√','∞','∟','∩','∫','≈','≠','≡','≤','≥','♠','♣','♥','♦','¿','ª','¹','²','³','º','ا','ب','ت','ث','ج','ح','خ','د','ذ','ر','ز','س','ش','ص','ض','ط','ظ','ع','غ','ف','ق','ك','ل','م','ن','و','ي','ﺀ','א','ב','ג','ד','ה','ו','ז','ח','ט','י','כ','ל','מ','נ','ס','ע','פ','צ','ק','ר','ש','ת','Α','Β','Γ','Δ','Ε','Ζ','Η','Θ','Ι','Κ','Λ','Μ','Ν','Ξ','Ο','Π','Ρ','Σ','Τ','Υ','Φ','Χ','Ψ','Ω','α','β','γ','δ','ε','ζ','η','θ','ι','κ','λ','μ','ν','ξ','ο','π','ρ','σ','τ','υ','φ','χ','ψ','ω','イ','ロ','ハ','ニ','ホ','ヘ','ト','チ','リ','ヌ','ル','ヲ','ワ','ヵ','ヨ','タ','レ','ソ','ツ','ネ','ナ','ラ','ム','ウ','ヰ','ノ','オ','ク','ヤ','マ','ケ','フ','コ','エ','テ','ア','サ','キ','ユ','メ','ミ','シ','ヱ','ヒ','ﾓ','ス','ン','ﾞ','ﾟ','ー','ガ','ギ','グ','ゲ','ゴ','ザ','ジ','ズ','ゼ','ゾ','ダ','ヂ','ヅ','デ','ド','バ','パ','ビ','ピ','ブ','プ','ベ','ペ','ボ','ポ','ヴ','ヷ','ヸ','ヹ','ヺ');
var key2=new Array('`','\'','"','?','/','c','a','b','f','d','i','g','h','l','j','k','o','m',' ','n','r','2','6','4','p','q','u','s','t','x','v','w','0','y','z','3','1','5','9','7','8','#','!','@','^','$','%','(','&','*','¶',')','§','A',',','.','D','B','C','G','E','F','J','H','I','M','K','L','P','N','O','S','Q','R','V','T','U','Y','X','W','=','Z','-','[','_','+',':',']',';','|','{','}','~','e','‰','>','<','¥','£','‘','ð','ø','æ','’','“','½','®','”','†','«','©','—','»','¼','♪','♫','€','Ø','™','ż','Ž','‡','¾','Я','Г','к','Ч','Л','Х','в','Ю','б','У','И','Ć','ć','Ĉ','ĉ','з','Ċ','ċ','Č','д','č','Е','г','Б','С','П','Ы','Щ','Н','Ж','и','й','Й','ª','¹','З','Ь','н','²','³','º','е','М','а','Т','м','Ц','В','Р','ж','о','с','л','Ш','у','Э','К','Ф','О','Д','А','т','х','п','ч','щ','ы','р','э','ъ','ф','ь','ц','ш','ä','Â','Ã','ю','я','à','À','Á','Ä','Å','Æ','Ç','È','É','Ê','Ë','♥','Ì','Í','Î','Ñ','Ï','Ð','Ò','Ó','Ü','Ý','Þ','Ô','Õ','Ö','×','Ù','Ú','Û','ß','à','á','õ','ö','ä','å','ç','è','é','ê','ë','ì','í','î','ï','ñ','ò','ó','â','ã','ô','÷','ù','ú','û','ü','ý','þ','ÿ','Ā','ā','Ă','Ţ','ţ','Ť','ť','ă','Ą','ą','Ď','ď','Ē','ē','Ĕ','ĕ','Ė','ė','Ę','ę','Ě','ě','Ĝ','ĝ','Ğ','ğ','Ġ','Đ','đ','ġ','Ģ','ģ','Ĥ','ĥ','Ħ','ħ','Ĩ','Ī','ŏ','Ő','ī','Ĭ','ĭ','Į','į','ĸ','İ','ı','Ĳ','ĳ','Ĵ','ĵ','Ķ','ķ','Ĺ','ĺ','Ļ','ŧ','ļ','Ľ','ľ','Ņ','ĩ','Ŀ','ŀ','Ł','ł','Ń','ń','ņ','Ň','Ř','ř','Ŝ','ŝ','Ś','ś','Ş','Ŭ','ş','Š','Ű','š','Ŧ','Ũ','ũ','ŗ','Ū','ū','ŭ','Ō','ō','Ů','ů','ű','Ų','ų','Ŵ','ŵ','Ŷ','Ŏ','ŷ','Ÿ','Ź','ź','Ż','ň','ŉ','Ŋ','ŋ','ő','Œ','œ','Ŕ','ŕ','Ŗ','∂','∆','∏','∑','−','•','√','∞','∟','∩','∫','≈','≠','≡','≤','≥','♠','マ','ケ','♣','♦','¿','ا','ب','ت','ث','ج','ح','Ε','Ζ','Η','Θ','خ','د','ذ','Τ','Υ','Φ','Χ','ر','ز','س','ش','ص','ض','ط','ظ','ع','غ','ف','ق','ك','ل','م','ن','و','ي','ﺀ','א','ב','ג','ד','ה','ヴ','ו','ז','ח','ט','י','כ','ל','מ','נ','ס','ע','ボ','ポ','ヷ','ヸ','ヹ','ヺ','פ','צ','ק','ר','ש','ת','Α','Β','Γ','Δ','Ι','Κ','Λ','Μ','Ρ','Σ','Ψ','Ω','α','β','γ','δ','ε','ζ','η','θ','ι','κ','λ','チ','リ','ヌ','μ','ν','ξ','ο','π','ρ','σ','τ','υ','φ','χ','ψ','ω','イ','ロ','ハ','ニ','ホ','ヘ','ト','ル','ヲ','ワ','ヵ','ヨ','タ','レ','ソ','ツ','ネ','ナ','ラ','ム','ウ','ヰ','ノ','オ','ク','ヤ','フ','コ','エ','テ','ア','サ','キ','ユ','メ','ミ','シ','ヱ','ヒ','ﾓ','ス','ン','ﾞ','ﾟ','ー','ガ','ギ','グ','ゲ','ゴ','ザ','ジ','ズ','ゼ','ゾ','ダ','ヂ','ヅ','デ','ド','Ν','Ξ','ピ','ブ','プ','ベ','ペ','Ο','Π','バ','パ','ビ');

// Declares global encryption variables.
var s, n, i, k, check, cryptString, buckets, square, pSquare;

// Sets the value of an input element.
function setValue(a,b) {
  g(a).value=b;
}

// Initiates the encoding process.
function coder(a) {
  // Two-way box check.
  if (E_TWOWAY) {
    s=(a)?g('encoder').value:g('decoder').value; 
  }
  else {
    s=g('encoder').value;
  }
  
  // If the user did not enter any input, ends the function.
  if (s==""||s==null) {
    return;
  }
  
  // Loader Animation
  g('loader').src="images/active.gif";
  g('loader').alt="Active";
  
  // Encrypts using Morse Code
  if (g('morse').checked && a) {
    s=toMorse(s);
  }
  
  // Checks for substitution for encryption.
  if (g('sub').checked && a) {
    if (document.getElementsByName('subswitch')[0].checked) {
      s=substitute(a, s);
    }
    else if (document.getElementsByName('subswitch')[1].checked) {
      s=leet(a, s);
    }
    else {
      try {
        var testNum=parseInt(g('subMoves').value); // Throws out non-integers.
        if (testNum<0 || g('subMoves').value=="" || isNaN(g('subMoves').value)) {throw "Keys cannot be negative or not a number!";}
      }
      catch (e) {return;} // User entered an invalid key.
      s=customSub(a, s);
    }
  }
  
  // Adds White Noise
  if (g('whiteNoise').checked && a) {
    var wkey1=(!isNaN(g('wkey1').value) && g('wkey1').value>=0)?parseInt(g('wkey1').value):0;
    var wkey2=(!isNaN(g('wkey2').value) && g('wkey2').value>=0)?parseInt(g('wkey2').value):0;
    var wkey3=(!isNaN(g('wkey3').value) && g('wkey3').value>=0)?parseInt(g('wkey3').value):0;
    s=insertWhiteNoise(s, wkey1, wkey2, wkey3);
  }
  
  // Checks for Escape for encryption.
  if (g('esc').checked && a) {
    var temp=g('escSel').options[g('escSel').selectedIndex].value;
    
    if (temp==1) {
      s=escape(s);
    }
    else if (temp==2) {
      s=encodeURI(s);
    }
    else {
      s=encodeURIComponent(s);
    }
  }
  
  // Encrypts using Base64
  if (g('b64').checked && a) {
    s=encode64(s);
  }
  
  // Encrypting using the Polybius Square.
  if (g('polybius').checked && a) {
    s=polybius(s);
  }
  
  // Checks for a transposition.
  if (g('trans').checked) {
    // Encrypt Flip
    if (g('flip').checked && a) {
      s=flipIt(s);
    }
    try {
      var testNum=parseInt(g('key').value); // Throws out non-integers.
      if (testNum<1 || g('key').value=="" || isNaN(g('key').value)) {throw "Keys cannot be negative or zero or not a number!";}
    }
    catch (e) {return;} // User entered an invalid key.
    if (a) {
      s=transpose(s);
    }
    else {
      s=depose(s);
    }
    // Decrypt Flip
    if (g('flip').checked && !a) {
      s=flipIt(s);
    }
  }
  
  // Decrypts using the Polybius Square.
  if (g('polybius').checked && !a) {
    s=dePolybius(s);
  }
  
  // Decrypts using Base64.
  if (g('b64').checked && !a) {
    s=decode64(s);
  }
  
  // Decrypts using Escape.
  if (g('esc').checked && !a) {
    var temp=g('escSel').options[g('escSel').selectedIndex].value;
    
    if (temp==1) {
      s=unescape(s);
    }
    else if (temp==2) {
      s=decodeURI(s);
    }
    else {
      s=decodeURIComponent(s);
    }
  }
  
  // Removes White Noise
  if (g('whiteNoise').checked && !a) {
    var wkey1=(!isNaN(g('wkey1').value) && g('wkey1').value>=0)?parseInt(g('wkey1').value):0;
    var wkey2=(!isNaN(g('wkey2').value) && g('wkey2').value>=0)?parseInt(g('wkey2').value):0;
    var wkey3=(!isNaN(g('wkey3').value) && g('wkey3').value>=0)?parseInt(g('wkey3').value):0;
    s=removeWhiteNoise(s, wkey1, wkey2, wkey3);
  }
  
  // Checks for substitution for decryption.
  if (g('sub').checked && !a) {
    if (document.getElementsByName('subswitch')[0].checked) {
      s=substitute(a, s);
    }
    else if (document.getElementsByName('subswitch')[1].checked) {
      s=leet(a, s);
    }
    else {
      try {
        var testNum=parseInt(g('subMoves').value); // Throws out non-integers.
        if (testNum<0 || g('subMoves').value=="" || isNaN(g('subMoves').value)) {throw "Keys cannot be negative or not a number!";}
      }
      catch (e) {return;} // User entered an invalid key.
      s=customSub(a, s);
    }
  }
  
  // Decrypts using Morse Code
  if (g('morse').checked && !a) {
    s=fromMorse(s);
  }
  
  // Sets output.
  if (E_TWOWAY) {
    // Two-way box check.
    (a)?setValue('decoder',s):setValue('encoder',s);
  }
  else {
    setValue('decoder',s);
  }
  
  // Loader Animation
  g('loader').src="images/done.gif";
  g('loader').alt="Inactive";
}

/***********
Substitution
************/

function substitute(a, str) {
  n="";
  
  for (i=0; i<s.length; i++) {
    check=0;
    for (k=0; k<key1.length; k++) {
      (a)?encodeFirst():decodeFirst();
    }
    if (check==0&&s.substring(i,i+1)!=null) {n+=s.substring(i,i+1);} // If current letter couldn't be substituted.
  }
  
  return n;
}

// Switches around the characters of the user input based on the arrays.
function encodeFirst() {
  if (s.substring(i,i+1)==key1[k]) {n+=key2[k]; check=1;}
}
function decodeFirst() {
  if (s.substring(i,i+1)==key2[k]) {n+=key1[k]; check=1;}
}

/***
1337
****/

var rchars=new Array(/A{1}/gi,/B{1}/gi,/C{1}/gi,/E{1}/gi,/G{1}/gi,/H{1}/gi,/I{1}/gi,/J{1}/gi,/L{1}/gi,/M{1}/gi,/N{1}/gi,/O{1}/gi,/P{1}/gi,/Q{1}/gi,/R{1}/gi,/S{1}/gi,/T{1}/gi,/V{1}/gi,/W{1}/gi,/X{1}/gi,/Y{1}/gi,/Z{1}/gi,/U{1}/gi,/F{1}/gi,/D{1}/gi,/K{1}/gi);
var schars=new Array('A','B','C','E','G','H','I','J','L','M','N','O','P','Q','R','S','T','V','W','X','Y','Z','U','F','D','K');
var lchars=new Array('4','ß','[','3','6','#','!','¿','1','∑','И','0','9','Ϙ','Я','$','7','∆','Ш','Ж','¥','5','V','‡','Đ','X');
function findLeet(stri) {
  for (l2=0; l2<lchars.length; l2++) {
    if (stri==lchars[l2]) {
      return l2;
    }
  }
  return -1;
}
// Encrypt/Decrypt 1337.
function leet(cType, str) {
  var finalString=str;
  
  // Encrypting
  if (cType) {
    for (eet=0; eet<schars.length; eet++) {
      if (rchars[eet].exec(finalString) != null) {
        finalString=finalString.replace(rchars[eet], lchars[eet]);
      }
    }
  }
  
  // Decrypting
  else {
    finalString="";
    for (eet=0; eet<str.length; eet++) {
      if (findLeet(str.charAt(eet)) != -1) {
        finalString+=schars[findLeet(str.charAt(eet))].toLowerCase();
      }
      else {
        finalString+=str.charAt(eet).toLowerCase();
      }
    }
  }
  
  return finalString;
}

// Custom substitution movement.
function customSub(a, str) {
  var displacement=g('subMoves').value%key1.length;
  var finalString="";
  
  // Checks each character.
  for (i=0; i<str.length; i++) {
    var charFound=false;
    
    // Look for current character in the cipher.
    for (k=0; k<key1.length; k++) {
      var temp;
      if (a) {
        temp=k+displacement;
      }
      else {
        temp=k-displacement;
      }
    
      // Wrap around the cipher.
      if (temp>key1.length) {
        temp-=key1.length;
      }
      if (temp<0) {
        temp+=key1.length;
      }
    
      // Character found in cipher.
      if (str.charAt(i)==key1[k]) {
        finalString+=key1[temp];
        charFound=true;
        break;
      }
    }
    if (!charFound) {
      finalString+=str.charAt(i);
    }
  }
  
  return finalString;
}

/************
Transposition
*************/

// Reverse Text
function flipIt(str) {
  var startOff=str;
  var topOff="";
  for (i=startOff.length; i>=0; i--) {
    topOff+=startOff.charAt(i);
  }
  return topOff;
}

// Encrypts using transposition.
function transpose(str) {
  cryptString=str;
  buckets=new Array();
  for (i=0; i<g('key').value; i++) {
    buckets.push(new Array());
  }
  
  // Partition the message into buckets.
  for (i=0; i<cryptString.length; i++) {
    buckets[i%g('key').value].push(cryptString.charAt(i));
  }
  
  // Build the final message, after transposition.
  cryptString="";
  for (i=0; i<buckets.length; i++) {
    var temp=buckets[i].join("");
    cryptString+=temp;
  }
  return cryptString;
}

// Decrypts a transposition.
function depose(str) {
  cryptString=str;
  buckets=new Array();
  var remainder=cryptString.length%g('key').value;
  var unremainders=g('key').value-remainder;
  var basic_divisor=Math.floor(cryptString.length/g('key').value); // Basic dividing unit.
  
  // String didn't divide evenly by the key.
  while (remainder>0) {
    var tempString=cryptString.substring(0, basic_divisor+1);
    buckets.push(tempString);
    cryptString=cryptString.substring(basic_divisor+1, cryptString.length);
    remainder--;
  }
  
  // Separate the code into the proper buckets.
  for (i=0; i<unremainders; i++) {
    var tempString=cryptString.substring(0, basic_divisor);
    buckets.push(tempString);
    cryptString=cryptString.substring(basic_divisor, cryptString.length);
  }
  
  // Cycles through the buckets, rebuilding the original message.
  cryptString="";
  for (i=0; i<buckets[0].length; i++) {
    for (k=0; k<buckets.length; k++) {
      cryptString+=buckets[k].charAt(i);
    }
  }
  return cryptString;
}

/**************
Polybius Square
***************/

// Searches the list of Polybius keys for the numerical equivalent.
function getPolyNum(b) {
  for (l=0; l<pSquare.length; l++) {
    if (b==pSquare[l]) {return l;}
  }
  return pSquare.length-1;
}

// Encode into a Polybius Square.
function polybius(str) {
  var side=Math.sqrt(key1.length);
  var finalString="";
  
  pSquare=new Array();
  square=new Array();
  
  // Instantiates the second dimensional arrays.
  for (i=0; i<side; i++) {
    square.push(new Array());
    
    // User entered a valid custom alphabet.
    if (g('alphabet').value.length==side) {
      pSquare.push(g('alphabet').value.charAt(i));
    }
    // Default alphabet.
    else {
      pSquare.push(key1[i].toUpperCase());
    }
  }
  
  // Spread the cipher into the square.
  for (i=0; i<key1.length; i++) {
    square[i%side].push(key1[i]);
  }
  
  // Cycles through the message
  for (i=0; i<str.length; i++) {
    var getout=false; // Ends character search.
    
    // Cycles through the square
    for (k=0; k<side; k++) {
      for (j=0; j<side; j++) {
        // Match found!
        if (square[k][j]==str.charAt(i)) {
          finalString+=(pSquare[k]+""+pSquare[j]);
          getout=true;
          break;
        }
      }
      if (getout) {break;}
    }
    
    // All purpose catch for characters outside of the square.
    if (!getout) {
      finalString+="XX";
    }
  }
  
  return finalString;
}

// Gets plaintext from Polybius Square.
function dePolybius(str) {
  var side=Math.sqrt(key1.length);
  var finalString="";
  
  pSquare=new Array();
  square=new Array();
  
  // Instantiates the second dimensional arrays.
  for (i=0; i<side; i++) {
    square.push(new Array());
    
    // User entered a valid custom alphabet.
    if (g('alphabet').value.length==side) {
      pSquare.push(g('alphabet').value.charAt(i));
    }
    // Default alphabet.
    else {
      pSquare.push(key1[i].toUpperCase());
    }
  }
  
  // Spread the cipher into the square.
  for (i=0; i<key1.length; i++) {
    square[i%side].push(key1[i]);
  }
  
  // Derives the correct character based on the two Polybius coordinates.
  for (i=0; i<str.length; i++) {
    finalString+=square[getPolyNum(s.charAt(i))][getPolyNum(s.charAt(i+1))];
    i++;
  }
  
  return finalString;
}

/**********************************************************************
Base64 Encoder/Decoder
Originally created by aardwulf.com
http://www.aardwulf.com/tutor/viewSource.asp?file=base64/base64.html

Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 1.0
http://creativecommons.org/licenses/by-nc-sa/1.0/
************************************************************************/

var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function encode64(input) {
  var output = "";
  var chr1, chr2, chr3 = "";
  var enc1, enc2, enc3, enc4 = "";
  var i = 0;

  do {
     chr1 = input.charCodeAt(i++);
     chr2 = input.charCodeAt(i++);
     chr3 = input.charCodeAt(i++);

     enc1 = chr1 >> 2;
     enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
     enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
     enc4 = chr3 & 63;

     if (isNaN(chr2)) {
        enc3 = enc4 = 64;
     }
     else if (isNaN(chr3)) {
        enc4 = 64;
     }

     output = output + 
        keyStr.charAt(enc1) + 
        keyStr.charAt(enc2) + 
        keyStr.charAt(enc3) + 
        keyStr.charAt(enc4);
     chr1 = chr2 = chr3 = "";
     enc1 = enc2 = enc3 = enc4 = "";
  }
  while (i < input.length);

  return output;
}

function decode64(input) {
  var output = "";
  var chr1, chr2, chr3 = "";
  var enc1, enc2, enc3, enc4 = "";
  var i = 0;

  // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
  var base64test = /[^A-Za-z0-9\+\/\=]/g;
  if (base64test.exec(input)) {
     output+=("There were invalid base64 characters in the input text. Valid base64 characters are A-Z, a-z, 0-9, '+', '/', and '=' Expect errors in decoding.\n \n");
  }
  
  // User can replace bad character.
  if (g('b64Rep').checked && g('b64Replace').value.match(base64test)==null) {
    input = input.replace(base64test, g('b64Replace').value);
  }
  else {
    input = input.replace(base64test, "");
  }

  do {
     enc1 = keyStr.indexOf(input.charAt(i++));
     enc2 = keyStr.indexOf(input.charAt(i++));
     enc3 = keyStr.indexOf(input.charAt(i++));
     enc4 = keyStr.indexOf(input.charAt(i++));

     chr1 = (enc1 << 2) | (enc2 >> 4);
     chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
     chr3 = ((enc3 & 3) << 6) | enc4;

     output = output + String.fromCharCode(chr1);

     if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
     }
     if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
     }

     chr1 = chr2 = chr3 = "";
     enc1 = enc2 = enc3 = enc4 = "";

  }
  while (i < input.length);

  return output;
}

/*********
Morse Code
**********/

// Alphabet Character exists in language.
function charExistsIn(findChar, lang) {
  for (m=0; m<langChars[lang].length; m++) {
    if (langChars[lang][m]==findChar) {
      return m;
    }
  }
  return -1;
}

// Morse letter exists in language.
function codeExistsIn(findChar, lang) {
  for (m=0; m<morseCode[lang].length; m++) {
    if (morseCode[lang][m]==findChar) {
      return m;
    }
  }
  return -1;
}

var morseCode=new Array();
morseCode.push(new Array("-----",".----","..---","...--","....-",".....","-....","--...","---..","----.",".-.-.-","--..--","..--..",".----.","-.-.--","-..-.","-.--.","-.--.-","---...","-.-.-.","-...-",".-.-.","-....-","..--.-",".-..-.","...-..-",".--.-."));
// Arabic Morse
morseCode.push(new Array(".-",".---","-","-.-.",".---","....","---","-..","--..",".-.","---.","...","---","-..-","...-","..-","-.--",".-.-","--.","----","-..-","-.-",".-..","--","-.",".--","..","."));
// Cyrillic Morse
morseCode.push(new Array(".-","-...",".--","--.","-..",".","...-","--..","..",".---","-.-",".-..","--","-.","---",".--.",".-.","...","-","..-","..-.","....","-.-.","---.","----","--.-","-..-","-.--","..-..","..--",".-.-"));
// Greek Morse
morseCode.push(new Array(".-","-...","--.","-..",".","--..","....","-.-.","..","-.-",".-..","--","-.","-..-","---",".--.",".-.","...","-","-.--",".-..","----","--.-",".--"));
// Hebrew Morse
morseCode.push(new Array(".-",".---","--.","-..","---",".","--..","....","..-","..",".-.",".-..","--","-.","-.-.",".---",".--.",".--","--.-",".-.","...","-"));
// Japanese Katakana Morse
morseCode.push(new Array('.-','.-.-','-...','-.-.','-..','.','..-..','..-.','--.','....','-.--.','.---','-.-','...','--','-.','---','---.','.--.','--.-','.-.','...','-','..-','.-..-','..--','.-...','...-','.--','-..-','-.--','--..','----','-.---','.-.--','--.--','-.-.-','-.-..','-..--','-...-','..-.-','--.-.','.-..','--..-','-..-.','---.-','.-.-.','..','..--.','.--.-'));
// Latin Morse
morseCode.push(new Array(".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","----",".-.-",".-.-",".--.-",".--.-","-.-..","-.-..","..--.",".-..-","..-..","--.-.","-.--.",".---.","--.--","---.","---.","...-.",".--..","..--","..--"));
// Katakana (with Dakuten) Morse
morseCode.push(new Array(".-.. ..","-.-.. ..","...- ..","-.-- ..","---- ..","-.-.- ..","--.-. ..","---.- ..",".---. ..","---. ..","-. ..","..-. ..",".--. ..",".-.-- ..","..-.. ..","-... ..","-... ..--.","--..- ..","--..- ..--.","--.. ..","--.. ..--.",". ..",". ..--.","-.. ..",".. ..--.","..- ..","-.- ..","..-- ..",".--.. ..",".--- .."));

var langChars=new Array();
langChars.push(new Array("0","1","2","3","4","5","6","7","8","9",".",",","?","\'","!","/","(",")",":",";","=","+","-","_","\"","$","@"));
// Arabic Alphabet
langChars.push(new Array("ا","ب","ت","ث","ج","ح","خ","د","ذ","ر","ز","س","ش","ص","ض","ط","ظ","ع","غ","ف","ق","ك","ل","م","ن","و","ي","ﺀ"));
// Cyrillic Alphabet
langChars.push(new Array("А","Б","В","Г","Д","Е","Ж","З","И","Й","К","Л","М","Н","О","П","Р","С","Т","У","Ф","Х","Ц","Ч","Ш","Щ","Ь","Ы","Э","Ю","Я"));
// Greek Alphabet
langChars.push(new Array("Α","Β","Γ","Δ","Ε","Ζ","Η","Θ","Ι","Κ","Λ","Μ","Ν","Ξ","Ο","Π","Ρ","Σ","Τ","Υ","Φ","Χ","Ψ","Ω"));
// Hebrew Alphabet
langChars.push(new Array("א","ב","ג","ד","ה","ו","ז","ח","ט","י","כ","ל","מ","נ","ס","ע","פ","צ","ק","ר","ש","ת"));
// Japanese Katakana Alphabet
// With thanks to http://www.asahi-net.or.jp/~rg8k-okt/ecw.htm
langChars.push(new Array("イ","ロ","ハ","ニ","ホ","ヘ","ト","チ","リ","ヌ","ル","ヲ","ワ","ヵ","ヨ","タ","レ","ソ","ツ","ネ","ナ","ラ","ム","ウ","ヰ","ノ","オ","ク","ヤ","マ","ケ","フ","コ","エ","テ","ア","サ","キ","ユ","メ","ミ","シ","ヱ","ヒ","ﾓ","ス","ン","ﾞ","ﾟ","ー"));
// Latin Alphabet
langChars.push(new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","CH","Ä","ÆÀ","Å","Ç","Ĉ","Ð","È","É","Ĝ","Ĥ","Ĵ","Ñ","Ö","Ø","Ŝ","Þ","Ü","Ŭ"));
// Katakana (with Dakuten) Morse
langChars.push(new Array("ガ","ギ","グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","パ","ビ","ピ","ブ","プ","ベ","ペ","ボ","ポ","ヴ","ヷ","ヸ","ヹ","ヺ"));

// Converts TO Morse
function toMorse(str) {
  var s=str.toUpperCase();
  var finalString="";
  
  var words=s.split(" ");
  for (i=0; i<words.length; i++) {
    
    finalString+=" ";
    
    var tempWord=words[i];
    var tempLang=g('morseLang').selectedIndex+1;
    for (k=0; k<tempWord.length; k++) {
      
      // Latin CH
      if (tempLang==6 && tempWord.charAt(k)=="C" && tempWord.charAt(k+1)=="H") {
        k++;
        finalString+=" ----";
        continue;
      }
      // Checks for number/punctuation mark.
      if (charExistsIn(tempWord.charAt(k), 0)>=0) {
        finalString+=" "+morseCode[0][charExistsIn(tempWord.charAt(k), 0)];
        continue;
      }
      
      // Check to see if character exists in selected charset.
      var tempPos=charExistsIn(tempWord.charAt(k), tempLang);
      
      // Special Kana Dakuten check.
      if (tempPos<0 && tempLang==5) {
        tempLang=7;
        tempPos=charExistsIn(tempWord.charAt(k), tempLang);
      }
      
      if (tempPos>=0) {
        finalString+=" "+morseCode[tempLang][tempPos];
      }
      
      // Checks other alphabets if not found.
      if (tempPos<0) {
        for (j in langChars) {
          if (charExistsIn(tempWord.charAt(k), j)>=0) {
            finalString+=" "+morseCode[j][charExistsIn(tempWord.charAt(k), j)];
            break;
          }
        }
      }
    }
    
    finalString+=" ";
  }
  
  return finalString;
}

// Converts FROM Morse
function fromMorse(str) {
  var s=str.toUpperCase();
  var finalString="";
  
  var words=s.split("   ");
  for (i=0; i<words.length; i++) {
    
    var tempWord=words[i].split(" ");
    var tempLang=g('morseLang').selectedIndex+1;
    for (k=0; k<tempWord.length; k++) {
      
      // Checks for number/punctuation mark.
      if (codeExistsIn(tempWord[k], 0)>=0) {
        finalString+=langChars[0][codeExistsIn(tempWord[k], 0)];
        continue;
      }
      
      var tempPos=codeExistsIn(tempWord[k], tempLang);
      if (tempPos>=0) {
        finalString+=langChars[tempLang][tempPos];
      }
    }
    
    finalString+=" ";
  }
  
  return finalString;
}

/************
White Noise
*************/

// Add White Noise
function insertWhiteNoise(stri, w1, w2, w3) {
  var finalString="";
  
  // Strips Whitespace
  var str = stri.replace(new RegExp( "\\n|\\r", "g" )," ");
  
  for (i=0; i<str.length; i++) {
    // Noise Key #1
    if (i%3==0) {
      for (k=0; k<w1; k++) {
        finalString+=key1[Math.round(Math.random()*(key1.length-1))];
      }
    }
    // Noise Key #2
    else if (i%3==1) {
      for (k=0; k<w2; k++) {
        finalString+=key1[Math.round(Math.random()*(key1.length-1))];
      }
    }
    // Noise Key #3
    else if (i%3==2){
      for (k=0; k<w3; k++) {
        finalString+=key1[Math.round(Math.random()*(key1.length-1))];
      }
    }
    finalString+=str.charAt(i);
  }
  return finalString;
}

// Remove White Noise
function removeWhiteNoise(str, w1, w2, w3) {
  var finalString="";
  var currKey=0;
  for (i=0; i<str.length; i++) {
    // Noise Key #1
    if (currKey==0) {
      i+=w1;
      currKey=1;
    }
    // Noise Key #2
    else if (currKey==1) {
      i+=w2;
      currKey=2;
    }
    // Noise Key #3
    else if (currKey==2) {
      i+=w3;
      currKey=0;
    }
    finalString+=str.charAt(i);
  }
  return finalString;
}