index.template.html

file with Javascript Function. - Nepherkaan, 07/30/2009 11:00 am

Download (22.7 kB)

 
1
<!-- saved from url=(0014)about:internet -->
2
<html lang="en">
3

4
<!-- 
5
Smart developers always View Source. 
6

7
This application was built using Adobe Flex, an open source framework
8
for building rich Internet applications that get delivered via the
9
Flash Player or to desktops via Adobe AIR. 
10

11
Learn more about Flex at http://flex.org 
12
// -->
13

14
<head>
15
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
16

17
<!--  BEGIN Browser History required section -->
18
<link rel="stylesheet" type="text/css" href="history/history.css" />
19
<!--  END Browser History required section -->
20

21
<title>${title}</title>
22
<script src="AC_OETags.js" language="javascript"></script>
23

24
<!--  BEGIN Browser History required section -->
25
<script src="history/history.js" language="javascript"></script>
26
<!--  END Browser History required section -->
27

28
<style>
29
body { margin: 0px; overflow:hidden }
30
</style>
31
<script language="JavaScript" type="text/javascript">
32
<!--
33
// -----------------------------------------------------------------------------
34
// Globals
35
// Major version of Flash required
36
var requiredMajorVersion = ${version_major};
37
// Minor version of Flash required
38
var requiredMinorVersion = ${version_minor};
39
// Minor version of Flash required
40
var requiredRevision = ${version_revision};
41
// -----------------------------------------------------------------------------
42
// -->
43
</script>
44
</head>
45

46
<body scroll="no">
47
<script language="JavaScript" type="text/javascript">
48
<!--
49
// Version check for the Flash Player that has the ability to start Player Product Install (6.0r65)
50
var hasProductInstall = DetectFlashVer(6, 0, 65);
51

52
// Version check based upon the values defined in globals
53
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
54

55
if ( hasProductInstall && !hasRequestedVersion ) {
56
        // DO NOT MODIFY THE FOLLOWING FOUR LINES
57
        // Location visited after installation is complete if installation is required
58
        var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
59
        var MMredirectURL = window.location;
60
    document.title = document.title.slice(0, 47) + " - Flash Player Installation";
61
    var MMdoctitle = document.title;
62

63
        AC_FL_RunContent(
64
                "src", "playerProductInstall",
65
                "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"",
66
                "width", "${width}",
67
                "height", "${height}",
68
                "align", "middle",
69
                "id", "${application}",
70
                "quality", "high",
71
                "bgcolor", "${bgcolor}",
72
                "name", "${application}",
73
                "allowScriptAccess","sameDomain",
74
                "type", "application/x-shockwave-flash",
75
                "pluginspage", "http://www.adobe.com/go/getflashplayer"
76
        );
77
} else if (hasRequestedVersion) {
78
        // if we've detected an acceptable version
79
        // embed the Flash Content SWF when all tests are passed
80
        AC_FL_RunContent(
81
                        "src", "${swf}",
82
                        "width", "${width}",
83
                        "height", "${height}",
84
                        "align", "middle",
85
                        "id", "${application}",
86
                        "quality", "high",
87
                        "bgcolor", "${bgcolor}",
88
                        "name", "${application}",
89
                        "allowScriptAccess","sameDomain",
90
                        "type", "application/x-shockwave-flash",
91
                        "pluginspage", "http://www.adobe.com/go/getflashplayer"
92
        );
93
  } else {  // flash is too old or we can't detect the plugin
94
    var alternateContent = 'Alternate HTML content should be placed here. '
95
          + 'This content requires the Adobe Flash Player. '
96
           + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
97
    document.write(alternateContent);  // insert non-flash content
98
  }
99
// -->
100
</script>
101
<noscript>
102
          <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
103
                        id="${application}" width="${width}" height="${height}"
104
                        codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
105
                        <param name="movie" value="${swf}.swf" />
106
                        <param name="quality" value="high" />
107
                        <param name="bgcolor" value="${bgcolor}" />
108
                        <param name="allowScriptAccess" value="sameDomain" />
109
                        <embed src="${swf}.swf" quality="high" bgcolor="${bgcolor}"
110
                                width="${width}" height="${height}" name="${application}" align="middle"
111
                                play="true"
112
                                loop="false"
113
                                quality="high"
114
                                allowScriptAccess="sameDomain"
115
                                type="application/x-shockwave-flash"
116
                                pluginspage="http://www.adobe.com/go/getflashplayer">
117
                        </embed>
118
        </object>
119
</noscript>
120
<script language="Javascript">
121
                /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
122
                /*  AES implementation in JavaScript (c) Chris Veness 2005-2008                                   */
123
                /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
124
                
125
                /*
126
                 * AES Cipher function: encrypt 'input' with Rijndael algorithm
127
                 *
128
                 *   takes   byte-array 'input' (16 bytes)
129
                 *           2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
130
                 *
131
                 *   applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
132
                 *
133
                 *   returns byte-array encrypted value (16 bytes)
134
                 */
135
                function Cipher(input, w) {    // main Cipher function [§5.1]
136
                  var Nb = 4;               // block size (in words): no of columns in state (fixed at 4 for AES)
137
                  var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
138
                
139
                  var state = [[],[],[],[]];  // initialise 4xNb byte-array 'state' with input [§3.4]
140
                  for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
141
                
142
                  state = AddRoundKey(state, w, 0, Nb);
143
                
144
                  for (var round=1; round<Nr; round++) {
145
                    state = SubBytes(state, Nb);
146
                    state = ShiftRows(state, Nb);
147
                    state = MixColumns(state, Nb);
148
                    state = AddRoundKey(state, w, round, Nb);
149
                  }
150
                
151
                  state = SubBytes(state, Nb);
152
                  state = ShiftRows(state, Nb);
153
                  state = AddRoundKey(state, w, Nr, Nb);
154
                
155
                  var output = new Array(4*Nb);  // convert state to 1-d array before returning [§3.4]
156
                  for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
157
                  return output;
158
                }
159
                
160
                
161
                function SubBytes(s, Nb) {    // apply SBox to state S [§5.1.1]
162
                  for (var r=0; r<4; r++) {
163
                    for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
164
                  }
165
                  return s;
166
                }
167
                
168
                
169
                function ShiftRows(s, Nb) {    // shift row r of state S left by r bytes [§5.1.2]
170
                  var t = new Array(4);
171
                  for (var r=1; r<4; r++) {
172
                    for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb];  // shift into temp copy
173
                    for (var c=0; c<4; c++) s[r][c] = t[c];         // and copy back
174
                  }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
175
                  return s;  // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf 
176
                }
177
                
178
                
179
                function MixColumns(s, Nb) {   // combine bytes of each col of state S [§5.1.3]
180
                  for (var c=0; c<4; c++) {
181
                    var a = new Array(4);  // 'a' is a copy of the current column from 's'
182
                    var b = new Array(4);  // 'b' is a•{02} in GF(2^8)
183
                    for (var i=0; i<4; i++) {
184
                      a[i] = s[i][c];
185
                      b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
186
                    }
187
                    // a[n] ^ b[n] is a•{03} in GF(2^8)
188
                    s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
189
                    s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
190
                    s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
191
                    s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
192
                  }
193
                  return s;
194
                }
195
                
196
                
197
                function AddRoundKey(state, w, rnd, Nb) {  // xor Round Key into state S [§5.1.4]
198
                  for (var r=0; r<4; r++) {
199
                    for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
200
                  }
201
                  return state;
202
                }
203
                
204
                
205
                function KeyExpansion(key) {  // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
206
                  var Nb = 4;            // block size (in words): no of columns in state (fixed at 4 for AES)
207
                  var Nk = key.length/4  // key length (in words): 4/6/8 for 128/192/256-bit keys
208
                  var Nr = Nk + 6;       // no of rounds: 10/12/14 for 128/192/256-bit keys
209
                
210
                  var w = new Array(Nb*(Nr+1));
211
                  var temp = new Array(4);
212
                
213
                  for (var i=0; i<Nk; i++) {
214
                    var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
215
                    w[i] = r;
216
                  }
217
                
218
                  for (var i=Nk; i<(Nb*(Nr+1)); i++) {
219
                    w[i] = new Array(4);
220
                    for (var t=0; t<4; t++) temp[t] = w[i-1][t];
221
                    if (i % Nk == 0) {
222
                      temp = SubWord(RotWord(temp));
223
                      for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
224
                    } else if (Nk > 6 && i%Nk == 4) {
225
                      temp = SubWord(temp);
226
                    }
227
                    for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
228
                  }
229
                
230
                  return w;
231
                }
232
                
233
                function SubWord(w) {    // apply SBox to 4-byte word w
234
                  for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
235
                  return w;
236
                }
237
                
238
                function RotWord(w) {    // rotate 4-byte word w left by one byte
239
                  var tmp = w[0];
240
                  for (var i=0; i<3; i++) w[i] = w[i+1];
241
                  w[3] = tmp;
242
                  return w;
243
                }
244
                
245
                
246
                // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
247
                var Sbox =  [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
248
                             0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
249
                             0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
250
                             0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
251
                             0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
252
                             0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
253
                             0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
254
                             0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
255
                             0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
256
                             0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
257
                             0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
258
                             0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
259
                             0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
260
                             0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
261
                             0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
262
                             0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
263
                
264
                // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
265
                var Rcon = [ [0x00, 0x00, 0x00, 0x00],
266
                             [0x01, 0x00, 0x00, 0x00],
267
                             [0x02, 0x00, 0x00, 0x00],
268
                             [0x04, 0x00, 0x00, 0x00],
269
                             [0x08, 0x00, 0x00, 0x00],
270
                             [0x10, 0x00, 0x00, 0x00],
271
                             [0x20, 0x00, 0x00, 0x00],
272
                             [0x40, 0x00, 0x00, 0x00],
273
                             [0x80, 0x00, 0x00, 0x00],
274
                             [0x1b, 0x00, 0x00, 0x00],
275
                             [0x36, 0x00, 0x00, 0x00] ]; 
276
                
277
                
278
                /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
279
                
280
                /** 
281
                 * Encrypt a text using AES encryption in Counter mode of operation
282
                 *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
283
                 *
284
                 * Unicode multi-byte character safe
285
                 *
286
                 * @param plaintext source text to be encrypted
287
                 * @param password  the password to use to generate a key
288
                 * @param nBits     number of bits to be used in the key (128, 192, or 256)
289
                 * @return          encrypted text
290
                 */
291
                function AESEncryptCtr(plaintext, password, nBits) {
292
                  var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
293
                  if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
294
                  plaintext = plaintext.encodeUTF8();
295
                  password = password.encodeUTF8();
296
                  //var t = new Date();  // timer
297
                        
298
                  // use AES itself to encrypt password to get cipher key (using plain password as source for key 
299
                  // expansion) - gives us well encrypted key
300
                  var nBytes = nBits/8;  // no bytes in key
301
                  var pwBytes = new Array(nBytes);
302
                  for (var i=0; i<nBytes; i++) {
303
                    pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
304
                  }
305

306
                  var key = Cipher(pwBytes, KeyExpansion(pwBytes));  // gives us 16-byte key
307
                  key = key.concat(key.slice(0, nBytes-16));  // expand key to 16/24/32 bytes long
308
                
309
                  // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
310
                  // block counter in 2nd 8 bytes
311
                  var counterBlock = new Array(blockSize);
312
                  var nonce = (new Date()).getTime();  // timestamp: milliseconds since 1-Jan-1970
313
                  var nonceSec = Math.floor(nonce/1000);
314
                  var nonceMs = nonce%1000;
315
                  // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
316
                  for (var i=0; i<4; i++) counterBlock[i] = (nonceSec >>> i*8) & 0xff;
317
                  for (var i=0; i<4; i++) counterBlock[i+4] = nonceMs & 0xff; 
318
                  // and convert it to a string to go on the front of the ciphertext
319
                  var ctrTxt = '';
320
                  for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
321
                
322
                  // generate key schedule - an expansion of the key into distinct Key Rounds for each round
323
                  var keySchedule = KeyExpansion(key);
324
                  
325
                  var blockCount = Math.ceil(plaintext.length/blockSize);
326
                  var ciphertxt = new Array(blockCount);  // ciphertext as array of strings
327
                  
328
                  for (var b=0; b<blockCount; b++) {
329
                    // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
330
                    // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
331
                    for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
332
                    for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
333
                
334
                    var cipherCntr = Cipher(counterBlock, keySchedule);  // -- encrypt counter block --
335
                    
336
                    // block size is reduced on final block
337
                    var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
338
                    var cipherChar = new Array(blockLength);
339
                    
340
                    for (var i=0; i<blockLength; i++) {  // -- xor plaintext with ciphered counter char-by-char --
341
                      cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i);
342
                      cipherChar[i] = String.fromCharCode(cipherChar[i]);
343
                    }
344
                    ciphertxt[b] = cipherChar.join(''); 
345
                  }
346
                
347
                  // Array.join is more efficient than repeated string concatenation
348
                  var ciphertext = ctrTxt + ciphertxt.join('');
349
                  ciphertext = ciphertext.encodeBase64();  // encode in base64
350
                  
351
                  //alert((new Date()) - t);
352
                  return ciphertext;
353
                }
354
                
355
                
356
                /** 
357
                 * Decrypt a text encrypted by AES in counter mode of operation
358
                 *
359
                 * @param ciphertext source text to be encrypted
360
                 * @param password   the password to use to generate a key
361
                 * @param nBits      number of bits to be used in the key (128, 192, or 256)
362
                 * @return           decrypted text
363
                 */
364
                function AESDecryptCtr(ciphertext, password, nBits) {
365
                  var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
366
                  if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
367
                  ciphertext = ciphertext.decodeBase64();
368
                  password = password.encodeUTF8();
369
                  //var t = new Date();  // timer
370
                  
371
                  // use AES to encrypt password (mirroring encrypt routine)
372
                  var nBytes = nBits/8;  // no bytes in key
373
                  var pwBytes = new Array(nBytes);
374
                  for (var i=0; i<nBytes; i++) {
375
                    pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
376
                  }
377
                  var key = Cipher(pwBytes, KeyExpansion(pwBytes));
378
                  key = key.concat(key.slice(0, nBytes-16));  // expand key to 16/24/32 bytes long
379
                
380
                  // recover nonce from 1st 8 bytes of ciphertext
381
                  var counterBlock = new Array(8);
382
                  ctrTxt = ciphertext.slice(0, 8);
383
                  for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
384
                  
385
                  // generate key schedule
386
                  var keySchedule = KeyExpansion(key);
387
                
388
                  // separate ciphertext into blocks (skipping past initial 8 bytes)
389
                  var nBlocks = Math.ceil((ciphertext.length-8) / blockSize);
390
                  var ct = new Array(nBlocks);
391
                  for (var b=0; b<nBlocks; b++) ct[b] = ciphertext.slice(8+b*blockSize, 8+b*blockSize+blockSize);
392
                  ciphertext = ct;  // ciphertext is now array of block-length strings
393
                
394
                  // plaintext will get generated block-by-block into array of block-length strings
395
                  var plaintxt = new Array(ciphertext.length);
396
                
397
                  for (var b=0; b<nBlocks; b++) {
398
                    // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
399
                    for (var c=0; c<4; c++) counterBlock[15-c] = ((b) >>> c*8) & 0xff;
400
                    for (var c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff;
401
                
402
                    var cipherCntr = Cipher(counterBlock, keySchedule);  // encrypt counter block
403
                
404
                    var plaintxtByte = new Array(ciphertext[b].length);
405
                    for (var i=0; i<ciphertext[b].length; i++) {
406
                      // -- xor plaintxt with ciphered counter byte-by-byte --
407
                      plaintxtByte[i] = cipherCntr[i] ^ ciphertext[b].charCodeAt(i);
408
                      plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]);
409
                    }
410
                    plaintxt[b] = plaintxtByte.join('');
411
                  }
412
                
413
                  // join array of blocks into single plaintext string
414
                  var plaintext = plaintxt.join('');
415
                  plaintext = plaintext.decodeUTF8();  // decode from UTF8 back to Unicode multi-byte chars
416
                  
417
                  //alert((new Date()) - t);
418
                  return plaintext;
419
                }
420
                
421
                /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
422
                
423
                /**
424
                 * Encode string into Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
425
                 * (instance method extending String object). As per RFC 4648, no newlines are added.
426
                 *
427
                 * @param utf8encode optional parameter, if set to true Unicode string is encoded to UTF8 before 
428
                 *                   conversion to base64; otherwise string is assumed to be 8-bit characters
429
                 * @return           base64-encoded string
430
                 */ 
431
                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
432
                
433
                String.prototype.encodeBase64 = function(utf8encode) {  // http://tools.ietf.org/html/rfc4648
434
                  utf8encode =  (typeof utf8encode == 'undefined') ? false : utf8encode;
435
                  var o1, o2, o3, bits, h1, h2, h3, h4, e=[], pad = '', c, plain, coded;
436
                   
437
                  plain = utf8encode ? this.encodeUTF8() : this;
438
                  
439
                  c = plain.length % 3;  // pad string to length of multiple of 3
440
                  if (c > 0) { while (c++ < 3) { pad += '='; plain += '\0'; } }
441
                  // note: doing padding here saves us doing special-case packing for trailing 1 or 2 chars
442
                  
443
                  for (c=0; c<plain.length; c+=3) {  // pack three octets into four hexets
444
                    o1 = plain.charCodeAt(c);
445
                    o2 = plain.charCodeAt(c+1);
446
                    o3 = plain.charCodeAt(c+2);
447
                      
448
                    bits = o1<<16 | o2<<8 | o3;
449
                      
450
                    h1 = bits>>18 & 0x3f;
451
                    h2 = bits>>12 & 0x3f;
452
                    h3 = bits>>6 & 0x3f;
453
                    h4 = bits & 0x3f;
454
                
455
                    // use hextets to index into b64 string
456
                    e[c/3] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
457
                  }
458
                  coded = e.join('');  // join() is far faster than repeated string concatenation
459
                  
460
                  // replace 'A's from padded nulls with '='s
461
                  coded = coded.slice(0, coded.length-pad.length) + pad;
462
                   
463
                  return coded;
464
                }
465
                
466
                /**
467
                 * Decode string from Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
468
                 * (instance method extending String object). As per RFC 4648, newlines are not catered for.
469
                 *
470
                 * @param utf8decode optional parameter, if set to true UTF8 string is decoded back to Unicode  
471
                 *                   after conversion from base64
472
                 * @return           decoded string
473
                 */ 
474
                String.prototype.decodeBase64 = function(utf8decode) {
475
                  utf8decode =  (typeof utf8decode == 'undefined') ? false : utf8decode;
476
                  var o1, o2, o3, h1, h2, h3, h4, bits, d=[], plain, coded;
477
                
478
                  coded = utf8decode ? this.decodeUTF8() : this;
479
                  
480
                  for (var c=0; c<coded.length; c+=4) {  // unpack four hexets into three octets
481
                    h1 = b64.indexOf(coded.charAt(c));
482
                    h2 = b64.indexOf(coded.charAt(c+1));
483
                    h3 = b64.indexOf(coded.charAt(c+2));
484
                    h4 = b64.indexOf(coded.charAt(c+3));
485
                      
486
                    bits = h1<<18 | h2<<12 | h3<<6 | h4;
487
                      
488
                    o1 = bits>>>16 & 0xff;
489
                    o2 = bits>>>8 & 0xff;
490
                    o3 = bits & 0xff;
491
                    
492
                    d[c/4] = String.fromCharCode(o1, o2, o3);
493
                    // check for padding
494
                    if (h4 == 0x40) d[c/4] = String.fromCharCode(o1, o2);
495
                    if (h3 == 0x40) d[c/4] = String.fromCharCode(o1);
496
                  }
497
                  plain = d.join('');  // join() is far faster than repeated string concatenation
498
                   
499
                  return utf8decode ? plain.decodeUTF8() : plain; 
500
                }
501
                
502
                /**
503
                 * Encode multi-byte Unicode string into utf-8 multiple single-byte characters 
504
                 * (BMP / basic multilingual plane only) (instance method extending String object).
505
                 *
506
                 * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
507
                 *
508
                 * @return encoded string
509
                 */
510
                String.prototype.encodeUTF8 = function() {
511
                  // use regular expressions & String.replace callback function for better efficiency 
512
                  // than procedural approaches
513
                  var str = this.replace(
514
                      /[\u0080-\u07ff]/g,  // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
515
                      function(c) { 
516
                        var cc = c.charCodeAt(0);
517
                        return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
518
                    );
519
                  str = str.replace(
520
                      /[\u0800-\uffff]/g,  // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
521
                      function(c) { 
522
                        var cc = c.charCodeAt(0); 
523
                        return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
524
                    );
525
                  return str;
526
                }
527
                
528
                /**
529
                 * Decode utf-8 encoded string back into multi-byte Unicode characters
530
                 * (instance method extending String object).
531
                 *
532
                 * @return decoded string
533
                 */
534
                String.prototype.decodeUTF8 = function() {
535
                  var str = this.replace(
536
                      /[\u00c0-\u00df][\u0080-\u00bf]/g,                 // 2-byte chars
537
                      function(c) {  // (note parentheses for precence)
538
                        var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
539
                        return String.fromCharCode(cc); }
540
                    );
541
                  str = str.replace(
542
                      /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,  // 3-byte chars
543
                      function(c) {  // (note parentheses for precence)
544
                        var cc = ((c.charCodeAt(0)&0x0f)<<12) | ((c.charCodeAt(1)&0x3f)<<6) | ( c.charCodeAt(2)&0x3f); 
545
                        return String.fromCharCode(cc); }
546
                    );
547
                  return str;
548
                }
549
                
550
                /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
551
        </script>
552
</body>
553
</html>