text: /*
  CryptoJS v3.1.2
  code.google.com/p/crypto-js
  (c) 2009-2013 by Jeff Mott. All rights reserved.
  code.google.com/p/crypto-js/wiki/License
  */
  /**
   * CryptoJS core components.
   */
   var CryptoJS = CryptoJS || (function (Math, undefined) {
      /**
       * CryptoJS namespace.
       */
      var C = {};
  
      /**
       * Library namespace.
       */
      var C_lib = C.lib = {};
  
      /**
       * Base object for prototypal inheritance.
       */
      var Base = C_lib.Base = (function () {
          function F() {}
  
          return {
              /**
               * Creates a new object that inherits from this object.
               *
               * @param {Object} overrides Properties to copy into the new object.
               *
               * @return {Object} The new object.
               *
               * @static
               *
               * @example
               *
               *     var MyType = CryptoJS.lib.Base.extend({
               *         field: 'value',
               *
               *         method: function () {
               *         }
               *     });
               */
              extend: function (overrides) {
                  // Spawn
                  F.prototype = this;
                  var subtype = new F();
  
                  // Augment
                  if (overrides) {
                      subtype.mixIn(overrides);
                  }
  
                  // Create default initializer
                  if (!subtype.hasOwnProperty('init')) {
                      subtype.init = function () {
                          subtype.$super.init.apply(this, arguments);
                      };
                  }
  
                  // Initializer's prototype is the subtype object
                  subtype.init.prototype = subtype;
  
                  // Reference supertype
                  subtype.$super = this;
  
                  return subtype;
              },
  
              /**
               * Extends this object and runs the init method.
               * Arguments to create() will be passed to init().
               *
               * @return {Object} The new object.
               *
               * @static
               *
               * @example
               *
               *     var instance = MyType.create();
               */
              create: function () {
                  var instance = this.extend();
                  instance.init.apply(instance, arguments);
  
                  return instance;
              },
  
              /**
               * Initializes a newly created object.
               * Override this method to add some logic when your objects are created.
               *
               * @example
               *
               *     var MyType = CryptoJS.lib.Base.extend({
               *         init: function () {
               *             // ...
               *         }
               *     });
               */
              init: function () {
              },
  
              /**
               * Copies properties into this object.
               *
               * @param {Object} properties The properties to mix in.
               *
               * @example
               *
               *     MyType.mixIn({
               *         field: 'value'
               *     });
               */
              mixIn: function (properties) {
                  for (var propertyName in properties) {
                      if (properties.hasOwnProperty(propertyName)) {
                          this[propertyName] = properties[propertyName];
                      }
                  }
  
                  // IE won't copy toString using the loop above
                  if (properties.hasOwnProperty('toString')) {
                      this.toString = properties.toString;
                  }
              },
  
              /**
               * Creates a copy of this object.
               *
               * @return {Object} The clone.
               *
               * @example
               *
               *     var clone = instance.clone();
               */
              clone: function () {
                  return this.init.prototype.extend(this);
              }
          };
      }());
  
      /**
       * An array of 32-bit words.
       *
       * @property {Array} words The array of 32-bit words.
       * @property {number} sigBytes The number of significant bytes in this word array.
       */
      var WordArray = C_lib.WordArray = Base.extend({
          /**
           * Initializes a newly created word array.
           *
           * @param {Array} words (Optional) An array of 32-bit words.
           * @param {number} sigBytes (Optional) The number of significant bytes in the words.
           *
           * @example
           *
           *     var wordArray = CryptoJS.lib.WordArray.create();
           *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
           *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
           */
          init: function (words, sigBytes) {
              words = this.words = words || [];
  
              if (sigBytes != undefined) {
                  this.sigBytes = sigBytes;
              } else {
                  this.sigBytes = words.length * 4;
              }
          },
  
          /**
           * Converts this word array to a string.
           *
           * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
           *
           * @return {string} The stringified word array.
           *
           * @example
           *
           *     var string = wordArray + '';
           *     var string = wordArray.toString();
           *     var string = wordArray.toString(CryptoJS.enc.Utf8);
           */
          toString: function (encoder) {
              return (encoder || Hex).stringify(this);
          },
  
          /**
           * Concatenates a word array to this word array.
           *
           * @param {WordArray} wordArray The word array to append.
           *
           * @return {WordArray} This word array.
           *
           * @example
           *
           *     wordArray1.concat(wordArray2);
           */
          concat: function (wordArray) {
              // Shortcuts
              var thisWords = this.words;
              var thatWords = wordArray.words;
              var thisSigBytes = this.sigBytes;
              var thatSigBytes = wordArray.sigBytes;
  
              // Clamp excess bits
              this.clamp();
  
              // Concat
              if (thisSigBytes % 4) {
                  // Copy one byte at a time
                  for (var i = 0; i < thatSigBytes; i++) {
                      var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                      thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
                  }
              } else if (thatWords.length > 0xffff) {
                  // Copy one word at a time
                  for (var i = 0; i < thatSigBytes; i += 4) {
                      thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
                  }
              } else {
                  // Copy all words at once
                  thisWords.push.apply(thisWords, thatWords);
              }
              this.sigBytes += thatSigBytes;
  
              // Chainable
              return this;
          },
  
          /**
           * Removes insignificant bits.
           *
           * @example
           *
           *     wordArray.clamp();
           */
          clamp: function () {
              // Shortcuts
              var words = this.words;
              var sigBytes = this.sigBytes;
  
              // Clamp
              words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
              words.length = Math.ceil(sigBytes / 4);
          },
  
          /**
           * Creates a copy of this word array.
           *
           * @return {WordArray} The clone.
           *
           * @example
           *
           *     var clone = wordArray.clone();
           */
          clone: function () {
              var clone = Base.clone.call(this);
              clone.words = this.words.slice(0);
  
              return clone;
          },
  
          /**
           * Creates a word array filled with random bytes.
           *
           * @param {number} nBytes The number of random bytes to generate.
           *
           * @return {WordArray} The random word array.
           *
           * @static
           *
           * @example
           *
           *     var wordArray = CryptoJS.lib.WordArray.random(16);
           */
          random: function (nBytes) {
              var words = [];
              for (var i = 0; i < nBytes; i += 4) {
                  words.push((Math.random() * 0x100000000) | 0);
              }
  
              return new WordArray.init(words, nBytes);
          }
      });
  
      /**
       * Encoder namespace.
       */
      var C_enc = C.enc = {};
  
      /**
       * Hex encoding strategy.
       */
      var Hex = C_enc.Hex = {
          /**
           * Converts a word array to a hex string.
           *
           * @param {WordArray} wordArray The word array.
           *
           * @return {string} The hex string.
           *
           * @static
           *
           * @example
           *
           *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
           */
          stringify: function (wordArray) {
              // Shortcuts
              var words = wordArray.words;
              var sigBytes = wordArray.sigBytes;
  
              // Convert
              var hexChars = [];
              for (var i = 0; i < sigBytes; i++) {
                  var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                  hexChars.push((bite >>> 4).toString(16));
                  hexChars.push((bite & 0x0f).toString(16));
              }
  
              return hexChars.join('');
          },
  
          /**
           * Converts a hex string to a word array.
           *
           * @param {string} hexStr The hex string.
           *
           * @return {WordArray} The word array.
           *
           * @static
           *
           * @example
           *
           *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
           */
          parse: function (hexStr) {
              // Shortcut
              var hexStrLength = hexStr.length;
  
              // Convert
              var words = [];
              for (var i = 0; i < hexStrLength; i += 2) {
                  words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
              }
  
              return new WordArray.init(words, hexStrLength / 2);
          }
      };
  
      /**
       * Latin1 encoding strategy.
       */
      var Latin1 = C_enc.Latin1 = {
          /**
           * Converts a word array to a Latin1 string.
           *
           * @param {WordArray} wordArray The word array.
           *
           * @return {string} The Latin1 string.
           *
           * @static
           *
           * @example
           *
           *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
           */
          stringify: function (wordArray) {
              // Shortcuts
              var words = wordArray.words;
              var sigBytes = wordArray.sigBytes;
  
              // Convert
              var latin1Chars = [];
              for (var i = 0; i < sigBytes; i++) {
                  var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
                  latin1Chars.push(String.fromCharCode(bite));
              }
  
              return latin1Chars.join('');
          },
  
          /**
           * Converts a Latin1 string to a word array.
           *
           * @param {string} latin1Str The Latin1 string.
           *
           * @return {WordArray} The word array.
           *
           * @static
           *
           * @example
           *
           *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
           */
          parse: function (latin1Str) {
              // Shortcut
              var latin1StrLength = latin1Str.length;
  
              // Convert
              var words = [];
              for (var i = 0; i < latin1StrLength; i++) {
                  words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
              }
  
              return new WordArray.init(words, latin1StrLength);
          }
      };
  
      /**
       * UTF-8 encoding strategy.
       */
      var Utf8 = C_enc.Utf8 = {
          /**
           * Converts a word array to a UTF-8 string.
           *
           * @param {WordArray} wordArray The word array.
           *
           * @return {string} The UTF-8 string.
           *
           * @static
           *
           * @example
           *
           *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
           */
          stringify: function (wordArray) {
              try {
                  return decodeURIComponent(escape(Latin1.stringify(wordArray)));
              } catch (e) {
                  throw new Error('Malformed UTF-8 data');
              }
          },
  
          /**
           * Converts a UTF-8 string to a word array.
           *
           * @param {string} utf8Str The UTF-8 string.
           *
           * @return {WordArray} The word array.
           *
           * @static
           *
           * @example
           *
           *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
           */
          parse: function (utf8Str) {
              return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
          }
      };
  
      /**
       * Abstract buffered block algorithm template.
       *
       * The property blockSize must be implemented in a concrete subtype.
       *
       * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
       */
      var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
          /**
           * Resets this block algorithm's data buffer to its initial state.
           *
           * @example
           *
           *     bufferedBlockAlgorithm.reset();
           */
          reset: function () {
              // Initial values
              this._data = new WordArray.init();
              this._nDataBytes = 0;
          },
  
          /**
           * Adds new data to this block algorithm's buffer.
           *
           * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
           *
           * @example
           *
           *     bufferedBlockAlgorithm._append('data');
           *     bufferedBlockAlgorithm._append(wordArray);
           */
          _append: function (data) {
              // Convert string to WordArray, else assume WordArray already
              if (typeof data == 'string') {
                  data = Utf8.parse(data);
              }
  
              // Append
              this._data.concat(data);
              this._nDataBytes += data.sigBytes;
          },
  
          /**
           * Processes available data blocks.
           *
           * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
           *
           * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
           *
           * @return {WordArray} The processed data.
           *
           * @example
           *
           *     var processedData = bufferedBlockAlgorithm._process();
           *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
           */
          _process: function (doFlush) {
              // Shortcuts
              var data = this._data;
              var dataWords = data.words;
              var dataSigBytes = data.sigBytes;
              var blockSize = this.blockSize;
              var blockSizeBytes = blockSize * 4;
  
              // Count blocks ready
              var nBlocksReady = dataSigBytes / blockSizeBytes;
              if (doFlush) {
                  // Round up to include partial blocks
                  nBlocksReady = Math.ceil(nBlocksReady);
              } else {
                  // Round down to include only full blocks,
                  // less the number of blocks that must remain in the buffer
                  nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
              }
  
              // Count words ready
              var nWordsReady = nBlocksReady * blockSize;
  
              // Count bytes ready
              var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
  
              // Process blocks
              if (nWordsReady) {
                  for (var offset = 0; offset < nWordsReady; offset += blockSize) {
                      // Perform concrete-algorithm logic
                      this._doProcessBlock(dataWords, offset);
                  }
  
                  // Remove processed words
                  var processedWords = dataWords.splice(0, nWordsReady);
                  data.sigBytes -= nBytesReady;
              }
  
              // Return processed words
              return new WordArray.init(processedWords, nBytesReady);
          },
  
          /**
           * Creates a copy of this object.
           *
           * @return {Object} The clone.
           *
           * @example
           *
           *     var clone = bufferedBlockAlgorithm.clone();
           */
          clone: function () {
              var clone = Base.clone.call(this);
              clone._data = this._data.clone();
  
              return clone;
          },
  
          _minBufferSize: 0
      });
  
      /**
       * Abstract hasher template.
       *
       * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
       */
      var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
          /**
           * Configuration options.
           */
          cfg: Base.extend(),
  
          /**
           * Initializes a newly created hasher.
           *
           * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
           *
           * @example
           *
           *     var hasher = CryptoJS.algo.SHA256.create();
           */
          init: function (cfg) {
              // Apply config defaults
              this.cfg = this.cfg.extend(cfg);
  
              // Set initial values
              this.reset();
          },
  
          /**
           * Resets this hasher to its initial state.
           *
           * @example
           *
           *     hasher.reset();
           */
          reset: function () {
              // Reset data buffer
              BufferedBlockAlgorithm.reset.call(this);
  
              // Perform concrete-hasher logic
              this._doReset();
          },
  
          /**
           * Updates this hasher with a message.
           *
           * @param {WordArray|string} messageUpdate The message to append.
           *
           * @return {Hasher} This hasher.
           *
           * @example
           *
           *     hasher.update('message');
           *     hasher.update(wordArray);
           */
          update: function (messageUpdate) {
              // Append
              this._append(messageUpdate);
  
              // Update the hash
              this._process();
  
              // Chainable
              return this;
          },
  
          /**
           * Finalizes the hash computation.
           * Note that the finalize operation is effectively a destructive, read-once operation.
           *
           * @param {WordArray|string} messageUpdate (Optional) A final message update.
           *
           * @return {WordArray} The hash.
           *
           * @example
           *
           *     var hash = hasher.finalize();
           *     var hash = hasher.finalize('message');
           *     var hash = hasher.finalize(wordArray);
           */
          finalize: function (messageUpdate) {
              // Final message update
              if (messageUpdate) {
                  this._append(messageUpdate);
              }
  
              // Perform concrete-hasher logic
              var hash = this._doFinalize();
  
              return hash;
          },
  
          blockSize: 512/32,
  
          /**
           * Creates a shortcut function to a hasher's object interface.
           *
           * @param {Hasher} hasher The hasher to create a helper for.
           *
           * @return {Function} The shortcut function.
           *
           * @static
           *
           * @example
           *
           *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
           */
          _createHelper: function (hasher) {
              return function (message, cfg) {
                  return new hasher.init(cfg).finalize(message);
              };
          },
  
          /**
           * Creates a shortcut function to the HMAC's object interface.
           *
           * @param {Hasher} hasher The hasher to use in this HMAC helper.
           *
           * @return {Function} The shortcut function.
           *
           * @static
           *
           * @example
           *
           *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
           */
          _createHmacHelper: function (hasher) {
              return function (message, key) {
                  return new C_algo.HMAC.init(hasher, key).finalize(message);
              };
          }
      });
  
      /**
       * Algorithm namespace.
       */
      var C_algo = C.algo = {};
  
      return C;
  }(Math));
  
  /*
  CryptoJS v3.1.2
  code.google.com/p/crypto-js
  (c) 2009-2013 by Jeff Mott. All rights reserved.
  code.google.com/p/crypto-js/wiki/License
  */
  (function (Math) {
      // Shortcuts
      var C = CryptoJS;
      var C_lib = C.lib;
      var WordArray = C_lib.WordArray;
      var Hasher = C_lib.Hasher;
      var C_algo = C.algo;
  
      // Initialization and round constants tables
      var H = [];
      var K = [];
  
      // Compute constants
      (function () {
          function isPrime(n) {
              var sqrtN = Math.sqrt(n);
              for (var factor = 2; factor <= sqrtN; factor++) {
                  if (!(n % factor)) {
                      return false;
                  }
              }
  
              return true;
          }
  
          function getFractionalBits(n) {
              return ((n - (n | 0)) * 0x100000000) | 0;
          }
  
          var n = 2;
          var nPrime = 0;
          while (nPrime < 64) {
              if (isPrime(n)) {
                  if (nPrime < 8) {
                      H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
                  }
                  K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
  
                  nPrime++;
              }
  
              n++;
          }
      }());
  
      // Reusable object
      var W = [];
  
      /**
       * SHA-256 hash algorithm.
       */
      var SHA256 = C_algo.SHA256 = Hasher.extend({
          _doReset: function () {
              this._hash = new WordArray.init(H.slice(0));
          },
  
          _doProcessBlock: function (M, offset) {
              // Shortcut
              var H = this._hash.words;
  
              // Working variables
              var a = H[0];
              var b = H[1];
              var c = H[2];
              var d = H[3];
              var e = H[4];
              var f = H[5];
              var g = H[6];
              var h = H[7];
  
              // Computation
              for (var i = 0; i < 64; i++) {
                  if (i < 16) {
                      W[i] = M[offset + i] | 0;
                  } else {
                      var gamma0x = W[i - 15];
                      var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
                                    ((gamma0x << 14) | (gamma0x >>> 18)) ^
                                     (gamma0x >>> 3);
  
                      var gamma1x = W[i - 2];
                      var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
                                    ((gamma1x << 13) | (gamma1x >>> 19)) ^
                                     (gamma1x >>> 10);
  
                      W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
                  }
  
                  var ch  = (e & f) ^ (~e & g);
                  var maj = (a & b) ^ (a & c) ^ (b & c);
  
                  var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
                  var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));
  
                  var t1 = h + sigma1 + ch + K[i] + W[i];
                  var t2 = sigma0 + maj;
  
                  h = g;
                  g = f;
                  f = e;
                  e = (d + t1) | 0;
                  d = c;
                  c = b;
                  b = a;
                  a = (t1 + t2) | 0;
              }
  
              // Intermediate hash value
              H[0] = (H[0] + a) | 0;
              H[1] = (H[1] + b) | 0;
              H[2] = (H[2] + c) | 0;
              H[3] = (H[3] + d) | 0;
              H[4] = (H[4] + e) | 0;
              H[5] = (H[5] + f) | 0;
              H[6] = (H[6] + g) | 0;
              H[7] = (H[7] + h) | 0;
          },
  
          _doFinalize: function () {
              // Shortcuts
              var data = this._data;
              var dataWords = data.words;
  
              var nBitsTotal = this._nDataBytes * 8;
              var nBitsLeft = data.sigBytes * 8;
  
              // Add padding
              dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
              dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
              dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
              data.sigBytes = dataWords.length * 4;
  
              // Hash final blocks
              this._process();
  
              // Return final computed hash
              return this._hash;
          },
  
          clone: function () {
              var clone = Hasher.clone.call(this);
              clone._hash = this._hash.clone();
  
              return clone;
          }
      });
  
      /**
       * Shortcut function to the hasher's object interface.
       *
       * @param {WordArray|string} message The message to hash.
       *
       * @return {WordArray} The hash.
       *
       * @static
       *
       * @example
       *
       *     var hash = CryptoJS.SHA256('message');
       *     var hash = CryptoJS.SHA256(wordArray);
       */
      C.SHA256 = Hasher._createHelper(SHA256);
  
      /**
       * Shortcut function to the HMAC's object interface.
       *
       * @param {WordArray|string} message The message to hash.
       * @param {WordArray|string} key The secret key.
       *
       * @return {WordArray} The HMAC.
       *
       * @static
       *
       * @example
       *
       *     var hmac = CryptoJS.HmacSHA256(message, key);
       */
      C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
  }(Math));
  
  /*
  CryptoJS v3.1.2
  code.google.com/p/crypto-js
  (c) 2009-2013 by Jeff Mott. All rights reserved.
  code.google.com/p/crypto-js/wiki/License
  */
  /** @preserve
  (c) 2012 by Cédric Mesnil. All rights reserved.
  
  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  
      - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
      - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  
  (function (Math) {
      // Shortcuts
      var C = CryptoJS;
      var C_lib = C.lib;
      var WordArray = C_lib.WordArray;
      var Hasher = C_lib.Hasher;
      var C_algo = C.algo;
  
      // Constants table
      var _zl = WordArray.create([
          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
          7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
          3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
          1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
          4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13]);
      var _zr = WordArray.create([
          5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
          6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
          15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
          8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
          12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11]);
      var _sl = WordArray.create([
           11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
          7, 6,   8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
          11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
            11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
          9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 ]);
      var _sr = WordArray.create([
          8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
          9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
          9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
          15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
          8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 ]);
  
      var _hl =  WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]);
      var _hr =  WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]);
  
      /**
       * RIPEMD160 hash algorithm.
       */
      var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({
          _doReset: function () {
              this._hash  = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
          },
  
          _doProcessBlock: function (M, offset) {
  
              // Swap endian
              for (var i = 0; i < 16; i++) {
                  // Shortcuts
                  var offset_i = offset + i;
                  var M_offset_i = M[offset_i];
  
                  // Swap
                  M[offset_i] = (
                      (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
                      (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
                  );
              }
              // Shortcut
              var H  = this._hash.words;
              var hl = _hl.words;
              var hr = _hr.words;
              var zl = _zl.words;
              var zr = _zr.words;
              var sl = _sl.words;
              var sr = _sr.words;
  
              // Working variables
              var al, bl, cl, dl, el;
              var ar, br, cr, dr, er;
  
              ar = al = H[0];
              br = bl = H[1];
              cr = cl = H[2];
              dr = dl = H[3];
              er = el = H[4];
              // Computation
              var t;
              for (var i = 0; i < 80; i += 1) {
                  t = (al +  M[offset+zl[i]])|0;
                  if (i<16){
  	            t +=  f1(bl,cl,dl) + hl[0];
                  } else if (i<32) {
  	            t +=  f2(bl,cl,dl) + hl[1];
                  } else if (i<48) {
  	            t +=  f3(bl,cl,dl) + hl[2];
                  } else if (i<64) {
  	            t +=  f4(bl,cl,dl) + hl[3];
                  } else {// if (i<80) {
  	            t +=  f5(bl,cl,dl) + hl[4];
                  }
                  t = t|0;
                  t =  rotl(t,sl[i]);
                  t = (t+el)|0;
                  al = el;
                  el = dl;
                  dl = rotl(cl, 10);
                  cl = bl;
                  bl = t;
  
                  t = (ar + M[offset+zr[i]])|0;
                  if (i<16){
  	            t +=  f5(br,cr,dr) + hr[0];
                  } else if (i<32) {
  	            t +=  f4(br,cr,dr) + hr[1];
                  } else if (i<48) {
  	            t +=  f3(br,cr,dr) + hr[2];
                  } else if (i<64) {
  	            t +=  f2(br,cr,dr) + hr[3];
                  } else {// if (i<80) {
  	            t +=  f1(br,cr,dr) + hr[4];
                  }
                  t = t|0;
                  t =  rotl(t,sr[i]) ;
                  t = (t+er)|0;
                  ar = er;
                  er = dr;
                  dr = rotl(cr, 10);
                  cr = br;
                  br = t;
              }
              // Intermediate hash value
              t    = (H[1] + cl + dr)|0;
              H[1] = (H[2] + dl + er)|0;
              H[2] = (H[3] + el + ar)|0;
              H[3] = (H[4] + al + br)|0;
              H[4] = (H[0] + bl + cr)|0;
              H[0] =  t;
          },
  
          _doFinalize: function () {
              // Shortcuts
              var data = this._data;
              var dataWords = data.words;
  
              var nBitsTotal = this._nDataBytes * 8;
              var nBitsLeft = data.sigBytes * 8;
  
              // Add padding
              dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
              dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
                  (((nBitsTotal << 8)  | (nBitsTotal >>> 24)) & 0x00ff00ff) |
                  (((nBitsTotal << 24) | (nBitsTotal >>> 8))  & 0xff00ff00)
              );
              data.sigBytes = (dataWords.length + 1) * 4;
  
              // Hash final blocks
              this._process();
  
              // Shortcuts
              var hash = this._hash;
              var H = hash.words;
  
              // Swap endian
              for (var i = 0; i < 5; i++) {
                  // Shortcut
                  var H_i = H[i];
  
                  // Swap
                  H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
                         (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
              }
  
              // Return final computed hash
              return hash;
          },
  
          clone: function () {
              var clone = Hasher.clone.call(this);
              clone._hash = this._hash.clone();
  
              return clone;
          }
      });
  
  
      function f1(x, y, z) {
          return ((x) ^ (y) ^ (z));
  
      }
  
      function f2(x, y, z) {
          return (((x)&(y)) | ((~x)&(z)));
      }
  
      function f3(x, y, z) {
          return (((x) | (~(y))) ^ (z));
      }
  
      function f4(x, y, z) {
          return (((x) & (z)) | ((y)&(~(z))));
      }
  
      function f5(x, y, z) {
          return ((x) ^ ((y) |(~(z))));
  
      }
  
      function rotl(x,n) {
          return (x<<n) | (x>>>(32-n));
      }
  
  
      /**
       * Shortcut function to the hasher's object interface.
       *
       * @param {WordArray|string} message The message to hash.
       *
       * @return {WordArray} The hash.
       *
       * @static
       *
       * @example
       *
       *     var hash = CryptoJS.RIPEMD160('message');
       *     var hash = CryptoJS.RIPEMD160(wordArray);
       */
      C.RIPEMD160 = Hasher._createHelper(RIPEMD160);
  
      /**
       * Shortcut function to the HMAC's object interface.
       *
       * @param {WordArray|string} message The message to hash.
       * @param {WordArray|string} key The secret key.
       *
       * @return {WordArray} The HMAC.
       *
       * @static
       *
       * @example
       *
       *     var hmac = CryptoJS.HmacRIPEMD160(message, key);
       */
      C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160);
  }(Math));
  