Merging fixes and updates from stable branch
authorDan
Fri, 22 Feb 2008 12:51:53 -0500
changeset 458 c433348f3628
parent 439 d9dd2b2134c4 (current diff)
parent 457 d823e49e2e4e (diff)
child 459 31c23016ab62
Merging fixes and updates from stable branch
includes/clientside/static/misc.js
includes/comment.php
includes/common.php
includes/functions.php
includes/pageprocess.php
includes/pageutils.php
includes/paths.php
includes/render.php
includes/rijndael.php
includes/sessions.php
includes/template.php
includes/wikiengine/Tables.php
licenses/cc-by-2.0.html
plugins/SpecialAdmin.php
plugins/SpecialGroups.php
plugins/SpecialUpdownload.php
plugins/SpecialUserFuncs.php
Binary file images/graphbit.png has changed
--- a/includes/common.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/common.php	Fri Feb 22 12:51:53 2008 -0500
@@ -45,6 +45,7 @@
  * @return float
  */
 
+// First check to see if something already declared this function.... it happens often.
 if ( !function_exists('microtime_float') )
 {
   function microtime_float()
@@ -59,7 +60,16 @@
 $_starttime = microtime_float();
 
 // Verbose error reporting
-error_reporting(E_ALL);
+if ( defined('E_STRICT') )
+{
+  // PHP5, PHP6
+  error_reporting(E_ALL & ~E_STRICT);
+}
+else
+{
+  // PHP4
+  error_reporting(E_ALL);
+}
 
 //
 // Determine the location of Enano as an absolute path.
--- a/includes/paths.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/paths.php	Fri Feb 22 12:51:53 2008 -0500
@@ -2,7 +2,7 @@
 
 /**
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.1
+ * Version 1.1.2 (Caoineag alpha 2)
  * Copyright (C) 2006-2007 Dan Fuhry
  * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
  *
--- a/includes/render.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/render.php	Fri Feb 22 12:51:53 2008 -0500
@@ -54,7 +54,7 @@
     if(!$perms->get_permissions('read'))
       return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
     
-    if($wiki == 0 || $render == false)
+    if($namespace != 'Template' && ($wiki == 0 || $render == false))
     {
       if(!$perms->get_permissions('view_source'))
       {
--- a/includes/rijndael.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/rijndael.php	Fri Feb 22 12:51:53 2008 -0500
@@ -1,1086 +1,1083 @@
-<?php
-
-/**
- * Phijndael - an implementation of the AES encryption standard in PHP
- * Originally written by Fritz Schneider <fritz AT cd DOT ucsd DOT edu>
- * Ported to PHP by Dan Fuhry <dan AT enano DOT homelinux DOT org>
- * @package phijndael
- * @author Fritz Schneider
- * @author Dan Fuhry
- * @license BSD-style license
- */
-
-error_reporting(E_ALL);
-
-define ('ENC_HEX', 201);
-define ('ENC_BASE64', 202);
-define ('ENC_BINARY', 203);
-
-$_aes_objcache = array();
-
-class AESCrypt {
-  
-  var $debug = false;
-  var $mcrypt = false;
-  var $decrypt_cache = array();
-
-  // Rijndael parameters --  Valid values are 128, 192, or 256
-  
-  var $keySizeInBits = 128;
-  var $blockSizeInBits = 128;
-  
-  ///////  You shouldn't have to modify anything below this line except for
-  ///////  the function getRandomBytes().
-  //
-  // Note: in the following code the two dimensional arrays are indexed as
-  //       you would probably expect, as array[row][column]. The state arrays
-  //       are 2d arrays of the form state[4][Nb].
-  
-  
-  // The number of rounds for the cipher, indexed by [Nk][Nb]
-  var $roundsArray = Array(0,0,0,0,Array(0,0,0,0,10,0, 12,0, 14),0, 
-                               Array(0,0,0,0,12,0, 12,0, 14),0, 
-                               Array(0,0,0,0,14,0, 14,0, 14) );
-  
-  // The number of bytes to shift by in shiftRow, indexed by [Nb][row]
-  var $shiftOffsets = Array(0,0,0,0,Array(0,1, 2, 3),0,Array(0,1, 2, 3),0,Array(0,1, 3, 4) );
-  
-  // The round constants used in subkey expansion
-  var $Rcon = Array( 
-  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 
-  0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 
-  0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 
-  0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 
-  0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 );
-  
-  // Precomputed lookup table for the SBox
-  var $SBox = Array(
-   99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 
-  118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 
-  114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 
-  216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 
-  235,  39, 178, 117,   9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 
-  179,  41, 227,  47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 
-  190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69, 
-  249,   2, 127,  80,  60, 159, 168,  81, 163,  64, 143, 146, 157,  56, 245, 
-  188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,  
-  23,  196, 167, 126,  61, 100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 
-  144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
-    6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
-  141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,  
-   46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62, 
-  181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
-  248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
-  140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  
-   22 );
-  
-  // Precomputed lookup table for the inverse SBox
-  var $SBoxInverse = Array(
-   82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 
-  251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 
-  233, 203,  84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 
-  250, 195,  78,   8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 
-  109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 
-  204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  
-   70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247, 
-  228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2, 
-  193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220, 
-  234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
-   53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29, 
-   41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75, 
-  198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
-   51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
-  127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
-  224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97, 
-   23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
-  125 );
-  
-  function __construct($ks = 128, $bs = 128, $debug = false)
-  {
-    $this->keySizeInBits = $ks;
-    $this->blockSizeInBits = $bs;
-    
-    // Use the Mcrypt library? This speeds things up dramatically.
-    if(defined('MCRYPT_RIJNDAEL_' . $ks) && defined('MCRYPT_ACCEL'))
-    {
-      eval('$mcb = MCRYPT_RIJNDAEL_' . $ks.';');
-      $bks = mcrypt_module_get_algo_block_size($mcb);
-      $bks = $bks * 8;
-      if ( $bks != $bs )
-      {
-        $mcb = false;
-        echo (string)$bks;
-      }
-    }
-    else
-    {
-      $mcb = false;
-    }
-      
-    $this->mcrypt = $mcb;
-    
-    // Cipher parameters ... do not change these
-    $this->Nk = $this->keySizeInBits / 32;
-    $this->Nb = $this->blockSizeInBits / 32;
-    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
-    $this->debug = $debug;
-  }
-  
-  public static function singleton($key_size, $block_size)
-  {
-    static $_aes_objcache;
-    if ( isset($_aes_objcache["$key_size,$block_size"]) )
-    {
-      return $_aes_objcache["$key_size,$block_size"];
-    }
-    
-    $_aes_objcache["$key_size,$block_size"] = new AESCrypt($key_size, $block_size);
-    return $_aes_objcache["$key_size,$block_size"];
-  }
-  
-  // Error handler
-  
-  function trigger_error($text, $level = E_USER_NOTICE)
-  {
-    $bt = debug_backtrace();
-    $lastfunc =& $bt[1];
-    switch($level)
-    {
-      case E_USER_NOTICE:
-      default:
-        $desc = 'Notice';
-        break;
-      case E_USER_WARNING:
-        $desc = 'Warning';
-        break;
-      case E_USER_ERROR:
-        $desc = 'Fatal';
-        break;
-    }
-    ob_start();
-    if($this->debug || $level == E_USER_ERROR) echo "AES encryption: <b>{$desc}:</b> $text in {$lastfunc['file']} on line {$lastfunc['line']} in function {$lastfunc['function']}<br />";
-    if($this->debug)
-    {
-      //echo '<pre>'.enano_debug_print_backtrace(true).'</pre>';
-    }
-    ob_end_flush();
-    if($level == E_USER_ERROR)
-    {
-      echo '<p><b>This can sometimes happen if you are upgrading Enano to a new version and did not log out first.</b> <a href="'.$_SERVER['PHP_SELF'].'?do=diag&amp;sub=cookie_destroy">Click here</a> to force cookies to clear and try again. You will be logged out.</p>';
-      exit;
-    }
-  }
-  
-  function array_slice_js_compat($array, $start, $finish = 0)
-  {
-    $len = $finish - $start;
-    if($len < 0) $len = 0 - $len;
-    //if($this->debug) echo (string)$len . ' ';
-    //if(count($array) < $start + $len)
-    //  $this->trigger_error('Index out of range', E_USER_WARNING);
-    return array_slice($array, $start, $len);
-  }
-  
-  function concat($s1, $s2)
-  {
-    if(is_array($s1) && is_array($s2))
-      return array_merge($s1, $s2);
-    elseif( ( is_array($s1) && !is_array($s2) ) || ( !is_array($s1) && is_array($s2) ) )
-    {
-      $this->trigger_error('incompatible types - you can\'t combine a non-array with an array', E_USER_WARNING);
-      return false;
-    }
-    else
-      return $s1 . $s2;
-  }
-  
-  // This method circularly shifts the array left by the number of elements
-  // given in its parameter. It returns the resulting array and is used for 
-  // the ShiftRow step. Note that shift() and push() could be used for a more 
-  // elegant solution, but they require IE5.5+, so I chose to do it manually. 
-  
-  function cyclicShiftLeft($theArray, $positions) {
-    if(!is_int($positions))
-    {
-      $this->trigger_error('$positions is not an integer! Backtrace:<br /><pre>'.print_r(debug_backtrace(), true).'</pre>', E_USER_WARNING);
-      return false;
-    }
-    $second = array_slice($theArray, 0, $positions);
-    $first = array_slice($theArray, $positions);
-    $theArray = array_merge($first, $second);
-    return $theArray;
-  }
-  
-  // Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
-  
-  function xtime($poly) {
-    $poly <<= 1;
-    return (($poly & 0x100) ? ($poly ^ 0x11B) : ($poly));
-  }
-  
-  // Multiplies the two elements of GF(2^8) together and returns the result.
-  // See the Rijndael spec, but should be straightforward: for each power of
-  // the indeterminant that has a 1 coefficient in x, add y times that power
-  // to the result. x and y should be bytes representing elements of GF(2^8)
-  
-  function mult_GF256($x, $y) {
-    $result = 0;
-    
-    for ($bit = 1; $bit < 256; $bit *= 2, $y = $this->xtime($y)) {
-      if ($x & $bit) 
-        $result ^= $y;
-    }
-    return $result;
-  }
-  
-  // Performs the substitution step of the cipher. State is the 2d array of
-  // state information (see spec) and direction is string indicating whether
-  // we are performing the forward substitution ("encrypt") or inverse 
-  // substitution (anything else)
-  
-  function byteSub(&$state, $direction) {
-    //global $this->SBox, $this->SBoxInverse, $this->Nb;
-    if ($direction == "encrypt")           // Point S to the SBox we're using
-      $S =& $this->SBox;
-    else
-      $S =& $this->SBoxInverse;
-    for ($i = 0; $i < 4; $i++)           // Substitute for every byte in state
-      for ($j = 0; $j < $this->Nb; $j++)
-         $state[$i][$j] = $S[$state[$i][$j]];
-  }
-  
-  // Performs the row shifting step of the cipher.
-  
-  function shiftRow(&$state, $direction) {
-    //global $this->Nb, $this->shiftOffsets;
-    for ($i=1; $i<4; $i++)               // Row 0 never shifts
-      if ($direction == "encrypt")
-         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->shiftOffsets[$this->Nb][$i]);
-      else
-         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->Nb - $this->shiftOffsets[$this->Nb][$i]);
-  
-  }
-  
-  // Performs the column mixing step of the cipher. Most of these steps can
-  // be combined into table lookups on 32bit values (at least for encryption)
-  // to greatly increase the speed. 
-  
-  function mixColumn(&$state, $direction) {
-    //global $this->Nb;
-    $b = Array();                                  // Result of matrix multiplications
-    for ($j = 0; $j < $this->Nb; $j++) {                 // Go through each column...
-      for ($i = 0; $i < 4; $i++) {                 // and for each row in the column...
-        if ($direction == "encrypt")
-          $b[$i] = $this->mult_GF256($state[$i][$j], 2) ^ // perform mixing
-                   $this->mult_GF256($state[($i+1)%4][$j], 3) ^ 
-                   $state[($i+2)%4][$j] ^ 
-                   $state[($i+3)%4][$j];
-        else 
-          $b[$i] = $this->mult_GF256($state[$i][$j], 0xE) ^ 
-                   $this->mult_GF256($state[($i+1)%4][$j], 0xB) ^
-                   $this->mult_GF256($state[($i+2)%4][$j], 0xD) ^
-                   $this->mult_GF256($state[($i+3)%4][$j], 9);
-      }
-      for ($i = 0; $i < 4; $i++)          // Place result back into column
-        $state[$i][$j] = $b[$i];
-    }
-  }
-  
-  // Adds the current round key to the state information. Straightforward.
-  
-  function addRoundKey(&$state, $roundKey) {
-    //global $this->Nb;
-    for ($j = 0; $j < $this->Nb; $j++) {                      // Step through columns...
-      $state[0][$j] ^= ( $roundKey[$j] & 0xFF);         // and XOR
-      $state[1][$j] ^= (($roundKey[$j]>>8) & 0xFF);
-      $state[2][$j] ^= (($roundKey[$j]>>16) & 0xFF);
-      $state[3][$j] ^= (($roundKey[$j]>>24) & 0xFF);
-    }
-  }
-  
-  // This function creates the expanded key from the input (128/192/256-bit)
-  // key. The parameter key is an array of bytes holding the value of the key.
-  // The returned value is an array whose elements are the 32-bit words that 
-  // make up the expanded key.
-  
-  function keyExpansion($key) {
-    //global $this->keySizeInBits, $this->blockSizeInBits, $this->roundsArray, $this->Nk, $this->Nb, $this->Nr, $this->Nk, $this->SBox, $this->Rcon;
-    $expandedKey = Array();
-  
-    // in case the key size or parameters were changed...
-    $this->Nk = $this->keySizeInBits / 32;                   
-    $this->Nb = $this->blockSizeInBits / 32;
-    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
-  
-    for ($j=0; $j < $this->Nk; $j++)     // Fill in input key first
-      $expandedKey[$j] = 
-        ($key[4*$j]) | ($key[4*$j+1]<<8) | ($key[4*$j+2]<<16) | ($key[4*$j+3]<<24);
-  
-    // Now walk down the rest of the array filling in expanded key bytes as
-    // per Rijndael's spec
-    for ($j = $this->Nk; $j < $this->Nb * ($this->Nr + 1); $j++) {    // For each word of expanded key
-      $temp = $expandedKey[$j - 1];
-      if ($j % $this->Nk == 0) 
-        $temp = ( ($this->SBox[($temp>>8) & 0xFF]) |
-                  ($this->SBox[($temp>>16) & 0xFF]<<8) |
-                  ($this->SBox[($temp>>24) & 0xFF]<<16) |
-                  ($this->SBox[$temp & 0xFF]<<24) ) ^ $this->Rcon[floor($j / $this->Nk) - 1];
-      elseif  ($this->Nk > 6 && $j % $this->Nk == 4)
-        $temp = ($this->SBox[($temp>>24) & 0xFF]<<24) |
-               ($this->SBox[($temp>>16) & 0xFF]<<16) |
-               ($this->SBox[($temp>>8) & 0xFF]<<8) |
-               ($this->SBox[ $temp & 0xFF]);
-      $expandedKey[$j] = $expandedKey[$j-$this->Nk] ^ $temp;
-    }
-    return $expandedKey;
-  }
-  
-  // Rijndael's round functions... 
-  
-  function RijndaelRound(&$state, $roundKey) {
-    $this->byteSub($state, "encrypt");
-    $this->shiftRow($state, "encrypt");
-    $this->mixColumn($state, "encrypt");
-    $this->addRoundKey($state, $roundKey);
-  }
-  
-  function InverseRijndaelRound(&$state, $roundKey) {
-    $this->addRoundKey($state, $roundKey);
-    $this->mixColumn($state, "decrypt");
-    $this->shiftRow($state, "decrypt");
-    $this->byteSub($state, "decrypt");
-  }
-  
-  function FinalRijndaelRound(&$state, $roundKey) {
-    $this->byteSub($state, "encrypt");
-    $this->shiftRow($state, "encrypt");
-    $this->addRoundKey($state, $roundKey);
-  }
-  
-  function InverseFinalRijndaelRound(&$state, $roundKey){
-    $this->addRoundKey($state, $roundKey);
-    $this->shiftRow($state, "decrypt");
-    $this->byteSub($state, "decrypt");  
-  }
-  
-  // encrypt is the basic encryption function. It takes parameters
-  // block, an array of bytes representing a plaintext block, and expandedKey,
-  // an array of words representing the expanded key previously returned by
-  // keyExpansion(). The ciphertext block is returned as an array of bytes.
-  
-  function cryptBlock($block, $expandedKey) {
-    //global $this->blockSizeInBits, $this->Nb, $this->Nr;
-    $t=count($block)*8;
-    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
-    {
-      $this->trigger_error('block is bad or block size is wrong<pre>'.print_r($block, true).'</pre><p>Aiming for size '.$this->blockSizeInBits.', got '.$t.'.', E_USER_WARNING); 
-      return false;
-    }
-    if (!$expandedKey)
-      return;
-  
-    $block = $this->packBytes($block);
-    $this->addRoundKey($block, $expandedKey);
-    for ($i=1; $i<$this->Nr; $i++) 
-      $this->RijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
-    $this->FinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr));
-    $ret = $this->unpackBytes($block);
-    return $ret;
-  }
-  
-  // decrypt is the basic decryption function. It takes parameters
-  // block, an array of bytes representing a ciphertext block, and expandedKey,
-  // an array of words representing the expanded key previously returned by
-  // keyExpansion(). The decrypted block is returned as an array of bytes.
-  
-  function unCryptBlock($block, $expandedKey) {
-    $t = count($block)*8;
-    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
-    {
-      $this->trigger_error('$block is not a valid rijndael-block array: '.$this->byteArrayToHex($block).'<pre>'.print_r($block, true).'</pre><p>Block size is '.$t.', should be '.$this->blockSizeInBits.'</p>', E_USER_WARNING);
-      return false;
-    }
-    if (!$expandedKey)
-    {
-      $this->trigger_error('$expandedKey is invalid', E_USER_WARNING);
-      return false;
-    }
-  
-    $block = $this->packBytes($block);
-    $this->InverseFinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr)); 
-    for ($i = $this->Nr - 1; $i>0; $i--) 
-    {
-      $this->InverseRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
-    }
-    $this->addRoundKey($block, $expandedKey);
-    $ret = $this->unpackBytes($block);
-    if(!is_array($ret))
-    {
-      $this->trigger_error('$ret is not an array', E_USER_WARNING);
-    }
-    return $ret;
-  }
-  
-  // This method takes a byte array (byteArray) and converts it to a string by
-  // applying String.fromCharCode() to each value and concatenating the result.
-  // The resulting string is returned. Note that this function SKIPS zero bytes
-  // under the assumption that they are padding added in formatPlaintext().
-  // Obviously, do not invoke this method on raw data that can contain zero
-  // bytes. It is really only appropriate for printable ASCII/Latin-1 
-  // values. Roll your own function for more robust functionality :)
-  
-  function byteArrayToString($byteArray) {
-    $result = "";
-    for($i=0; $i<count($byteArray); $i++)
-      if ($byteArray[$i] != 0) 
-        $result .= chr($byteArray[$i]);
-    return $result;
-  }
-  
-  // This function takes an array of bytes (byteArray) and converts them
-  // to a hexadecimal string. Array element 0 is found at the beginning of 
-  // the resulting string, high nibble first. Consecutive elements follow
-  // similarly, for example [16, 255] --> "10ff". The function returns a 
-  // string.
-  
-  /*
-  function byteArrayToHex($byteArray) {
-    $result = "";
-    if (!$byteArray)
-      return;
-    for ($i=0; $i<count($byteArray); $i++)
-      $result .= (($byteArray[$i]<16) ? "0" : "") + toString($byteArray[$i]); // magic number here is 16, not sure how to handle this...
-  
-    return $result;
-  }
-  */
-  function byteArrayToHex($arr)
-  {
-    $ret = '';
-    foreach($arr as $a)
-    {
-      $nibble = (string)dechex(intval($a));
-      if(strlen($nibble) == 1) $nibble = '0' . $nibble;
-      $ret .= $nibble;
-    }
-    return $ret;
-  }
-  
-  // PHP equivalent of Javascript's toString()
-  function toString($bool)
-  {
-    if(is_bool($bool))
-      return ($bool) ? 'true' : 'false';
-    elseif(is_array($bool))
-      return implode(',', $bool);
-    else
-      return (string)$bool;
-  }
-  
-  // This function converts a string containing hexadecimal digits to an 
-  // array of bytes. The resulting byte array is filled in the order the
-  // values occur in the string, for example "10FF" --> [16, 255]. This
-  // function returns an array. 
-  
-  /*
-  function hexToByteArray($hexString) {
-    $byteArray = Array();
-    if (strlen($hexString) % 2)             // must have even length
-      return;
-    if (strstr($hexString, "0x") == $hexString || strstr($hexString, "0X") == $hexString)
-      $hexString = substr($hexString, 2);
-    for ($i = 0; $i<strlen($hexString); $i++,$i++) 
-      $byteArray[floor($i/2)] = intval(substr($hexString, $i, 2)); // again, that strange magic number: 16
-    return $byteArray;
-  }
-  */
-  function hexToByteArray($str)
-  {
-    if(substr($str, 0, 2) == '0x' || substr($str, 0, 2) == '0X')
-      $str = substr($str, 2);
-    $arr = Array();
-    $str = $this->enano_str_split($str, 2);
-    foreach($str as $s)
-    {
-      $arr[] = intval(hexdec($s));
-    }
-    return $arr;
-  }
-  
-  // This function packs an array of bytes into the four row form defined by
-  // Rijndael. It assumes the length of the array of bytes is divisible by
-  // four. Bytes are filled in according to the Rijndael spec (starting with
-  // column 0, row 0 to 3). This function returns a 2d array.
-  
-  function packBytes($octets) {
-    $state = Array();
-    if (!$octets || count($octets) % 4)
-      return;
-  
-    $state[0] = Array(); $state[1] = Array(); 
-    $state[2] = Array(); $state[3] = Array();
-    for ($j=0; $j<count($octets); $j = $j+4) {
-       $state[0][$j/4] = $octets[$j];
-       $state[1][$j/4] = $octets[$j+1];
-       $state[2][$j/4] = $octets[$j+2];
-       $state[3][$j/4] = $octets[$j+3];
-    }
-    return $state;
-  }
-  
-  // This function unpacks an array of bytes from the four row format preferred
-  // by Rijndael into a single 1d array of bytes. It assumes the input "packed"
-  // is a packed array. Bytes are filled in according to the Rijndael spec. 
-  // This function returns a 1d array of bytes.
-  
-  function unpackBytes($packed) {
-    $result = Array();
-    for ($j=0; $j<count($packed[0]); $j++) {
-      $result[] = $packed[0][$j];
-      $result[] = $packed[1][$j];
-      $result[] = $packed[2][$j];
-      $result[] = $packed[3][$j];
-    }
-    return $result;
-  }
-  
-  function charCodeAt($str, $i)
-  {
-    return ord(substr($str, $i, 1));
-  }
-  
-  function fromCharCode($str)
-  {
-    return chr($str);
-  }
-  
-  // This function takes a prospective plaintext (string or array of bytes)
-  // and pads it with zero bytes if its length is not a multiple of the block 
-  // size. If plaintext is a string, it is converted to an array of bytes
-  // in the process. The type checking can be made much nicer using the 
-  // instanceof operator, but this operator is not available until IE5.0 so I 
-  // chose to use the heuristic below. 
-  
-  function formatPlaintext($plaintext) {
-    //global $this->blockSizeInBits;
-    $bpb = $this->blockSizeInBits / 8;               // bytes per block
-  
-    // if primitive string or String instance
-    if (is_string($plaintext)) {
-      $plaintext = $this->enano_str_split($plaintext);
-      // Unicode issues here (ignoring high byte)
-      for ($i=0; $i<sizeof($plaintext); $i++)
-        $plaintext[$i] = $this->charCodeAt($plaintext[$i], 0) & 0xFF;
-    } 
-  
-    for ($i = $bpb - (sizeof($plaintext) % $bpb); $i > 0 && $i < $bpb; $i--) 
-      $plaintext[] = 0;
-    
-    return $plaintext;
-  }
-  
-  // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
-  // TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
-  // APPLICATION. (edit: done, mt_rand() is relatively secure)
-  
-  function getRandomBytes($howMany) {
-    $bytes = Array();
-    for ($i=0; $i<$howMany; $i++)
-      $bytes[$i] = mt_rand(0, 255);
-    return $bytes;
-  }
-  
-  // rijndaelEncrypt(plaintext, key, mode)
-  // Encrypts the plaintext using the given key and in the given mode. 
-  // The parameter "plaintext" can either be a string or an array of bytes. 
-  // The parameter "key" must be an array of key bytes. If you have a hex 
-  // string representing the key, invoke hexToByteArray() on it to convert it 
-  // to an array of bytes. The third parameter "mode" is a string indicating
-  // the encryption mode to use, either "ECB" or "CBC". If the parameter is
-  // omitted, ECB is assumed.
-  // 
-  // An array of bytes representing the cihpertext is returned. To convert 
-  // this array to hex, invoke byteArrayToHex() on it. If you are using this 
-  // "for real" it is a good idea to change the function getRandomBytes() to 
-  // something that returns truly random bits.
-  
-  function rijndaelEncrypt($plaintext, $key, $mode = 'ECB') {
-    //global $this->blockSizeInBits, $this->keySizeInBits;
-    $bpb = $this->blockSizeInBits / 8;          // bytes per block
-    // var ct;                                 // ciphertext
-  
-    if($mode == 'CBC')
-    {
-      if (!is_string($plaintext) || !is_array($key))
-      {
-        $this->trigger_error('In CBC mode the first and second parameters should be strings', E_USER_WARNING);
-        return false;
-      }
-    } else {
-      if (!is_array($plaintext) || !is_array($key))
-      {
-        $this->trigger_error('In ECB mode the first and second parameters should be byte arrays', E_USER_WARNING);
-        return false;
-      }
-    }
-    if (sizeof($key)*8 != $this->keySizeInBits)
-    {
-      $this->trigger_error('The key needs to be '. ( $this->keySizeInBits / 8 ) .' bytes in length', E_USER_WARNING);
-      return false;
-    }
-    if ($mode == "CBC")
-      $ct = $this->getRandomBytes($bpb);             // get IV
-    else {
-      $mode = "ECB";
-      $ct = Array();
-    }
-    
-    // convert plaintext to byte array and pad with zeros if necessary. 
-    $plaintext = $this->formatPlaintext($plaintext);
-    
-    $expandedKey = $this->keyExpansion($key);
-    
-    for ($block=0; $block<sizeof($plaintext) / $bpb; $block++) {
-      $aBlock = $this->array_slice_js_compat($plaintext, $block*$bpb, ($block+1)*$bpb);
-      if ($mode == "CBC")
-      {
-        for ($i=0; $i<$bpb; $i++)
-        {
-          $aBlock[$i] ^= $ct[$block*$bpb + $i];
-        }
-      }
-      $cp = $this->cryptBlock($aBlock, $expandedKey);
-      $ct = $this->concat($ct, $cp);
-    }
-  
-    return $ct;
-  }
-  
-  // rijndaelDecrypt(ciphertext, key, mode)
-  // Decrypts the using the given key and mode. The parameter "ciphertext" 
-  // must be an array of bytes. The parameter "key" must be an array of key 
-  // bytes. If you have a hex string representing the ciphertext or key, 
-  // invoke hexToByteArray() on it to convert it to an array of bytes. The
-  // parameter "mode" is a string, either "CBC" or "ECB".
-  // 
-  // An array of bytes representing the plaintext is returned. To convert 
-  // this array to a hex string, invoke byteArrayToHex() on it. To convert it 
-  // to a string of characters, you can use byteArrayToString().
-  
-  function rijndaelDecrypt($ciphertext, $key, $mode = 'ECB') {
-    //global $this->blockSizeInBits, $this->keySizeInBits;
-    $bpb = $this->blockSizeInBits / 8;          // bytes per block
-    $pt = Array();                   // plaintext array
-    // $aBlock;                             // a decrypted block
-    // $block;                              // current block number
-  
-    if (!$ciphertext)
-    {
-      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
-      return false;
-    }
-    if(  !is_array($key) )
-    {
-      $this->trigger_error('$key should be a byte array', E_USER_WARNING);
-      return false;
-    }
-    if( is_string($ciphertext) )
-    {
-      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
-      return false;
-    }
-    if (sizeof($key)*8 != $this->keySizeInBits)
-    {
-      $this->trigger_error('Encryption key is the wrong length', E_USER_WARNING);
-      return false;
-    }
-    if (!$mode)
-      $mode = "ECB";                         // assume ECB if mode omitted
-  
-    $expandedKey = $this->keyExpansion($key);
-   
-    // work backwards to accomodate CBC mode 
-    for ($block=(sizeof($ciphertext) / $bpb)-1; $block>0; $block--)
-    {
-      if( ( $block*$bpb ) + ( ($block+1)*$bpb ) > count($ciphertext) )
-      {
-        //$this->trigger_error('$ciphertext index out of bounds', E_USER_ERROR);
-      }
-      $current_block = $this->array_slice_js_compat($ciphertext, $block*$bpb, ($block+1)*$bpb);
-      if(count($current_block) * 8 != $this->blockSizeInBits)
-      {
-        // $c=count($current_block)*8;
-        // $this->trigger_error('We got a '.$c.'-bit block, instead of '.$this->blockSizeInBits.'', E_USER_ERROR);
-      }
-      $aBlock = $this->uncryptBlock($current_block, $expandedKey);
-      if(!$aBlock)
-      {
-        $this->trigger_error('Shared block decryption routine returned false', E_USER_WARNING);
-        return false;
-      }
-      if ($mode == "CBC")
-        for ($i=0; $i<$bpb; $i++) 
-          $pt[($block-1)*$bpb + $i] = $aBlock[$i] ^ $ciphertext[($block-1)*$bpb + $i];
-      else
-        $pt = $this->concat($aBlock, $pt);
-    }
-  
-    // do last block if ECB (skips the IV in CBC)
-    if ($mode == "ECB")
-    {
-      $x = $this->uncryptBlock($this->array_slice_js_compat($ciphertext, 0, $bpb), $expandedKey);
-      if(!$x)
-      {
-        $this->trigger_error('ECB block decryption routine returned false', E_USER_WARNING);
-        return false;
-      }
-      $pt = $this->concat($x, $pt);
-      if(!$pt)
-      {
-        $this->trigger_error('ECB concatenation routine returned false', E_USER_WARNING);
-        return false;
-      }
-    }
-  
-    return $pt;
-  }
-  
-  /**
-   * Wrapper for encryption.
-   * @param string $text the text to encrypt
-   * @param string $key the raw binary key to encrypt with
-   * @param int $return_encoding optional - can be ENC_BINARY, ENC_HEX or ENC_BASE64
-   */
-   
-  function encrypt($text, $key, $return_encoding = ENC_HEX)
-  {
-    if ( $text == '' )
-      return '';
-    if ( $this->mcrypt && $this->blockSizeInBits == mcrypt_module_get_algo_block_size(eval('return MCRYPT_RIJNDAEL_'.$this->keySizeInBits.';')) )
-    {
-      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
-      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
-      $cryptext = mcrypt_encrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
-      switch($return_encoding)
-      {
-        case ENC_HEX:
-        default:
-          $cryptext = $this->strtohex($cryptext);
-          break;
-        case ENC_BINARY:
-          $cryptext = $cryptext;
-          break;
-        case ENC_BASE64:
-          $cryptext = base64_encode($cryptext);
-          break;
-      }
-    }
-    else
-    {
-      $key = $this->prepare_string($key);
-      $text = $this->prepare_string($text);
-      profiler_log('AES: Started encryption of a string');
-      $cryptext = $this->rijndaelEncrypt($text, $key, 'ECB');
-      profiler_log('AES: Finished encryption of a string');
-      if(!is_array($cryptext))
-      {
-        echo 'Warning: encryption failed for string: '.print_r($text,true).'<br />';
-        return false;
-      }
-      switch($return_encoding)
-      {
-        case ENC_HEX:
-        default:
-          $cryptext = $this->byteArrayToHex($cryptext);
-          break;
-        case ENC_BINARY:
-          $cryptext = $this->byteArrayToString($cryptext);
-          break;
-        case ENC_BASE64:
-          $cryptext = base64_encode($this->byteArrayToString($cryptext));
-          break;
-      }
-    }
-    return $cryptext;
-  }
-  
-  /**
-   * Wrapper for decryption.
-   * @param string $text the encrypted text
-   * @param string $key the raw binary key used to encrypt the text
-   * @param int $input_encoding the encoding used for the encrypted string. Can be ENC_BINARY, ENC_HEX, or ENC_BASE64.
-   * @return string
-   */
-   
-  function decrypt($text, $key, $input_encoding = ENC_HEX)
-  {
-    if ( $text == '' )
-      return '';
-    
-    switch($input_encoding)
-    {
-      case ENC_BINARY:
-      default:
-        break;
-      case ENC_HEX:
-        $text = $this->hextostring($text);
-        break;
-      case ENC_BASE64:
-        $text = base64_decode($text);
-        break;
-    }
-    
-    // Run memory-cache check
-    if ( isset($this->decrypt_cache[$key]) && is_array($this->decrypt_cache[$key]) )
-    {
-      if ( isset($this->decrypt_cache[$key][$text]) )
-      {
-        return $this->decrypt_cache[$key][$text];
-      }
-    }
-    
-    // Run disk-cache check
-    $hash = sha1($text . '::' . $key);
-    if ( $dypt = aes_decrypt_cache_fetch($hash) )
-      return $dypt;
-    
-    $text_bin = $text;
-    $key_bin = $key;
-    
-    if ( $this->mcrypt )
-    {
-      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
-      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
-      $dypt = mcrypt_decrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
-    }
-    else
-    {
-      $etext = $this->prepare_string($text);
-      $ekey  = $this->prepare_string($key);
-      $mod = count($etext) % $this->blockSizeInBits;
-      profiler_log('AES: Started decryption of a string');
-      $dypt = $this->rijndaelDecrypt($etext, $ekey, 'ECB');
-      profiler_log('AES: Finished decryption of a string');
-      if(!$dypt)
-      {
-        echo '<pre>'.print_r($dypt, true).'</pre>';
-        $this->trigger_error('Rijndael main decryption routine failed', E_USER_ERROR);
-      }
-      $dypt = $this->byteArrayToString($dypt);
-    }
-    if ( !isset($this->decrypt_cache[$key_bin]) )
-      $this->decrypt_cache[$key_bin] = array();
-    
-    $this->decrypt_cache[$key_bin][$text_bin] = $dypt;
-    
-    aes_decrypt_cache_store($text_bin, $dypt, $key_bin);
-    
-    return $dypt;
-  }
-  
-  /**
-   * Enano-ese equivalent of str_split() which is only found in PHP5
-   * @param $text string the text to split
-   * @param $inc int size of each block
-   * @return array
-   */
-   
-  function enano_str_split($text, $inc = 1)
-  {
-    if($inc < 1) return false;
-    if($inc >= strlen($text)) return Array($text);
-    $len = ceil(strlen($text) / $inc);
-    $ret = Array();
-    for($i=0;$i<strlen($text);$i=$i+$inc)
-    {
-      $ret[] = substr($text, $i, $inc);
-    }
-    return $ret;
-  }
-  
-  /**
-   * Generates a random key suitable for encryption
-   * @param int $len the length of the key, in bytes
-   * @return string a BINARY key
-   */
-  
-  function randkey($len = 32)
-  {
-    $key = '';
-    for($i=0;$i<$len;$i++)
-    {
-      $key .= chr(mt_rand(0, 255));
-    }
-    if ( file_exists('/dev/urandom') && is_readable('/dev/urandom') )
-    {
-      // Let's use something a little more secure
-      $ur = @fopen('/dev/urandom', 'r');
-      if ( !$ur )
-        return $key;
-      $ukey = @fread($ur, $len);
-      fclose($ur);
-      if ( strlen($ukey) != $len )
-        return $key;
-      return $ukey;
-    }
-    return $key;
-  }
-  
-  /*
-  function byteArrayToString($arr)
-  {
-    if(!is_array($arr))
-    {
-      $this->trigger_error('First parameter should be an array', E_USER_WARNING);
-      return false;
-    }
-    $ret = '';
-    foreach($arr as $a)
-    {
-      if($a != 0) $ret .= chr($a);
-    }
-    return $ret;
-  }
-  */
-  
-  function strtohex($str)
-  {
-    $str = $this->enano_str_split($str);
-    $ret = '';
-    foreach($str as $s)
-    {
-      $chr = dechex(ord($s));
-      if(strlen($chr) < 2) $chr = '0' . $chr;
-      $ret .= $chr;
-    }
-    return $ret;
-  }
-  
-  function gen_readymade_key()
-  {
-    $key = $this->strtohex($this->randkey($this->keySizeInBits / 8));
-    return $key;
-  }
-  
-  function prepare_string($text)
-  {
-    $ret = $this->hexToByteArray($this->strtohex($text));
-    if(count($ret) != strlen($text))
-    {
-      die('Could not convert string "' . $text . '" to hex byte array for encryption');
-    }
-    return $ret;
-  }
-  
-  /**
-   * Decodes a hex string.
-   * @param string $hex The hex code to decode
-   * @return string
-   */
-  
-  function hextostring($hex)
-  {
-    $hex = $this->enano_str_split($hex, 2);
-    $bin_key = '';
-    foreach($hex as $nibble)
-    {
-      $byte = chr(hexdec($nibble));
-      $bin_key .= $byte;
-    }
-    return $bin_key;
-  }
-}
-
-function aes_decrypt_cache_store($encrypted, $decrypted, $key)
-{
-  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
-  // only cache if $decrypted is long enough to actually warrant caching
-  if ( strlen($decrypted) < 32 )
-  {
-    profiler_log("AES: Skipped caching a string (probably a password, we dunno) because it's too short");
-    return false;
-  }
-  if ( file_exists($cache_file) )
-  {
-    require_once($cache_file);
-    global $aes_decrypt_cache;
-    $cachekey = sha1($encrypted . '::' . $key);
-    $aes_decrypt_cache[$cachekey] = $decrypted;
-    
-    if ( count($aes_decrypt_cache) > 5000 )
-    {
-      // we've got a lot of strings in the cache, clear out a few
-      $keys = array_keys($aes_decrypt_cache);
-      for ( $i = 0; $i < 2500; $i++ )
-      {
-        unset($aes_decrypt_cache[$keys[$i]]);
-        unset($aes_decrypt_cache[$keys[$i]]);
-      }
-    }
-  }
-  else
-  {
-    $aes_decrypt_cache = array(
-      sha1($encrypted . '::' . $key) => $decrypted
-    );
-  }
-  // call var_export and collect contents
-  ob_start();
-  var_export($aes_decrypt_cache);
-  $dec_cache_string = ob_get_contents();
-  ob_end_clean();
-  $f = @fopen($cache_file, 'w');
-  if ( !$f )
-    return false;
-  fwrite($f, "<?php
-\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
-");
-  fclose($f);
-  return true;
-}
-
-function aes_decrypt_cache_fetch($hash)
-{
-  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
-  if ( !file_exists($cache_file) )
-    return false;
-  
-  require_once($cache_file);
-  global $aes_decrypt_cache;
-  if ( isset($aes_decrypt_cache[$hash]) )
-  {
-    profiler_log("AES: Loaded cached decrypted string, hash is $hash");
-    return $aes_decrypt_cache[$hash];
-  }
-  
-  return false;
-}
-
-function aes_decrypt_cache_destroy($hash)
-{
-  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
-  if ( !file_exists($cache_file) )
-    return false;
-  
-  require_once($cache_file);
-  global $aes_decrypt_cache;
-  
-  if ( isset($aes_decrypt_cache[$hash]) )
-    unset($aes_decrypt_cache[$hash]);
-  
-  // call var_export and collect contents
-  ob_start();
-  var_export($aes_decrypt_cache);
-  $dec_cache_string = ob_get_contents();
-  ob_end_clean();
-  $f = @fopen($cache_file, 'w');
-  if ( !$f )
-    return false;
-  fwrite($f, "<?php
-\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
-");
-  fclose($f);
-  return true;
-}
-
-?>
+<?php
+
+/**
+ * Phijndael - an implementation of the AES encryption standard in PHP
+ * Originally written by Fritz Schneider <fritz AT cd DOT ucsd DOT edu>
+ * Ported to PHP by Dan Fuhry <dan AT enano DOT homelinux DOT org>
+ * @package phijndael
+ * @author Fritz Schneider
+ * @author Dan Fuhry
+ * @license BSD-style license
+ */
+
+define ('ENC_BASE64', 202);
+define ('ENC_BINARY', 203);
+
+$_aes_objcache = array();
+
+class AESCrypt {
+  
+  var $debug = false;
+  var $mcrypt = false;
+  var $decrypt_cache = array();
+
+  // Rijndael parameters --  Valid values are 128, 192, or 256
+  
+  var $keySizeInBits = 128;
+  var $blockSizeInBits = 128;
+  
+  ///////  You shouldn't have to modify anything below this line except for
+  ///////  the function getRandomBytes().
+  //
+  // Note: in the following code the two dimensional arrays are indexed as
+  //       you would probably expect, as array[row][column]. The state arrays
+  //       are 2d arrays of the form state[4][Nb].
+  
+  
+  // The number of rounds for the cipher, indexed by [Nk][Nb]
+  var $roundsArray = Array(0,0,0,0,Array(0,0,0,0,10,0, 12,0, 14),0, 
+                               Array(0,0,0,0,12,0, 12,0, 14),0, 
+                               Array(0,0,0,0,14,0, 14,0, 14) );
+  
+  // The number of bytes to shift by in shiftRow, indexed by [Nb][row]
+  var $shiftOffsets = Array(0,0,0,0,Array(0,1, 2, 3),0,Array(0,1, 2, 3),0,Array(0,1, 3, 4) );
+  
+  // The round constants used in subkey expansion
+  var $Rcon = Array( 
+  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 
+  0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 
+  0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 
+  0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 
+  0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 );
+  
+  // Precomputed lookup table for the SBox
+  var $SBox = Array(
+   99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 
+  118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 
+  114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 
+  216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 
+  235,  39, 178, 117,   9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 
+  179,  41, 227,  47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 
+  190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69, 
+  249,   2, 127,  80,  60, 159, 168,  81, 163,  64, 143, 146, 157,  56, 245, 
+  188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,  
+  23,  196, 167, 126,  61, 100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 
+  144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
+    6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
+  141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,  
+   46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62, 
+  181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
+  248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
+  140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  
+   22 );
+  
+  // Precomputed lookup table for the inverse SBox
+  var $SBoxInverse = Array(
+   82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 
+  251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 
+  233, 203,  84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 
+  250, 195,  78,   8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 
+  109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 
+  204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  
+   70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247, 
+  228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2, 
+  193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220, 
+  234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
+   53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29, 
+   41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75, 
+  198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
+   51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
+  127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
+  224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97, 
+   23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
+  125 );
+  
+  function __construct($ks = 128, $bs = 128, $debug = false)
+  {
+    $this->keySizeInBits = $ks;
+    $this->blockSizeInBits = $bs;
+    
+    // Use the Mcrypt library? This speeds things up dramatically.
+    if(defined('MCRYPT_RIJNDAEL_' . $ks) && defined('MCRYPT_ACCEL'))
+    {
+      eval('$mcb = MCRYPT_RIJNDAEL_' . $ks.';');
+      $bks = mcrypt_module_get_algo_block_size($mcb);
+      $bks = $bks * 8;
+      if ( $bks != $bs )
+      {
+        $mcb = false;
+        echo (string)$bks;
+      }
+    }
+    else
+    {
+      $mcb = false;
+    }
+      
+    $this->mcrypt = $mcb;
+    
+    // Cipher parameters ... do not change these
+    $this->Nk = $this->keySizeInBits / 32;
+    $this->Nb = $this->blockSizeInBits / 32;
+    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
+    $this->debug = $debug;
+  }
+  
+  public static function singleton($key_size, $block_size)
+  {
+    static $_aes_objcache;
+    if ( isset($_aes_objcache["$key_size,$block_size"]) )
+    {
+      return $_aes_objcache["$key_size,$block_size"];
+    }
+    
+    $_aes_objcache["$key_size,$block_size"] = new AESCrypt($key_size, $block_size);
+    return $_aes_objcache["$key_size,$block_size"];
+  }
+  
+  // Error handler
+  
+  function trigger_error($text, $level = E_USER_NOTICE)
+  {
+    $bt = debug_backtrace();
+    $lastfunc =& $bt[1];
+    switch($level)
+    {
+      case E_USER_NOTICE:
+      default:
+        $desc = 'Notice';
+        break;
+      case E_USER_WARNING:
+        $desc = 'Warning';
+        break;
+      case E_USER_ERROR:
+        $desc = 'Fatal';
+        break;
+    }
+    ob_start();
+    if($this->debug || $level == E_USER_ERROR) echo "AES encryption: <b>{$desc}:</b> $text in {$lastfunc['file']} on line {$lastfunc['line']} in function {$lastfunc['function']}<br />";
+    if($this->debug)
+    {
+      //echo '<pre>'.enano_debug_print_backtrace(true).'</pre>';
+    }
+    ob_end_flush();
+    if($level == E_USER_ERROR)
+    {
+      echo '<p><b>This can sometimes happen if you are upgrading Enano to a new version and did not log out first.</b> <a href="'.$_SERVER['PHP_SELF'].'?do=diag&amp;sub=cookie_destroy">Click here</a> to force cookies to clear and try again. You will be logged out.</p>';
+      exit;
+    }
+  }
+  
+  function array_slice_js_compat($array, $start, $finish = 0)
+  {
+    $len = $finish - $start;
+    if($len < 0) $len = 0 - $len;
+    //if($this->debug) echo (string)$len . ' ';
+    //if(count($array) < $start + $len)
+    //  $this->trigger_error('Index out of range', E_USER_WARNING);
+    return array_slice($array, $start, $len);
+  }
+  
+  function concat($s1, $s2)
+  {
+    if(is_array($s1) && is_array($s2))
+      return array_merge($s1, $s2);
+    elseif( ( is_array($s1) && !is_array($s2) ) || ( !is_array($s1) && is_array($s2) ) )
+    {
+      $this->trigger_error('incompatible types - you can\'t combine a non-array with an array', E_USER_WARNING);
+      return false;
+    }
+    else
+      return $s1 . $s2;
+  }
+  
+  // This method circularly shifts the array left by the number of elements
+  // given in its parameter. It returns the resulting array and is used for 
+  // the ShiftRow step. Note that shift() and push() could be used for a more 
+  // elegant solution, but they require IE5.5+, so I chose to do it manually. 
+  
+  function cyclicShiftLeft($theArray, $positions) {
+    if(!is_int($positions))
+    {
+      $this->trigger_error('$positions is not an integer! Backtrace:<br /><pre>'.print_r(debug_backtrace(), true).'</pre>', E_USER_WARNING);
+      return false;
+    }
+    $second = array_slice($theArray, 0, $positions);
+    $first = array_slice($theArray, $positions);
+    $theArray = array_merge($first, $second);
+    return $theArray;
+  }
+  
+  // Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
+  
+  function xtime($poly) {
+    $poly <<= 1;
+    return (($poly & 0x100) ? ($poly ^ 0x11B) : ($poly));
+  }
+  
+  // Multiplies the two elements of GF(2^8) together and returns the result.
+  // See the Rijndael spec, but should be straightforward: for each power of
+  // the indeterminant that has a 1 coefficient in x, add y times that power
+  // to the result. x and y should be bytes representing elements of GF(2^8)
+  
+  function mult_GF256($x, $y) {
+    $result = 0;
+    
+    for ($bit = 1; $bit < 256; $bit *= 2, $y = $this->xtime($y)) {
+      if ($x & $bit) 
+        $result ^= $y;
+    }
+    return $result;
+  }
+  
+  // Performs the substitution step of the cipher. State is the 2d array of
+  // state information (see spec) and direction is string indicating whether
+  // we are performing the forward substitution ("encrypt") or inverse 
+  // substitution (anything else)
+  
+  function byteSub(&$state, $direction) {
+    //global $this->SBox, $this->SBoxInverse, $this->Nb;
+    if ($direction == "encrypt")           // Point S to the SBox we're using
+      $S =& $this->SBox;
+    else
+      $S =& $this->SBoxInverse;
+    for ($i = 0; $i < 4; $i++)           // Substitute for every byte in state
+      for ($j = 0; $j < $this->Nb; $j++)
+         $state[$i][$j] = $S[$state[$i][$j]];
+  }
+  
+  // Performs the row shifting step of the cipher.
+  
+  function shiftRow(&$state, $direction) {
+    //global $this->Nb, $this->shiftOffsets;
+    for ($i=1; $i<4; $i++)               // Row 0 never shifts
+      if ($direction == "encrypt")
+         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->shiftOffsets[$this->Nb][$i]);
+      else
+         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->Nb - $this->shiftOffsets[$this->Nb][$i]);
+  
+  }
+  
+  // Performs the column mixing step of the cipher. Most of these steps can
+  // be combined into table lookups on 32bit values (at least for encryption)
+  // to greatly increase the speed. 
+  
+  function mixColumn(&$state, $direction) {
+    //global $this->Nb;
+    $b = Array();                                  // Result of matrix multiplications
+    for ($j = 0; $j < $this->Nb; $j++) {                 // Go through each column...
+      for ($i = 0; $i < 4; $i++) {                 // and for each row in the column...
+        if ($direction == "encrypt")
+          $b[$i] = $this->mult_GF256($state[$i][$j], 2) ^ // perform mixing
+                   $this->mult_GF256($state[($i+1)%4][$j], 3) ^ 
+                   $state[($i+2)%4][$j] ^ 
+                   $state[($i+3)%4][$j];
+        else 
+          $b[$i] = $this->mult_GF256($state[$i][$j], 0xE) ^ 
+                   $this->mult_GF256($state[($i+1)%4][$j], 0xB) ^
+                   $this->mult_GF256($state[($i+2)%4][$j], 0xD) ^
+                   $this->mult_GF256($state[($i+3)%4][$j], 9);
+      }
+      for ($i = 0; $i < 4; $i++)          // Place result back into column
+        $state[$i][$j] = $b[$i];
+    }
+  }
+  
+  // Adds the current round key to the state information. Straightforward.
+  
+  function addRoundKey(&$state, $roundKey) {
+    //global $this->Nb;
+    for ($j = 0; $j < $this->Nb; $j++) {                      // Step through columns...
+      $state[0][$j] ^= ( $roundKey[$j] & 0xFF);         // and XOR
+      $state[1][$j] ^= (($roundKey[$j]>>8) & 0xFF);
+      $state[2][$j] ^= (($roundKey[$j]>>16) & 0xFF);
+      $state[3][$j] ^= (($roundKey[$j]>>24) & 0xFF);
+    }
+  }
+  
+  // This function creates the expanded key from the input (128/192/256-bit)
+  // key. The parameter key is an array of bytes holding the value of the key.
+  // The returned value is an array whose elements are the 32-bit words that 
+  // make up the expanded key.
+  
+  function keyExpansion($key) {
+    //global $this->keySizeInBits, $this->blockSizeInBits, $this->roundsArray, $this->Nk, $this->Nb, $this->Nr, $this->Nk, $this->SBox, $this->Rcon;
+    $expandedKey = Array();
+  
+    // in case the key size or parameters were changed...
+    $this->Nk = $this->keySizeInBits / 32;                   
+    $this->Nb = $this->blockSizeInBits / 32;
+    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
+  
+    for ($j=0; $j < $this->Nk; $j++)     // Fill in input key first
+      $expandedKey[$j] = 
+        ($key[4*$j]) | ($key[4*$j+1]<<8) | ($key[4*$j+2]<<16) | ($key[4*$j+3]<<24);
+  
+    // Now walk down the rest of the array filling in expanded key bytes as
+    // per Rijndael's spec
+    for ($j = $this->Nk; $j < $this->Nb * ($this->Nr + 1); $j++) {    // For each word of expanded key
+      $temp = $expandedKey[$j - 1];
+      if ($j % $this->Nk == 0) 
+        $temp = ( ($this->SBox[($temp>>8) & 0xFF]) |
+                  ($this->SBox[($temp>>16) & 0xFF]<<8) |
+                  ($this->SBox[($temp>>24) & 0xFF]<<16) |
+                  ($this->SBox[$temp & 0xFF]<<24) ) ^ $this->Rcon[floor($j / $this->Nk) - 1];
+      elseif  ($this->Nk > 6 && $j % $this->Nk == 4)
+        $temp = ($this->SBox[($temp>>24) & 0xFF]<<24) |
+               ($this->SBox[($temp>>16) & 0xFF]<<16) |
+               ($this->SBox[($temp>>8) & 0xFF]<<8) |
+               ($this->SBox[ $temp & 0xFF]);
+      $expandedKey[$j] = $expandedKey[$j-$this->Nk] ^ $temp;
+    }
+    return $expandedKey;
+  }
+  
+  // Rijndael's round functions... 
+  
+  function RijndaelRound(&$state, $roundKey) {
+    $this->byteSub($state, "encrypt");
+    $this->shiftRow($state, "encrypt");
+    $this->mixColumn($state, "encrypt");
+    $this->addRoundKey($state, $roundKey);
+  }
+  
+  function InverseRijndaelRound(&$state, $roundKey) {
+    $this->addRoundKey($state, $roundKey);
+    $this->mixColumn($state, "decrypt");
+    $this->shiftRow($state, "decrypt");
+    $this->byteSub($state, "decrypt");
+  }
+  
+  function FinalRijndaelRound(&$state, $roundKey) {
+    $this->byteSub($state, "encrypt");
+    $this->shiftRow($state, "encrypt");
+    $this->addRoundKey($state, $roundKey);
+  }
+  
+  function InverseFinalRijndaelRound(&$state, $roundKey){
+    $this->addRoundKey($state, $roundKey);
+    $this->shiftRow($state, "decrypt");
+    $this->byteSub($state, "decrypt");  
+  }
+  
+  // encrypt is the basic encryption function. It takes parameters
+  // block, an array of bytes representing a plaintext block, and expandedKey,
+  // an array of words representing the expanded key previously returned by
+  // keyExpansion(). The ciphertext block is returned as an array of bytes.
+  
+  function cryptBlock($block, $expandedKey) {
+    //global $this->blockSizeInBits, $this->Nb, $this->Nr;
+    $t=count($block)*8;
+    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
+    {
+      $this->trigger_error('block is bad or block size is wrong<pre>'.print_r($block, true).'</pre><p>Aiming for size '.$this->blockSizeInBits.', got '.$t.'.', E_USER_WARNING); 
+      return false;
+    }
+    if (!$expandedKey)
+      return;
+  
+    $block = $this->packBytes($block);
+    $this->addRoundKey($block, $expandedKey);
+    for ($i=1; $i<$this->Nr; $i++) 
+      $this->RijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
+    $this->FinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr));
+    $ret = $this->unpackBytes($block);
+    return $ret;
+  }
+  
+  // decrypt is the basic decryption function. It takes parameters
+  // block, an array of bytes representing a ciphertext block, and expandedKey,
+  // an array of words representing the expanded key previously returned by
+  // keyExpansion(). The decrypted block is returned as an array of bytes.
+  
+  function unCryptBlock($block, $expandedKey) {
+    $t = count($block)*8;
+    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
+    {
+      $this->trigger_error('$block is not a valid rijndael-block array: '.$this->byteArrayToHex($block).'<pre>'.print_r($block, true).'</pre><p>Block size is '.$t.', should be '.$this->blockSizeInBits.'</p>', E_USER_WARNING);
+      return false;
+    }
+    if (!$expandedKey)
+    {
+      $this->trigger_error('$expandedKey is invalid', E_USER_WARNING);
+      return false;
+    }
+  
+    $block = $this->packBytes($block);
+    $this->InverseFinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr)); 
+    for ($i = $this->Nr - 1; $i>0; $i--) 
+    {
+      $this->InverseRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
+    }
+    $this->addRoundKey($block, $expandedKey);
+    $ret = $this->unpackBytes($block);
+    if(!is_array($ret))
+    {
+      $this->trigger_error('$ret is not an array', E_USER_WARNING);
+    }
+    return $ret;
+  }
+  
+  // This method takes a byte array (byteArray) and converts it to a string by
+  // applying String.fromCharCode() to each value and concatenating the result.
+  // The resulting string is returned. Note that this function SKIPS zero bytes
+  // under the assumption that they are padding added in formatPlaintext().
+  // Obviously, do not invoke this method on raw data that can contain zero
+  // bytes. It is really only appropriate for printable ASCII/Latin-1 
+  // values. Roll your own function for more robust functionality :)
+  
+  function byteArrayToString($byteArray) {
+    $result = "";
+    for($i=0; $i<count($byteArray); $i++)
+      if ($byteArray[$i] != 0) 
+        $result .= chr($byteArray[$i]);
+    return $result;
+  }
+  
+  // This function takes an array of bytes (byteArray) and converts them
+  // to a hexadecimal string. Array element 0 is found at the beginning of 
+  // the resulting string, high nibble first. Consecutive elements follow
+  // similarly, for example [16, 255] --> "10ff". The function returns a 
+  // string.
+  
+  /*
+  function byteArrayToHex($byteArray) {
+    $result = "";
+    if (!$byteArray)
+      return;
+    for ($i=0; $i<count($byteArray); $i++)
+      $result .= (($byteArray[$i]<16) ? "0" : "") + toString($byteArray[$i]); // magic number here is 16, not sure how to handle this...
+  
+    return $result;
+  }
+  */
+  function byteArrayToHex($arr)
+  {
+    $ret = '';
+    foreach($arr as $a)
+    {
+      $nibble = (string)dechex(intval($a));
+      if(strlen($nibble) == 1) $nibble = '0' . $nibble;
+      $ret .= $nibble;
+    }
+    return $ret;
+  }
+  
+  // PHP equivalent of Javascript's toString()
+  function toString($bool)
+  {
+    if(is_bool($bool))
+      return ($bool) ? 'true' : 'false';
+    elseif(is_array($bool))
+      return implode(',', $bool);
+    else
+      return (string)$bool;
+  }
+  
+  // This function converts a string containing hexadecimal digits to an 
+  // array of bytes. The resulting byte array is filled in the order the
+  // values occur in the string, for example "10FF" --> [16, 255]. This
+  // function returns an array. 
+  
+  /*
+  function hexToByteArray($hexString) {
+    $byteArray = Array();
+    if (strlen($hexString) % 2)             // must have even length
+      return;
+    if (strstr($hexString, "0x") == $hexString || strstr($hexString, "0X") == $hexString)
+      $hexString = substr($hexString, 2);
+    for ($i = 0; $i<strlen($hexString); $i++,$i++) 
+      $byteArray[floor($i/2)] = intval(substr($hexString, $i, 2)); // again, that strange magic number: 16
+    return $byteArray;
+  }
+  */
+  function hexToByteArray($str)
+  {
+    if(substr($str, 0, 2) == '0x' || substr($str, 0, 2) == '0X')
+      $str = substr($str, 2);
+    $arr = Array();
+    $str = $this->enano_str_split($str, 2);
+    foreach($str as $s)
+    {
+      $arr[] = intval(hexdec($s));
+    }
+    return $arr;
+  }
+  
+  // This function packs an array of bytes into the four row form defined by
+  // Rijndael. It assumes the length of the array of bytes is divisible by
+  // four. Bytes are filled in according to the Rijndael spec (starting with
+  // column 0, row 0 to 3). This function returns a 2d array.
+  
+  function packBytes($octets) {
+    $state = Array();
+    if (!$octets || count($octets) % 4)
+      return;
+  
+    $state[0] = Array(); $state[1] = Array(); 
+    $state[2] = Array(); $state[3] = Array();
+    for ($j=0; $j<count($octets); $j = $j+4) {
+       $state[0][$j/4] = $octets[$j];
+       $state[1][$j/4] = $octets[$j+1];
+       $state[2][$j/4] = $octets[$j+2];
+       $state[3][$j/4] = $octets[$j+3];
+    }
+    return $state;
+  }
+  
+  // This function unpacks an array of bytes from the four row format preferred
+  // by Rijndael into a single 1d array of bytes. It assumes the input "packed"
+  // is a packed array. Bytes are filled in according to the Rijndael spec. 
+  // This function returns a 1d array of bytes.
+  
+  function unpackBytes($packed) {
+    $result = Array();
+    for ($j=0; $j<count($packed[0]); $j++) {
+      $result[] = $packed[0][$j];
+      $result[] = $packed[1][$j];
+      $result[] = $packed[2][$j];
+      $result[] = $packed[3][$j];
+    }
+    return $result;
+  }
+  
+  function charCodeAt($str, $i)
+  {
+    return ord(substr($str, $i, 1));
+  }
+  
+  function fromCharCode($str)
+  {
+    return chr($str);
+  }
+  
+  // This function takes a prospective plaintext (string or array of bytes)
+  // and pads it with zero bytes if its length is not a multiple of the block 
+  // size. If plaintext is a string, it is converted to an array of bytes
+  // in the process. The type checking can be made much nicer using the 
+  // instanceof operator, but this operator is not available until IE5.0 so I 
+  // chose to use the heuristic below. 
+  
+  function formatPlaintext($plaintext) {
+    //global $this->blockSizeInBits;
+    $bpb = $this->blockSizeInBits / 8;               // bytes per block
+  
+    // if primitive string or String instance
+    if (is_string($plaintext)) {
+      $plaintext = $this->enano_str_split($plaintext);
+      // Unicode issues here (ignoring high byte)
+      for ($i=0; $i<sizeof($plaintext); $i++)
+        $plaintext[$i] = $this->charCodeAt($plaintext[$i], 0) & 0xFF;
+    } 
+  
+    for ($i = $bpb - (sizeof($plaintext) % $bpb); $i > 0 && $i < $bpb; $i--) 
+      $plaintext[] = 0;
+    
+    return $plaintext;
+  }
+  
+  // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
+  // TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
+  // APPLICATION. (edit: done, mt_rand() is relatively secure)
+  
+  function getRandomBytes($howMany) {
+    $bytes = Array();
+    for ($i=0; $i<$howMany; $i++)
+      $bytes[$i] = mt_rand(0, 255);
+    return $bytes;
+  }
+  
+  // rijndaelEncrypt(plaintext, key, mode)
+  // Encrypts the plaintext using the given key and in the given mode. 
+  // The parameter "plaintext" can either be a string or an array of bytes. 
+  // The parameter "key" must be an array of key bytes. If you have a hex 
+  // string representing the key, invoke hexToByteArray() on it to convert it 
+  // to an array of bytes. The third parameter "mode" is a string indicating
+  // the encryption mode to use, either "ECB" or "CBC". If the parameter is
+  // omitted, ECB is assumed.
+  // 
+  // An array of bytes representing the cihpertext is returned. To convert 
+  // this array to hex, invoke byteArrayToHex() on it. If you are using this 
+  // "for real" it is a good idea to change the function getRandomBytes() to 
+  // something that returns truly random bits.
+  
+  function rijndaelEncrypt($plaintext, $key, $mode = 'ECB') {
+    //global $this->blockSizeInBits, $this->keySizeInBits;
+    $bpb = $this->blockSizeInBits / 8;          // bytes per block
+    // var ct;                                 // ciphertext
+  
+    if($mode == 'CBC')
+    {
+      if (!is_string($plaintext) || !is_array($key))
+      {
+        $this->trigger_error('In CBC mode the first and second parameters should be strings', E_USER_WARNING);
+        return false;
+      }
+    } else {
+      if (!is_array($plaintext) || !is_array($key))
+      {
+        $this->trigger_error('In ECB mode the first and second parameters should be byte arrays', E_USER_WARNING);
+        return false;
+      }
+    }
+    if (sizeof($key)*8 != $this->keySizeInBits)
+    {
+      $this->trigger_error('The key needs to be '. ( $this->keySizeInBits / 8 ) .' bytes in length', E_USER_WARNING);
+      return false;
+    }
+    if ($mode == "CBC")
+      $ct = $this->getRandomBytes($bpb);             // get IV
+    else {
+      $mode = "ECB";
+      $ct = Array();
+    }
+    
+    // convert plaintext to byte array and pad with zeros if necessary. 
+    $plaintext = $this->formatPlaintext($plaintext);
+    
+    $expandedKey = $this->keyExpansion($key);
+    
+    for ($block=0; $block<sizeof($plaintext) / $bpb; $block++) {
+      $aBlock = $this->array_slice_js_compat($plaintext, $block*$bpb, ($block+1)*$bpb);
+      if ($mode == "CBC")
+      {
+        for ($i=0; $i<$bpb; $i++)
+        {
+          $aBlock[$i] ^= $ct[$block*$bpb + $i];
+        }
+      }
+      $cp = $this->cryptBlock($aBlock, $expandedKey);
+      $ct = $this->concat($ct, $cp);
+    }
+  
+    return $ct;
+  }
+  
+  // rijndaelDecrypt(ciphertext, key, mode)
+  // Decrypts the using the given key and mode. The parameter "ciphertext" 
+  // must be an array of bytes. The parameter "key" must be an array of key 
+  // bytes. If you have a hex string representing the ciphertext or key, 
+  // invoke hexToByteArray() on it to convert it to an array of bytes. The
+  // parameter "mode" is a string, either "CBC" or "ECB".
+  // 
+  // An array of bytes representing the plaintext is returned. To convert 
+  // this array to a hex string, invoke byteArrayToHex() on it. To convert it 
+  // to a string of characters, you can use byteArrayToString().
+  
+  function rijndaelDecrypt($ciphertext, $key, $mode = 'ECB') {
+    //global $this->blockSizeInBits, $this->keySizeInBits;
+    $bpb = $this->blockSizeInBits / 8;          // bytes per block
+    $pt = Array();                   // plaintext array
+    // $aBlock;                             // a decrypted block
+    // $block;                              // current block number
+  
+    if (!$ciphertext)
+    {
+      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if(  !is_array($key) )
+    {
+      $this->trigger_error('$key should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if( is_string($ciphertext) )
+    {
+      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if (sizeof($key)*8 != $this->keySizeInBits)
+    {
+      $this->trigger_error('Encryption key is the wrong length', E_USER_WARNING);
+      return false;
+    }
+    if (!$mode)
+      $mode = "ECB";                         // assume ECB if mode omitted
+  
+    $expandedKey = $this->keyExpansion($key);
+   
+    // work backwards to accomodate CBC mode 
+    for ($block=(sizeof($ciphertext) / $bpb)-1; $block>0; $block--)
+    {
+      if( ( $block*$bpb ) + ( ($block+1)*$bpb ) > count($ciphertext) )
+      {
+        //$this->trigger_error('$ciphertext index out of bounds', E_USER_ERROR);
+      }
+      $current_block = $this->array_slice_js_compat($ciphertext, $block*$bpb, ($block+1)*$bpb);
+      if(count($current_block) * 8 != $this->blockSizeInBits)
+      {
+        // $c=count($current_block)*8;
+        // $this->trigger_error('We got a '.$c.'-bit block, instead of '.$this->blockSizeInBits.'', E_USER_ERROR);
+      }
+      $aBlock = $this->uncryptBlock($current_block, $expandedKey);
+      if(!$aBlock)
+      {
+        $this->trigger_error('Shared block decryption routine returned false', E_USER_WARNING);
+        return false;
+      }
+      if ($mode == "CBC")
+        for ($i=0; $i<$bpb; $i++) 
+          $pt[($block-1)*$bpb + $i] = $aBlock[$i] ^ $ciphertext[($block-1)*$bpb + $i];
+      else
+        $pt = $this->concat($aBlock, $pt);
+    }
+  
+    // do last block if ECB (skips the IV in CBC)
+    if ($mode == "ECB")
+    {
+      $x = $this->uncryptBlock($this->array_slice_js_compat($ciphertext, 0, $bpb), $expandedKey);
+      if(!$x)
+      {
+        $this->trigger_error('ECB block decryption routine returned false', E_USER_WARNING);
+        return false;
+      }
+      $pt = $this->concat($x, $pt);
+      if(!$pt)
+      {
+        $this->trigger_error('ECB concatenation routine returned false', E_USER_WARNING);
+        return false;
+      }
+    }
+  
+    return $pt;
+  }
+  
+  /**
+   * Wrapper for encryption.
+   * @param string $text the text to encrypt
+   * @param string $key the raw binary key to encrypt with
+   * @param int $return_encoding optional - can be ENC_BINARY, ENC_HEX or ENC_BASE64
+   */
+   
+  function encrypt($text, $key, $return_encoding = ENC_HEX)
+  {
+    if ( $text == '' )
+      return '';
+    if ( $this->mcrypt && $this->blockSizeInBits == mcrypt_module_get_algo_block_size(eval('return MCRYPT_RIJNDAEL_'.$this->keySizeInBits.';')) )
+    {
+      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
+      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+      $cryptext = mcrypt_encrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
+      switch($return_encoding)
+      {
+        case ENC_HEX:
+        default:
+          $cryptext = $this->strtohex($cryptext);
+          break;
+        case ENC_BINARY:
+          $cryptext = $cryptext;
+          break;
+        case ENC_BASE64:
+          $cryptext = base64_encode($cryptext);
+          break;
+      }
+    }
+    else
+    {
+      $key = $this->prepare_string($key);
+      $text = $this->prepare_string($text);
+      profiler_log('AES: Started encryption of a string');
+      $cryptext = $this->rijndaelEncrypt($text, $key, 'ECB');
+      profiler_log('AES: Finished encryption of a string');
+      if(!is_array($cryptext))
+      {
+        echo 'Warning: encryption failed for string: '.print_r($text,true).'<br />';
+        return false;
+      }
+      switch($return_encoding)
+      {
+        case ENC_HEX:
+        default:
+          $cryptext = $this->byteArrayToHex($cryptext);
+          break;
+        case ENC_BINARY:
+          $cryptext = $this->byteArrayToString($cryptext);
+          break;
+        case ENC_BASE64:
+          $cryptext = base64_encode($this->byteArrayToString($cryptext));
+          break;
+      }
+    }
+    return $cryptext;
+  }
+  
+  /**
+   * Wrapper for decryption.
+   * @param string $text the encrypted text
+   * @param string $key the raw binary key used to encrypt the text
+   * @param int $input_encoding the encoding used for the encrypted string. Can be ENC_BINARY, ENC_HEX, or ENC_BASE64.
+   * @return string
+   */
+   
+  function decrypt($text, $key, $input_encoding = ENC_HEX)
+  {
+    if ( $text == '' )
+      return '';
+    
+    switch($input_encoding)
+    {
+      case ENC_BINARY:
+      default:
+        break;
+      case ENC_HEX:
+        $text = $this->hextostring($text);
+        break;
+      case ENC_BASE64:
+        $text = base64_decode($text);
+        break;
+    }
+    
+    // Run memory-cache check
+    if ( isset($this->decrypt_cache[$key]) && is_array($this->decrypt_cache[$key]) )
+    {
+      if ( isset($this->decrypt_cache[$key][$text]) )
+      {
+        return $this->decrypt_cache[$key][$text];
+      }
+    }
+    
+    // Run disk-cache check
+    $hash = sha1($text . '::' . $key);
+    if ( $dypt = aes_decrypt_cache_fetch($hash) )
+      return $dypt;
+    
+    $text_bin = $text;
+    $key_bin = $key;
+    
+    if ( $this->mcrypt )
+    {
+      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
+      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+      $dypt = mcrypt_decrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
+    }
+    else
+    {
+      $etext = $this->prepare_string($text);
+      $ekey  = $this->prepare_string($key);
+      $mod = count($etext) % $this->blockSizeInBits;
+      profiler_log('AES: Started decryption of a string');
+      $dypt = $this->rijndaelDecrypt($etext, $ekey, 'ECB');
+      profiler_log('AES: Finished decryption of a string');
+      if(!$dypt)
+      {
+        echo '<pre>'.print_r($dypt, true).'</pre>';
+        $this->trigger_error('Rijndael main decryption routine failed', E_USER_ERROR);
+      }
+      $dypt = $this->byteArrayToString($dypt);
+    }
+    if ( !isset($this->decrypt_cache[$key_bin]) )
+      $this->decrypt_cache[$key_bin] = array();
+    
+    $this->decrypt_cache[$key_bin][$text_bin] = $dypt;
+    
+    aes_decrypt_cache_store($text_bin, $dypt, $key_bin);
+    
+    return $dypt;
+  }
+  
+  /**
+   * Enano-ese equivalent of str_split() which is only found in PHP5
+   * @param $text string the text to split
+   * @param $inc int size of each block
+   * @return array
+   */
+   
+  function enano_str_split($text, $inc = 1)
+  {
+    if($inc < 1) return false;
+    if($inc >= strlen($text)) return Array($text);
+    $len = ceil(strlen($text) / $inc);
+    $ret = Array();
+    for($i=0;$i<strlen($text);$i=$i+$inc)
+    {
+      $ret[] = substr($text, $i, $inc);
+    }
+    return $ret;
+  }
+  
+  /**
+   * Generates a random key suitable for encryption
+   * @param int $len the length of the key, in bytes
+   * @return string a BINARY key
+   */
+  
+  function randkey($len = 32)
+  {
+    $key = '';
+    for($i=0;$i<$len;$i++)
+    {
+      $key .= chr(mt_rand(0, 255));
+    }
+    if ( file_exists('/dev/urandom') && is_readable('/dev/urandom') )
+    {
+      // Let's use something a little more secure
+      $ur = @fopen('/dev/urandom', 'r');
+      if ( !$ur )
+        return $key;
+      $ukey = @fread($ur, $len);
+      fclose($ur);
+      if ( strlen($ukey) != $len )
+        return $key;
+      return $ukey;
+    }
+    return $key;
+  }
+  
+  /*
+  function byteArrayToString($arr)
+  {
+    if(!is_array($arr))
+    {
+      $this->trigger_error('First parameter should be an array', E_USER_WARNING);
+      return false;
+    }
+    $ret = '';
+    foreach($arr as $a)
+    {
+      if($a != 0) $ret .= chr($a);
+    }
+    return $ret;
+  }
+  */
+  
+  function strtohex($str)
+  {
+    $str = $this->enano_str_split($str);
+    $ret = '';
+    foreach($str as $s)
+    {
+      $chr = dechex(ord($s));
+      if(strlen($chr) < 2) $chr = '0' . $chr;
+      $ret .= $chr;
+    }
+    return $ret;
+  }
+  
+  function gen_readymade_key()
+  {
+    $key = $this->strtohex($this->randkey($this->keySizeInBits / 8));
+    return $key;
+  }
+  
+  function prepare_string($text)
+  {
+    $ret = $this->hexToByteArray($this->strtohex($text));
+    if(count($ret) != strlen($text))
+    {
+      die('Could not convert string "' . $text . '" to hex byte array for encryption');
+    }
+    return $ret;
+  }
+  
+  /**
+   * Decodes a hex string.
+   * @param string $hex The hex code to decode
+   * @return string
+   */
+  
+  function hextostring($hex)
+  {
+    $hex = $this->enano_str_split($hex, 2);
+    $bin_key = '';
+    foreach($hex as $nibble)
+    {
+      $byte = chr(hexdec($nibble));
+      $bin_key .= $byte;
+    }
+    return $bin_key;
+  }
+}
+
+function aes_decrypt_cache_store($encrypted, $decrypted, $key)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  // only cache if $decrypted is long enough to actually warrant caching
+  if ( strlen($decrypted) < 32 )
+  {
+    profiler_log("AES: Skipped caching a string (probably a password, we dunno) because it's too short");
+    return false;
+  }
+  if ( file_exists($cache_file) )
+  {
+    require_once($cache_file);
+    global $aes_decrypt_cache;
+    $cachekey = sha1($encrypted . '::' . $key);
+    $aes_decrypt_cache[$cachekey] = $decrypted;
+    
+    if ( count($aes_decrypt_cache) > 5000 )
+    {
+      // we've got a lot of strings in the cache, clear out a few
+      $keys = array_keys($aes_decrypt_cache);
+      for ( $i = 0; $i < 2500; $i++ )
+      {
+        unset($aes_decrypt_cache[$keys[$i]]);
+        unset($aes_decrypt_cache[$keys[$i]]);
+      }
+    }
+  }
+  else
+  {
+    $aes_decrypt_cache = array(
+      sha1($encrypted . '::' . $key) => $decrypted
+    );
+  }
+  // call var_export and collect contents
+  ob_start();
+  var_export($aes_decrypt_cache);
+  $dec_cache_string = ob_get_contents();
+  ob_end_clean();
+  $f = @fopen($cache_file, 'w');
+  if ( !$f )
+    return false;
+  fwrite($f, "<?php
+\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
+");
+  fclose($f);
+  return true;
+}
+
+function aes_decrypt_cache_fetch($hash)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  if ( !file_exists($cache_file) )
+    return false;
+  
+  require_once($cache_file);
+  global $aes_decrypt_cache;
+  if ( isset($aes_decrypt_cache[$hash]) )
+  {
+    profiler_log("AES: Loaded cached decrypted string, hash is $hash");
+    return $aes_decrypt_cache[$hash];
+  }
+  
+  return false;
+}
+
+function aes_decrypt_cache_destroy($hash)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  if ( !file_exists($cache_file) )
+    return false;
+  
+  require_once($cache_file);
+  global $aes_decrypt_cache;
+  
+  if ( isset($aes_decrypt_cache[$hash]) )
+    unset($aes_decrypt_cache[$hash]);
+  
+  // call var_export and collect contents
+  ob_start();
+  var_export($aes_decrypt_cache);
+  $dec_cache_string = ob_get_contents();
+  ob_end_clean();
+  $f = @fopen($cache_file, 'w');
+  if ( !$f )
+    return false;
+  fwrite($f, "<?php
+\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
+");
+  fclose($f);
+  return true;
+}
+
+?>
--- a/includes/sessions.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/sessions.php	Fri Feb 22 12:51:53 2008 -0500
@@ -1906,7 +1906,6 @@
         'username' => $u
       ));
       
-    error_reporting(E_ALL);
     if(getConfig('smtp_enabled') == '1')
     {
       $result = smtp_send_email($r['email'], $lang->get('user_reg_activation_email_subject'), preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
@@ -1960,7 +1959,6 @@
         )
       );
     
-    error_reporting(E_ALL);
     
     if(getConfig('smtp_enabled') == '1')
     {
--- a/includes/wikiengine/Tables.php	Fri Feb 22 12:48:57 2008 -0500
+++ b/includes/wikiengine/Tables.php	Fri Feb 22 12:51:53 2008 -0500
@@ -280,11 +280,24 @@
     
     // In Enano 1.0.3, added this cheapo hack to keep ampersands
     // from being double-sanitized. Thanks to markybob from #deluge.
+    
+    // htmlspecialchars() the "manual" way
     $encValue = strtr( $text, array(
-      '&amp;' => '&'
+      '&amp;'  => '&',
+      '&quot;' => '"',
+      '&lt;'   => '<',
+      '&gt;'   => '>',
+      '&#039;' => "'"
     ) );
     
-		$encValue = htmlspecialchars( $text );
+    $encValue = strtr( $text, array(
+      '&' => '&amp;',
+      '"' => '&quot;',
+      '<' => '&lt;',
+      '>' => '&gt;',
+      "'" => '&#039;'
+    ) );
+    
 		
 		// Whitespace is normalized during attribute decoding,
 		// so if we've been passed non-spaces we must encode them
--- a/licenses/cc-by-2.0.html	Fri Feb 22 12:48:57 2008 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml111.dtd">
-<html>
-<head>
-<title>Creative Commons Attribution 2.0 License</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<style type="text/css">
-body {
-  margin: 0;
-  padding: 0;
-  background-color: #FFFFFF;
-  color: #000000;
-}
-body div.main {
-  border: 1px solid #cccccc;
-  background-color: #F1F3F5;
-  margin: 10px;
-  padding: 10px;
-}
-* {
- font-family: verdana, tahoma, arial, helvetica, sans-serif;
- font-size: 8pt;
-}
-p {
-  margin-left: 1.5em;
-}
-h1, h2, h3 {
-  color: #50A0D0;
-  font-weight: normal;
-  font-family: 'trebuchet ms', verdana, tahoma, arial, helvetica, sans-serif;
-}
-h1 {
-  font-size: 16pt;
-}
-h2 {
-  font-size: 12pt;
-  margin-left: 0.5em;
-}
-h3 {
-  font-size: 10pt;
-  margin-left: 1em;
-}
-a:link, a:visited, a:active {
-  color: #3080B0;
-  text-decoration: none;
-  border-bottom: 1px dotted #50A0D0;
-}
-a:hover {
-  color: #50A0D0;
-  border-bottom: 1px solid #50A0D0;
-}
-pre {
-  font-family: 'courier new', monospace;
-  background-color: #F8F8F8;
-  margin: 10px 10px 10px 30px;
-  max-height: 150px;
-  clip: rect(0px,auto,auto,0px);
-  overflow: auto;
-  padding: 10px;
-  border: 1px solid #3060B0;
-}
-ul li {
-  list-style-type: square;
-}
-div.copyright {
-  text-align: right;
-  font-size: smaller;
-}
-div.copyright * {
-  font-size: smaller;
-}
-</style>
-</head>
-<body>
-
-<div class="main">
-
-<h1>Creative Commons Attribution 2.0 License</h1>
-
-<!-- BEGIN LICENSE TEXT -->
-
-<p>THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. </p>
-
-<p>BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. </p>
-
-
-<p><strong>1. Definitions</strong> </p>
-
-<ol type="a">
-
-<li>
-<strong>"Collective Work"</strong> means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
-</li>
-
-<li>
-<strong>"Derivative Work"</strong> means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.</li>
-
-<li>
-<strong>"Licensor"</strong> means the individual or entity that offers the Work under the terms of this License.
-</li>
-
-<li>
-<strong>"Original Author"</strong> means the individual or entity who created the Work.
-</li>
-
-<li>
-<strong>"Work"</strong> means the copyrightable work of authorship offered under the terms of this License.
-</li>
-
-<li>
-<strong>"You"</strong> means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
-
-</li>
-</ol>
-
-<p><strong>2. Fair Use Rights.</strong> Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws. </p>
-
-
-<p><strong>3. License Grant.</strong> Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: </p>
-
-
-<ol type="a">
-<li>
-
-to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
-</li>
-
-<li>
-to create and reproduce Derivative Works;
-</li>
-
-<li>
-to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
-
-</li>
-
-<li>
-to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
-</li>
-
-<li><p>For the avoidance of doubt, where the work is a musical composition:</p>
-
-<ol type="i">
-<li><strong>Performance Royalties Under Blanket Licenses</strong>. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.</li>
-
-<li><strong>Mechanical Rights and Statutory Royalties</strong>. Licensor waives the exclusive right to collect, whether individually or via a music rights agency or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).</li></ol></li>
-
-<li><strong>Webcasting Rights and Statutory Royalties</strong>. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).</li>
-
-</ol>
-
-
-<p>The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.</p>
-
-<p><strong>4. Restrictions.</strong>The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: </p>
-
-
-<ol type="a">
-<li>
-You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any reference to such Licensor or the Original Author, as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any reference to such Licensor or the Original Author, as requested.
-</li>
-
-
-<li>
-If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and give the Original Author credit reasonable to the medium or means You are utilizing by conveying the name (or pseudonym if applicable) of the Original Author if supplied; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
-</li>
-
-</ol>
-
-<p><strong>5. Representations, Warranties and Disclaimer</strong></p>
-
-<p>UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.</p>
-
-
-<p><strong>6. Limitation on Liability.</strong> EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </p>
-
-<p><strong>7. Termination</strong> </p>
-
-<ol type="a">
-
-<li>
-This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
-</li>
-
-<li>
-Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
-</li>
-</ol>
-
-<p><strong>8. Miscellaneous</strong> </p>
-
-<ol type="a">
-
-<li>
-Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
-</li>
-
-<li>
-Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
-</li>
-
-<li>
-If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-</li>
-
-<li>
-No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
-
-</li>
-
-<li>
-This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
-</li>
-</ol>
-
-<!-- END LICENSE TEXT -->
-
-<div class="copyright">valid <a href="http://validator.w3.org/check/referer">xhtml</a> and <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">css</a>&nbsp;&nbsp;|&nbsp;&nbsp;design by <a href="http://enano.homelinux.org/User:dandaman32">dan fuhry</a> and <a href="http://www.fusionnerd.com/">manoj maddali</a></div>
-
-</div>
-
-</body>
-</html>