├── public
├── favicon.ico
├── stylesheets
│ └── style.css
└── js
│ ├── siphash.js
│ ├── back.js
│ ├── sync-client.js
│ ├── md5.js
│ ├── murmurhash3.js
│ ├── bit-sync.js
│ └── socket.io-1.4.5.js
├── views
├── error.ejs
└── index.ejs
├── routes
├── users.js
└── index.js
├── package.json
├── README.md
├── test.js
├── bin
└── www
├── app.js
└── LICENSE
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WebDeltaSync/WebR2sync_plus/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/views/error.ejs:
--------------------------------------------------------------------------------
1 |
<%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/routes/users.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | /* GET users listing. */
5 | router.get('/', function(req, res, next) {
6 | res.send('respond with a resource');
7 | });
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | /* GET home page. */
5 | router.get('/', function(req, res, next) {
6 | res.render('index', { title: 'WebR2sync+' });
7 | });
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "websync2",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node ./bin/www"
7 | },
8 | "dependencies": {
9 | "ali-oss": "^4.7.3",
10 | "arraybuffer-to-buffer": "0.0.4",
11 | "body-parser": "~1.15.2",
12 | "co": "^4.6.0",
13 | "cookie-parser": "~1.4.3",
14 | "debug": "~2.2.0",
15 | "ejs": "~2.5.2",
16 | "express": "~4.14.0",
17 | "fs": "0.0.1-security",
18 | "hashmap": "^2.0.6",
19 | "md5": "^2.2.1",
20 | "morgan": "~1.7.0",
21 | "serve-favicon": "~2.3.0",
22 | "socket.io": "^1.7.1",
23 | "stream-to-buffer": "^0.1.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebRsync+
2 |
3 | *Notice:
4 |
5 | 1. As a demo, we replace ECS API with local File API so that you can run locally.
6 | 2. Use pure javascript version of server side so you don't need to compile c++ code (which is same as Linux Rsync).
7 |
8 | ## Get started
9 | > environment: node.js v6.9.0
10 | >> \>\> git clone this repository
11 | >>
12 | >> \>\> install npm
13 | >>
14 | >> \>\> cd to the path of this project
15 | >>
16 | >> \>\> npm install
17 | >>
18 | >> \>\> node bin/www
19 | >>
20 | >> \>\> Now ,visit localhost:7070 on your browser
21 |
22 | ## Document
23 | > Javascript Implementation of rsync algorithm: WebR2sync_plus/blob/master/public/js/bit-sync.js
24 | >
25 | > WebRsync Client: WebR2sync_plus/blob/master/public/js/sync-client.js
26 | >
27 | > WebRsync Server: WebR2sync_plus/blob/master/app.js
28 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by xiaohe on 2017/1/22.
3 | */
4 | var MOD_ADLER = 65521;
5 | function rollingChecksum(adlerInfo, offset, end, data)
6 | {
7 | var temp = data[offset - 1]; //this is the first byte used in the previous iteration
8 | var a = ((adlerInfo.a - temp + data[end]) % MOD_ADLER + MOD_ADLER)%MOD_ADLER;
9 | var b = ((adlerInfo.b - ((end - offset + 1) * temp) + a - 1) % MOD_ADLER + MOD_ADLER)%MOD_ADLER;
10 | return {a: a&0xffffffff, b: b&0xffffffff, checksum: ((b << 16) | a)&0xffffffff };
11 | }
12 |
13 | function adler32(offset, end, data)
14 | {
15 |
16 | var a = 1, b= 0;
17 |
18 | //adjust the end to make sure we don't exceed the extents of the data.
19 | if(end >= data.length)
20 | end = data.length - 1;
21 |
22 | for(i=offset; i <= end; i++)
23 | {
24 | a += data[i];
25 | b += a;
26 | a %= MOD_ADLER;
27 | b %= MOD_ADLER;
28 | }
29 |
30 | return {a: a&0xffffffff, b: b&0xffffffff, checksum: ((b << 16) | a) & 0xffffffff };
31 |
32 | }
33 | var data8view = new Uint8Array([1,2,3,4,5,6,7,8]);
34 | console.log(data8view);
35 | adler32info = adler32(0,4,data8view)
36 | console.log(adler32info);
37 | adler32info = rollingChecksum(adler32info,1,5,data8view);
38 | console.log(adler32info);
39 | adler32info1 = adler32(1,5,data8view)
40 | console.log(adler32info1);
41 |
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= title %>
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
30 | <%= title %>
31 | Welcome to <%= title %>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('websync2:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '7070');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/public/js/siphash.js:
--------------------------------------------------------------------------------
1 | var SipHash = new function() {
2 | "use strict";
3 | function _add(a, b) {
4 | var rl = a.l + b.l,
5 | a2 = { h: a.h + b.h + (rl / 2 >>> 31) >>> 0,
6 | l: rl >>> 0 };
7 | a.h = a2.h; a.l = a2.l;
8 | }
9 |
10 | function _xor(a, b) {
11 | a.h ^= b.h; a.h >>>= 0;
12 | a.l ^= b.l; a.l >>>= 0;
13 | }
14 |
15 | function _rotl(a, n) {
16 | var a2 = {
17 | h: a.h << n | a.l >>> (32 - n),
18 | l: a.l << n | a.h >>> (32 - n)
19 | };
20 | a.h = a2.h; a.l = a2.l;
21 | }
22 |
23 | function _rotl32(a) {
24 | var al = a.l;
25 | a.l = a.h; a.h = al;
26 | }
27 |
28 | function _compress(v0, v1, v2, v3) {
29 | _add(v0, v1);
30 | _add(v2, v3);
31 | _rotl(v1, 13);
32 | _rotl(v3, 16);
33 | _xor(v1, v0);
34 | _xor(v3, v2);
35 | _rotl32(v0);
36 | _add(v2, v1);
37 | _add(v0, v3);
38 | _rotl(v1, 17);
39 | _rotl(v3, 21);
40 | _xor(v1, v2);
41 | _xor(v3, v0);
42 | _rotl32(v2);
43 | }
44 |
45 | function _get_int(a, offset) {
46 | return a[offset + 3] << 24 |
47 | a[offset + 2] << 16 |
48 | a[offset + 1] << 8 |
49 | a[offset];
50 | }
51 |
52 | function hash(m) {
53 | var key = [ 0xdeadbeef, 0xcafebabe, 0x8badf00d, 0x1badb002 ]
54 | var k0 = { h: key[1] >>> 0, l: key[0] >>> 0 },
55 | k1 = { h: key[3] >>> 0, l: key[2] >>> 0 },
56 | v0 = { h: k0.h, l: k0.l }, v2 = k0,
57 | v1 = { h: k1.h, l: k1.l }, v3 = k1,
58 | mi, mp = 0, ml = m.length, ml7 = ml - 7,
59 | buf = new Uint8Array(new ArrayBuffer(8));
60 |
61 | _xor(v0, { h: 0x736f6d65, l: 0x70736575 });
62 | _xor(v1, { h: 0x646f7261, l: 0x6e646f83 });
63 | _xor(v2, { h: 0x6c796765, l: 0x6e657261 });
64 | _xor(v3, { h: 0x74656462, l: 0x79746573 });
65 | while (mp < ml7) {
66 | mi = { h: _get_int(m, mp + 4), l: _get_int(m, mp) };
67 | _xor(v3, mi);
68 | _compress(v0, v1, v2, v3);
69 | _compress(v0, v1, v2, v3);
70 | _xor(v0, mi);
71 | mp += 8;
72 | }
73 | buf[7] = ml;
74 | var ic = 0;
75 | while (mp < ml) {
76 | buf[ic++] = m[mp++];
77 | }
78 | while (ic < 7) {
79 | buf[ic++] = 0;
80 | }
81 | mi = { h: buf[7] << 24 | buf[6] << 16 | buf[5] << 8 | buf[4],
82 | l: buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0] };
83 | _xor(v3, mi);
84 | _compress(v0, v1, v2, v3);
85 | _compress(v0, v1, v2, v3);
86 | _xor(v0, mi);
87 | _xor(v2, { h: 0, l: 0xee });
88 | _compress(v0, v1, v2, v3);
89 | _compress(v0, v1, v2, v3);
90 | _compress(v0, v1, v2, v3);
91 | _compress(v0, v1, v2, v3);
92 |
93 | var hh = { h: v0.h , l: v0.l };
94 | _xor(hh, v1);
95 | _xor(hh, v2);
96 | _xor(hh, v3);
97 | _xor(v1, { h: 0, l: 0xdd });
98 | _compress(v0, v1, v2, v3);
99 | _compress(v0, v1, v2, v3);
100 | _compress(v0, v1, v2, v3);
101 | _compress(v0, v1, v2, v3);
102 | var hl = v0;
103 | _xor(hl, v1);
104 | _xor(hl, v2);
105 | _xor(hl, v3);
106 |
107 | return [hl.h, hl.l, hh.h, hh.l];
108 | }
109 |
110 | function string16_to_key(a) {
111 | return [_get_int(a, 0), _get_int(a, 4),
112 | _get_int(a, 8), _get_int(a, 12)];
113 | }
114 | function hash_uint(key, m) {
115 | var r = hash(key, m);
116 | return (r.h & 0x1fffff) * 0x100000000 + r.l;
117 | }
118 |
119 | this.lib = {
120 | string16_to_key: string16_to_key,
121 | hash: hash,
122 | hash_uint: hash_uint
123 | };
124 | }
125 |
126 | if(((typeof require) != "undefined") &&
127 | ((typeof module) != "undefined") &&
128 | ((typeof module.exports) != "undefined"))
129 | module.exports = SipHash;
--------------------------------------------------------------------------------
/public/js/back.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by xiaohe on 2016/12/12.
3 | */
4 | /**
5 | * Create a patch document that contains all the information needed to bring the destination data into synchronization with the source data.
6 | *
7 | * The patch document looks like this: (little Endian)
8 | * 4 bytes - blockSize
9 | * 4 bytes - number of patches
10 | * 4 bytes - number of matched blocks
11 | * For each matched block:
12 | * 4 bytes - the index of the matched block
13 | * For each patch:
14 | * 4 bytes - last matching block index. NOTE: This is 1 based index! Zero indicates beginning of file, NOT the first block
15 | * 4 bytes - patch size
16 | * n bytes - new data
17 | */
18 | function createPatchDocument(checksumDocument, data)
19 | {
20 | function appendBuffer( buffer1, buffer2 ) {
21 | var tmp = new Uint8Array( buffer1.byteLength + buffer2.byteLength );
22 | tmp.set( new Uint8Array( buffer1 ), 0 );
23 | tmp.set( new Uint8Array( buffer2 ), buffer1.byteLength );
24 | return tmp.buffer;
25 | }
26 |
27 | /**
28 | * First, check to see if there's a match on the 16 bit hash
29 | * Then, look through all the entries in the hashtable row for an adler 32 match.
30 | * Finally, do a strong md5 comparison
31 | */
32 | function checkMatch(adlerInfo, hashTable, block)
33 | {
34 | var hash = hash16(adlerInfo.checksum);
35 | if(!(hashTable[hash])) return false;
36 | var row = hashTable[hash];
37 | var i=0;
38 | var matchedIndex=0;
39 |
40 | for(i=0; i data.byteLength)
90 | {
91 | chunkSize = data.byteLength - i;
92 | adlerInfo=null; //need to reset this because the rolling checksum doesn't work correctly on a final non-aligned block
93 | }
94 | else
95 | chunkSize = blockSize;
96 |
97 | if(adlerInfo)
98 | adlerInfo = rollingChecksum(adlerInfo, i, i + chunkSize - 1, dataUint8);
99 | else
100 | adlerInfo = adler32(i, i + chunkSize - 1, dataUint8);
101 |
102 | var matchedBlock = checkMatch(adlerInfo, hashTable, new Uint8Array(data,i,chunkSize));
103 | if(matchedBlock)
104 | {
105 | //if we have a match, do the following:
106 | //1) add the matched block index to our tracking buffer
107 | //2) check to see if there's a current patch. If so, add it to the patch document.
108 | //3) jump forward blockSize bytes and continue
109 | matchedBlocksUint32[matchCount] = matchedBlock;
110 | matchCount++;
111 | //check to see if we need more memory for the matched blocks
112 | if(matchCount >= matchedBlocksUint32.length)
113 | {
114 | matchedBlocks = appendBuffer(matchedBlocks, new ArrayBuffer(1000));
115 | matchedBlocksUint32 = new Uint32Array(matchedBlocks);
116 | }
117 | if(currentPatchSize > 0)
118 | {
119 | //create the patch and append it to the patches buffer
120 | patch = new ArrayBuffer(4 + 4); //4 for last match index, 4 for patch size
121 | var patchUint32 = new Uint32Array(patch,0,2);
122 | patchUint32[0] = lastMatchIndex;
123 | patchUint32[1] = currentPatchSize;
124 | patch = appendBuffer(patch,currentPatch.slice(0,currentPatchSize));
125 | patches = appendBuffer(patches, patch);
126 | currentPatch = new ArrayBuffer(1000);
127 | currentPatchUint8 = new Uint8Array(currentPatch);
128 | currentPatchSize = 0;
129 | numPatches++;
130 | }
131 | lastMatchIndex = matchedBlock;
132 | i+=blockSize;
133 | if(i >= dataUint8.length -1 ) break;
134 | adlerInfo=null;
135 | continue;
136 | }
137 | else
138 | {
139 | //while we don't have a block match, append bytes to the current patch
140 | currentPatchUint8[currentPatchSize] = dataUint8[i];
141 | currentPatchSize++;
142 | if(currentPatchSize >= currentPatch.byteLength)
143 | {
144 | //allocate another 1000 bytes
145 | currentPatch = appendBuffer(currentPatch, new ArrayBuffer(1000));
146 | currentPatchUint8 = new Uint8Array(currentPatch);
147 | }
148 | }
149 | if((i) >= dataUint8.length -1) break;
150 | i++;
151 | } //end for each byte in the data
152 | if(currentPatchSize > 0)
153 | {
154 | //create the patch and append it to the patches buffer
155 | patch = new ArrayBuffer(4 + 4); //4 for last match index, 4 for patch size
156 | var patchUint32 = new Uint32Array(patch,0,2);
157 | patchUint32[0] = lastMatchIndex;
158 | patchUint32[1] = currentPatchSize;
159 | patch = appendBuffer(patch,currentPatch.slice(0,currentPatchSize));
160 | patches = appendBuffer(patches, patch);
161 | numPatches++;
162 | }
163 |
164 | var patchDocumentView32 = new Uint32Array(patchDocument);
165 | patchDocumentView32[0] = blockSize;
166 | patchDocumentView32[1] = numPatches;
167 | patchDocumentView32[2] = matchCount;
168 | patchDocument = appendBuffer(patchDocument, matchedBlocks.slice(0,matchCount * 4));
169 | patchDocument = appendBuffer(patchDocument, patches);
170 |
171 | var patchDocumentView32 = new Uint32Array(patchDocument,0,matchCount + 3);
172 | var patchDocumentView8 = new Uint8Array(patchDocument);
173 |
174 | return patchDocument;
175 | }
--------------------------------------------------------------------------------
/public/js/sync-client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by xiaohe on 2016/12/9.
3 | * client functions for web-sync
4 | */
5 |
6 | // Check for the various File API support.
7 | if (window.File && window.FileReader && window.FileList && window.Blob) {
8 | // Great success! All the File APIs are supported.
9 | console.log("Great success! All the File APIs are supported.")
10 | } else {
11 | alert('The File APIs are not fully supported in this browser.');
12 | }
13 |
14 | var lock = true;
15 | var current_file = null;
16 | var block_size = 64 *1024;
17 | var chunkSize = 1024 * 1024 * 1024; // bytes
18 | var timetamp;
19 | var checksum_timetamp;
20 | var test_start_time = (new Date()).getTime();
21 | var traffic;
22 |
23 | var test_hash_average = 0;
24 | var test_hash_times = 0;
25 |
26 | var socket = io.connect('http://'+window.location.hostname+':8001');
27 | socket.on('matchdoc',function(req){
28 | traffic += req.matchdoc.byteLength;
29 | console.log("<= 0){
85 | data_offset += block_size;
86 | }
87 | else{
88 | if(patchsize < doc_offset+block_size + 4*2){
89 | patchdoc = appendBlock(patchdoc,new ArrayBuffer(patchsize+block_size));
90 | patchdoc32View = new Uint32Array(patchdoc);
91 | patchdoc8View = new Uint8Array(patchdoc);
92 | patchsize += patchsize + block_size;
93 | }
94 | //not match save into patch
95 | numPatch++;
96 | patchdoc32View[doc_offset/4] = block_index;
97 | doc_offset+=4;
98 | var current_blocksize = block_size;
99 | if(data.byteLength - data_offset < block_size){
100 | current_blocksize = data.byteLength - data_offset;
101 | }
102 | patchdoc32View[doc_offset/4] = current_blocksize;
103 | doc_offset+=4;
104 | for(j = 0; j < current_blocksize;j++){
105 | patchdoc8View[doc_offset] = data8View[data_offset+j];
106 | doc_offset++;
107 | }
108 | data_offset += current_blocksize;
109 | //if doc_offset is not 4-times
110 | doc_offset = Math.ceil(doc_offset/4)*4;
111 |
112 | }
113 | block_index++;
114 | }
115 | patchdoc32View[1] = numPatch;
116 | var d = new Date();
117 | var t = d.getTime() - checksum_timetamp.getTime();
118 | console.info(current_file.name,'patchdoc time is',t,'ms');
119 | console.log('patchdoc from',start,'to',stop,':',doc_offset,current_file.size);
120 |
121 | //emit the patchdoc
122 | traffic += doc_offset;
123 | socket.emit('patchdoc', {'filename':current_file.name,'patchdoc':patchdoc.slice(0,doc_offset),'numChunk':numChunk});
124 | })
125 |
126 | }
127 |
128 | /*
129 | * parse file
130 | */
131 | function parseFile(file, callback) {
132 | var fileSize = file.size;
133 |
134 | var offset = 0;
135 | var self = this; // we need a reference to the current object
136 | var chunkReaderBlock = null;
137 |
138 | var readEventHandler = function(evt) {
139 | if (evt.target.error == null) {
140 | var start = offset
141 | offset += evt.target.result.byteLength;
142 | var stop = offset
143 | callback('data',evt.target.result,start,stop); // callback for handling read chunk
144 |
145 | } else {
146 | console.log("Read error: " + evt.target.error);
147 | return;
148 | }
149 | if (offset >= fileSize) {
150 | // console.log("Done reading file");
151 | return;
152 | }
153 | chunkReaderBlock(offset, chunkSize, file);
154 | }
155 |
156 | chunkReaderBlock = function(_offset, length, _file) {
157 | var r = new FileReader();
158 | var start = _offset;
159 | var stop = start + length;
160 | if(stop > _file.size) stop = _file.size;
161 | if (file.webkitSlice) {
162 | var blob = file.webkitSlice(start, stop);
163 | } else if (file.mozSlice) {
164 | var blob = file.mozSlice(start, stop );
165 | }else if(file.slice) {
166 | blob = file.slice(start, stop);
167 | }
168 | r.onloadend = readEventHandler;
169 | r.readAsArrayBuffer(blob);
170 | }
171 |
172 | // now let's start the read with the first block
173 | chunkReaderBlock(offset, chunkSize, file);
174 | }
175 | /*
176 | * load blocks from file
177 | * @param: block_size : bytes
178 | */
179 | function load_blocks() {
180 | // block_size = blockSize;
181 | if(lock) {
182 | lock = false;
183 | traffic = 0;
184 | $("#result").text("同步开始");
185 | timetamp = new Date();
186 | }
187 |
188 | else{
189 | console.log('wait for lock of parsing file');
190 | return;
191 | }
192 |
193 | var files = document.getElementById('files').files;
194 | if (!files.length) {
195 | alert('Please select a file!');
196 | return;
197 | }
198 | current_file = files[0];
199 |
200 | var all_numBlocks = Math.ceil(current_file.size / block_size);
201 | var i=0;
202 | var all_docLength =
203 | 4 + //4 bytes for block size
204 | 4 + //4 bytes for the number of blocks
205 | 4 + // 4 bytes for bytelength
206 | ( all_numBlocks * //the number of blocks times
207 | ( 4 + //the 4 bytes for the adler32 plus
208 | 16) //the 16 bytes for the md5
209 | )
210 | var all_checksumdoc = new ArrayBuffer(all_docLength);
211 | var all_docview = new Uint32Array(all_checksumdoc);
212 | all_docview[0] = block_size;
213 | all_docview[1] = all_numBlocks;
214 | all_bytelength = 0;
215 | var doc_offset = 3;
216 | parseFile(current_file,function(type,data,start,stop){
217 | var checksumstart = new Date().getTime();
218 | checksumdoc = BSync.createChecksumDocument(block_size,data);
219 | var docView = new Uint32Array(checksumdoc);
220 | numBlocks = docView[1];
221 | all_bytelength += docView[2];
222 | for(i = 0; i < numBlocks*(1+4);i++){
223 | all_docview[doc_offset + i] = docView[i+3];
224 | }
225 | doc_offset += numBlocks*(1+4);
226 |
227 | console.log('checksum from',start,'to',stop,':',doc_offset,"/",all_docLength/4);
228 |
229 | if(doc_offset == all_docLength/4){
230 | all_docview[2] = all_bytelength;
231 | console.log('all checksum length is ',all_docLength);
232 | console.log('>>emit checksum doc',all_docLength);
233 | traffic += all_checksumdoc.byteLength;
234 | d = new Date();
235 | t = d.getTime() - checksumstart;
236 | console.log('checksum time is',t,'ms');
237 | checksum_timetamp = d;
238 | socket.emit('checksumdoc', {'filename':current_file.name,'checksumdoc':all_checksumdoc});
239 | // lock = true;
240 |
241 | test_hash_average += t;
242 | test_hash_times ++;
243 | console.log('average time is',test_hash_average/test_hash_times,'ms');
244 |
245 | }
246 | })
247 | }
248 | var test_handler = null;
249 | var sync_handler = null;
250 | var test_time = 0;
251 | function test(){
252 | d = new Date();
253 | test_time = d.getTime() - test_start_time;
254 | console.info(test_time);
255 | }
256 | function start_test(){
257 |
258 | test_start_time = (new Date()).getTime();
259 | if(!test_handler){
260 | console.log('start_test');
261 | test_handler = setInterval(function(){ test(); }, 100);
262 | sync_handler = setTimeout(load_blocks,200);
263 | }else{
264 | clearInterval(test_handler);
265 | test_handler = null;
266 | sync_handler = null;
267 | console.log('stop_test');
268 | }
269 | }
270 |
271 | function stop_test(){
272 | if(test_handler){
273 | clearInterval(test_handler);
274 | test_handler = null;
275 | sync_handler = null;
276 | console.log('stop_test');
277 | }
278 | }
279 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 | var fs = require("fs");
8 | var OSS = require('ali-oss');
9 | var co = require('co');
10 | var client = new OSS({
11 | region: 'oss-cn-shanghai',
12 | accessKeyId: 'LTAIiTUIWMffMbLD',
13 | accessKeySecret: 'Ykcf2pSp3uTP9IKCqqRHzJXMgDwQzC',
14 | bucket:'xiaohe-websync',
15 | internal:true,
16 | endpoint:'oss-cn-shanghai-internal.aliyuncs.com',
17 | });
18 |
19 | var index = require('./routes/index');
20 | var users = require('./routes/users');
21 | var BSync = require('./public/js/bit-sync');
22 | var arrayBufferToBuffer = require('arraybuffer-to-buffer');
23 |
24 | var stream = require('stream');
25 | var streamToBuffer = require('stream-to-buffer')
26 |
27 |
28 | var basePath = __dirname + "/upload/";
29 |
30 | var app = express();
31 |
32 | var server = require('http').Server(app);
33 | var io = require('socket.io')(server);
34 |
35 | var direct_stream = false;
36 |
37 | server.listen(8001);
38 |
39 | /* match_cache = [filename1:(1234 bytes,matchdoc],
40 | }
41 | */
42 | var match_cache = {};
43 | var patch_cache = {};
44 | var patch_num_cache = {};
45 |
46 | var origin_file_cache = {};
47 |
48 | // view engine setup
49 | app.set('views', path.join(__dirname, 'views'));
50 | app.set('view engine', 'ejs');
51 |
52 | // uncomment after placing your favicon in /public
53 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
54 | app.use(logger('dev'));
55 | app.use(bodyParser.json());
56 | app.use(bodyParser.urlencoded({ extended: false }));
57 | app.use(cookieParser());
58 | app.use(express.static(path.join(__dirname, 'public')));
59 |
60 | app.use('/', index);
61 | app.use('/users', users);
62 |
63 | // catch 404 and forward to error handler
64 | app.use(function(req, res, next) {
65 | var err = new Error('Not Found');
66 | err.status = 404;
67 | next(err);
68 | });
69 |
70 | // error handler
71 | app.use(function(err, req, res, next) {
72 | // set locals, only providing error in development
73 | res.locals.message = err.message;
74 | res.locals.error = req.app.get('env') === 'development' ? err : {};
75 |
76 | // render the error page
77 | res.status(err.status || 500);
78 | res.render('error');
79 | });
80 |
81 | io.on('connection', function(socket)
82 | {
83 | console.log('new connect!');
84 | socket.on('checksumdoc', function(req)
85 | {
86 |
87 | console.log('got checksumdoc of filename:',req.filename);
88 | filePath = basePath + req.filename;
89 |
90 | checksumdocView = new Uint8Array(req.checksumdoc);
91 | checksumdocBuffer = checksumdocView.buffer;
92 |
93 | if(direct_stream){
94 | co(function * () {
95 | client.useBucket('xiaohe-websync');
96 | var result = yield client.getStream(req.filename);
97 | streamToBuffer(result.stream, function (err, buffer) {
98 | origin_file_cache[req.filename] = buffer
99 | matchret = BSync.createMatchDocument(checksumdocBuffer,buffer);
100 | matchdoc = matchret[0];
101 | filebytelength = matchret[1];
102 | match_cache[req.filename] = [filebytelength,matchdoc];
103 | socket.emit('matchdoc',{filename:req.filename,matchdoc:matchdoc});
104 | })
105 | }).catch(function (err) {
106 | console.log(err);
107 | origin_file_cache[req.filename] = new ArrayBuffer(0);
108 | matchret = BSync.createMatchDocument(checksumdocBuffer,new ArrayBuffer(0));
109 | matchdoc = matchret[0];
110 | filebytelength = matchret[1];
111 | match_cache[req.filename] = [filebytelength,matchdoc];
112 | socket.emit('matchdoc',{filename:req.filename,matchdoc:matchdoc});
113 | });
114 | }else{
115 | fs.stat(filePath, function (err,stat) {
116 |
117 | if (err == null) {
118 | getFileData(filePath,function(data){
119 | origin_file_cache[req.filename] = data
120 | matchret = BSync.createMatchDocument(checksumdocBuffer,data);
121 | matchdoc = matchret[0];
122 | filebytelength = matchret[1];
123 | match_cache[req.filename] = [filebytelength,matchdoc];
124 | socket.emit('matchdoc',{filename:req.filename,matchdoc:matchdoc});
125 | })
126 | } else {
127 | origin_file_cache[req.filename] = new ArrayBuffer(0);
128 | matchret = BSync.createMatchDocument(checksumdocBuffer,new ArrayBuffer(0));
129 | matchdoc = matchret[0];
130 | filebytelength = matchret[1];
131 | match_cache[req.filename] = [filebytelength,matchdoc];
132 | socket.emit('matchdoc',{filename:req.filename,matchdoc:matchdoc});
133 | }
134 | });
135 | }
136 | });
137 |
138 | socket.on('patchdoc',function(req){
139 | console.log('patchdoc of',req.filename);
140 |
141 | //todo combine patch doc and matched blocks
142 | var matchdoc = match_cache[req.filename][1];
143 | var filebytelength = match_cache[req.filename][0];
144 | var matchtable = BSync.parseMatchDocument(matchdoc);
145 | filePath = basePath + req.filename;
146 | var newFilebuffer = new ArrayBuffer(filebytelength);
147 | var file8View = new Uint8Array(newFilebuffer);
148 | if(!patch_cache[req.filename]) {
149 | patch_cache[req.filename] = {};
150 | patch_num_cache[req.filename] = 0;
151 | }
152 |
153 | parsePatchDoc(req.filename,req.patchdoc,function(blocksize){
154 | if(patch_num_cache[req.filename] == req.numChunk){
155 | data = origin_file_cache[req.filename];
156 | var data8View = new Uint8Array(data);
157 | numBlocks = Math.ceil(filebytelength/blocksize);
158 | dataoffset = 0;
159 | for(i = 1; i <= numBlocks;i++){
160 | //i is blockindex
161 | if(matchtable[i] >= 0){
162 | matchoffset = matchtable[i];
163 | // for(j = 0;j < blocksize && (j+matchoffset) < data.length;j++){
164 | // file8View[dataoffset++] = data8View[matchoffset+j];
165 | // }
166 | var b_size = Math.min(blocksize,data.length - matchoffset);
167 | file8View.set(data8View.slice(matchoffset,matchoffset+b_size),dataoffset);
168 | dataoffset += b_size;
169 | }else{
170 | blockcontent = patch_cache[req.filename][i];
171 | block8View = new Uint8Array(blockcontent);
172 | // for(j = 0; j < blockcontent.byteLength;j++){
173 | // file8View[dataoffset++] = block8View[j];
174 | // }
175 | file8View.set(block8View,dataoffset);
176 | dataoffset += block8View.length;
177 |
178 | }
179 | }
180 | if(direct_stream){
181 | co(function * () {
182 | client.useBucket('xiaohe-websync');
183 | var bufferStream = new stream.PassThrough();
184 | bufferStream.end(arrayBufferToBuffer(newFilebuffer));
185 | var result = yield client.putStream(req.filename,bufferStream);
186 | if(result['res']['status'] == 200){
187 | console.log('file write over~');
188 | BlockSyncStatus = 'success';
189 | socket.emit('SyncOver', BlockSyncStatus);
190 | //reset cache
191 | delete match_cache[req.filename]
192 | delete patch_num_cache[req.filename]
193 | delete patch_cache[req.filename]
194 | }
195 | }).catch(function (err) {
196 | console.log(err);
197 | });
198 | }else{
199 | fs.writeFile(filePath,arrayBufferToBuffer(newFilebuffer),function(err){
200 | if (err){
201 | throw 'error writing file: ' + err;
202 | }
203 | else{
204 | console.log('file write over~');
205 | BlockSyncStatus = 'success';
206 | socket.emit('SyncOver', BlockSyncStatus);
207 |
208 | console.log('冲突:',BSync.hash16_coll);
209 | }
210 | //reset cache
211 | delete match_cache[req.filename]
212 | delete patch_num_cache[req.filename]
213 | delete patch_cache[req.filename]
214 | })
215 | }
216 | }
217 | });
218 | })
219 | });
220 | function parsePatchDoc(filename,patchdoc,callback){
221 | var patchdoc8View = new Uint8Array(patchdoc);
222 | var patchdoc32View = new Uint32Array(patchdoc8View.buffer);
223 | var patch_offset = 2;
224 | var blocksize = patchdoc32View[0];
225 | var numPatch = patchdoc32View[1];
226 | // var patchtable = {};
227 | for(i = 0; i < numPatch;i++){
228 | var blockindex = patchdoc32View[patch_offset];
229 | patch_offset++;
230 | var currentblocksize = patchdoc32View[patch_offset];
231 | patch_offset++;
232 | var filecontent = new ArrayBuffer(currentblocksize);
233 | var file8View = new Uint8Array(filecontent);
234 | for(j = 0;j < currentblocksize;j++){
235 | file8View[j] = patchdoc8View[patch_offset*4+j];
236 | }
237 | patch_offset += Math.ceil(j/4);
238 | patch_cache[filename][blockindex] = filecontent;
239 | }
240 | patch_num_cache[filename]++;
241 | callback(blocksize);
242 | }
243 |
244 | // 在服务器端读取文件
245 | function getFileData(file, callback)
246 | {
247 | fs.readFile(file, function(err, data) {
248 | if (err) {
249 | // console.error("Error getting file data: " + err);
250 | }
251 | callback(data);
252 | });
253 | }
254 |
255 |
256 | module.exports = app;
257 |
--------------------------------------------------------------------------------
/public/js/md5.js:
--------------------------------------------------------------------------------
1 | /*
2 | * JavaScript MD5
3 | * https://github.com/blueimp/JavaScript-MD5
4 | *
5 | * Copyright 2011, Sebastian Tschan
6 | * https://blueimp.net
7 | *
8 | * Licensed under the MIT license:
9 | * http://www.opensource.org/licenses/MIT
10 | *
11 | * Based on
12 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
13 | * Digest Algorithm, as defined in RFC 1321.
14 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
15 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16 | * Distributed under the BSD License
17 | * See http://pajhome.org.uk/crypt/md5 for more info.
18 | */
19 |
20 | /* global define */
21 |
22 | ;(function ($) {
23 | 'use strict'
24 |
25 | /*
26 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
27 | * to work around bugs in some JS interpreters.
28 | */
29 | function safeAdd (x, y) {
30 | var lsw = (x & 0xFFFF) + (y & 0xFFFF)
31 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
32 | return (msw << 16) | (lsw & 0xFFFF)
33 | }
34 |
35 | /*
36 | * Bitwise rotate a 32-bit number to the left.
37 | */
38 | function bitRotateLeft (num, cnt) {
39 | return (num << cnt) | (num >>> (32 - cnt))
40 | }
41 |
42 | /*
43 | * These functions implement the four basic operations the algorithm uses.
44 | */
45 | function md5cmn (q, a, b, x, s, t) {
46 | return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
47 | }
48 | function md5ff (a, b, c, d, x, s, t) {
49 | return md5cmn((b & c) | ((~b) & d), a, b, x, s, t)
50 | }
51 | function md5gg (a, b, c, d, x, s, t) {
52 | return md5cmn((b & d) | (c & (~d)), a, b, x, s, t)
53 | }
54 | function md5hh (a, b, c, d, x, s, t) {
55 | return md5cmn(b ^ c ^ d, a, b, x, s, t)
56 | }
57 | function md5ii (a, b, c, d, x, s, t) {
58 | return md5cmn(c ^ (b | (~d)), a, b, x, s, t)
59 | }
60 |
61 | /*
62 | * Calculate the MD5 of an array of little-endian words, and a bit length.
63 | */
64 | function binlMD5 (x, len) {
65 | /* append padding */
66 | x[len >> 5] |= 0x80 << (len % 32)
67 | x[(((len + 64) >>> 9) << 4) + 14] = len
68 |
69 | var i
70 | var olda
71 | var oldb
72 | var oldc
73 | var oldd
74 | var a = 1732584193
75 | var b = -271733879
76 | var c = -1732584194
77 | var d = 271733878
78 |
79 | for (i = 0; i < x.length; i += 16) {
80 | olda = a
81 | oldb = b
82 | oldc = c
83 | oldd = d
84 |
85 | a = md5ff(a, b, c, d, x[i], 7, -680876936)
86 | d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
87 | c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
88 | b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
89 | a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
90 | d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
91 | c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
92 | b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
93 | a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
94 | d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
95 | c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
96 | b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
97 | a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
98 | d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
99 | c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
100 | b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)
101 |
102 | a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
103 | d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
104 | c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
105 | b = md5gg(b, c, d, a, x[i], 20, -373897302)
106 | a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
107 | d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
108 | c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
109 | b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
110 | a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
111 | d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
112 | c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
113 | b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
114 | a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
115 | d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
116 | c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473)
117 | b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)
118 |
119 | a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
120 | d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
121 | c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
122 | b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
123 | a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
124 | d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
125 | c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
126 | b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
127 | a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
128 | d = md5hh(d, a, b, c, x[i], 11, -358537222)
129 | c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
130 | b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
131 | a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
132 | d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
133 | c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
134 | b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)
135 |
136 | a = md5ii(a, b, c, d, x[i], 6, -198630844)
137 | d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
138 | c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
139 | b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
140 | a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
141 | d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
142 | c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
143 | b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
144 | a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
145 | d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
146 | c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
147 | b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
148 | a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
149 | d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
150 | c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
151 | b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)
152 |
153 | a = safeAdd(a, olda)
154 | b = safeAdd(b, oldb)
155 | c = safeAdd(c, oldc)
156 | d = safeAdd(d, oldd)
157 | }
158 | return [a, b, c, d]
159 | }
160 |
161 | /*
162 | * Convert an array of little-endian words to a string
163 | */
164 | function binl2rstr (input) {
165 | var i
166 | var output = ''
167 | var length32 = input.length * 32
168 | for (i = 0; i < length32; i += 8) {
169 | output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF)
170 | }
171 | return output
172 | }
173 |
174 | /*
175 | * Convert a raw string to an array of little-endian words
176 | * Characters >255 have their high-byte silently ignored.
177 | */
178 | function rstr2binl (input) {
179 | var i
180 | var output = []
181 | output[(input.length >> 2) - 1] = undefined
182 | for (i = 0; i < output.length; i += 1) {
183 | output[i] = 0
184 | }
185 | var length8 = input.length * 8
186 | for (i = 0; i < length8; i += 8) {
187 | output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32)
188 | }
189 | return output
190 | }
191 |
192 | /*
193 | * Calculate the MD5 of a raw string
194 | */
195 | function rstrMD5 (s) {
196 | return binl2rstr(binlMD5(rstr2binl(s), s.length * 8))
197 | }
198 |
199 | /*
200 | * Calculate the HMAC-MD5, of a key and some data (raw strings)
201 | */
202 | function rstrHMACMD5 (key, data) {
203 | var i
204 | var bkey = rstr2binl(key)
205 | var ipad = []
206 | var opad = []
207 | var hash
208 | ipad[15] = opad[15] = undefined
209 | if (bkey.length > 16) {
210 | bkey = binlMD5(bkey, key.length * 8)
211 | }
212 | for (i = 0; i < 16; i += 1) {
213 | ipad[i] = bkey[i] ^ 0x36363636
214 | opad[i] = bkey[i] ^ 0x5C5C5C5C
215 | }
216 | hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8)
217 | return binl2rstr(binlMD5(opad.concat(hash), 512 + 128))
218 | }
219 |
220 | /*
221 | * Convert a raw string to a hex string
222 | */
223 | function rstr2hex (input) {
224 | var hexTab = '0123456789abcdef'
225 | var output = ''
226 | var x
227 | var i
228 | for (i = 0; i < input.length; i += 1) {
229 | x = input.charCodeAt(i)
230 | output += hexTab.charAt((x >>> 4) & 0x0F) +
231 | hexTab.charAt(x & 0x0F)
232 | }
233 | return output
234 | }
235 |
236 | /*
237 | * Encode a string as utf-8
238 | */
239 | function str2rstrUTF8 (input) {
240 | return unescape(encodeURIComponent(input))
241 | }
242 |
243 | /*
244 | * Take string arguments and return either raw or hex encoded strings
245 | */
246 | function rawMD5 (s) {
247 | return rstrMD5(str2rstrUTF8(s))
248 | }
249 | function hexMD5 (s) {
250 | return rstr2hex(rawMD5(s))
251 | }
252 | function rawHMACMD5 (k, d) {
253 | return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d))
254 | }
255 | function hexHMACMD5 (k, d) {
256 | return rstr2hex(rawHMACMD5(k, d))
257 | }
258 |
259 | function md5 (string, key, raw) {
260 | if (!key) {
261 | if (!raw) {
262 | return hexMD5(string)
263 | }
264 | return rawMD5(string)
265 | }
266 | if (!raw) {
267 | return hexHMACMD5(key, string)
268 | }
269 | return rawHMACMD5(key, string)
270 | }
271 |
272 | if (typeof define === 'function' && define.amd) {
273 | define(function () {
274 | return md5
275 | })
276 | } else if (typeof module === 'object' && module.exports) {
277 | module.exports = md5
278 | } else {
279 | $.md5 = md5
280 | }
281 | }(this))
282 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/public/js/murmurhash3.js:
--------------------------------------------------------------------------------
1 | // +----------------------------------------------------------------------+
2 | // | murmurHash3.js v2.1.2 (http://github.com/karanlyons/murmurHash.js) |
3 | // | A javascript implementation of MurmurHash3's x86 hashing algorithms. |
4 | // |----------------------------------------------------------------------|
5 | // | Copyright (c) 2012 Karan Lyons |
6 | // | Freely distributable under the MIT license. |
7 | // +----------------------------------------------------------------------+
8 |
9 |
10 | var MMHASH3 = new function() {
11 |
12 | // Create a local object that'll be exported or referenced globally.
13 | var library = {
14 | 'version': '2.1.2',
15 | 'x86': {},
16 | 'x64': {}
17 | };
18 |
19 |
20 | // PRIVATE FUNCTIONS
21 | // -----------------
22 |
23 | function _x86Multiply(m, n) {
24 | //
25 | // Given two 32bit ints, returns the two multiplied together as a
26 | // 32bit int.
27 | //
28 |
29 | return ((m & 0xffff) * n) + ((((m >>> 16) * n) & 0xffff) << 16);
30 | }
31 |
32 |
33 | function _x86Rotl(m, n) {
34 | //
35 | // Given a 32bit int and an int representing a number of bit positions,
36 | // returns the 32bit int rotated left by that number of positions.
37 | //
38 |
39 | return (m << n) | (m >>> (32 - n));
40 | }
41 |
42 |
43 | function _x86Fmix(h) {
44 | //
45 | // Given a block, returns murmurHash3's final x86 mix of that block.
46 | //
47 |
48 | h ^= h >>> 16;
49 | h = _x86Multiply(h, 0x85ebca6b);
50 | h ^= h >>> 13;
51 | h = _x86Multiply(h, 0xc2b2ae35);
52 | h ^= h >>> 16;
53 |
54 | return h;
55 | }
56 |
57 |
58 | function _x64Add(m, n) {
59 | //
60 | // Given two 64bit ints (as an array of two 32bit ints) returns the two
61 | // added together as a 64bit int (as an array of two 32bit ints).
62 | //
63 |
64 | m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff];
65 | n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff];
66 | var o = [0, 0, 0, 0];
67 |
68 | o[3] += m[3] + n[3];
69 | o[2] += o[3] >>> 16;
70 | o[3] &= 0xffff;
71 |
72 | o[2] += m[2] + n[2];
73 | o[1] += o[2] >>> 16;
74 | o[2] &= 0xffff;
75 |
76 | o[1] += m[1] + n[1];
77 | o[0] += o[1] >>> 16;
78 | o[1] &= 0xffff;
79 |
80 | o[0] += m[0] + n[0];
81 | o[0] &= 0xffff;
82 |
83 | return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]];
84 | }
85 |
86 |
87 | function _x64Multiply(m, n) {
88 | //
89 | // Given two 64bit ints (as an array of two 32bit ints) returns the two
90 | // multiplied together as a 64bit int (as an array of two 32bit ints).
91 | //
92 |
93 | m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff];
94 | n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff];
95 | var o = [0, 0, 0, 0];
96 |
97 | o[3] += m[3] * n[3];
98 | o[2] += o[3] >>> 16;
99 | o[3] &= 0xffff;
100 |
101 | o[2] += m[2] * n[3];
102 | o[1] += o[2] >>> 16;
103 | o[2] &= 0xffff;
104 |
105 | o[2] += m[3] * n[2];
106 | o[1] += o[2] >>> 16;
107 | o[2] &= 0xffff;
108 |
109 | o[1] += m[1] * n[3];
110 | o[0] += o[1] >>> 16;
111 | o[1] &= 0xffff;
112 |
113 | o[1] += m[2] * n[2];
114 | o[0] += o[1] >>> 16;
115 | o[1] &= 0xffff;
116 |
117 | o[1] += m[3] * n[1];
118 | o[0] += o[1] >>> 16;
119 | o[1] &= 0xffff;
120 |
121 | o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]);
122 | o[0] &= 0xffff;
123 |
124 | return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]];
125 | }
126 |
127 |
128 | function _x64Rotl(m, n) {
129 | //
130 | // Given a 64bit int (as an array of two 32bit ints) and an int
131 | // representing a number of bit positions, returns the 64bit int (as an
132 | // array of two 32bit ints) rotated left by that number of positions.
133 | //
134 |
135 | n %= 64;
136 |
137 | if (n === 32) {
138 | return [m[1], m[0]];
139 | }
140 |
141 | else if (n < 32) {
142 | return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))];
143 | }
144 |
145 | else {
146 | n -= 32;
147 | return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))];
148 | }
149 | }
150 |
151 |
152 | function _x64LeftShift(m, n) {
153 | //
154 | // Given a 64bit int (as an array of two 32bit ints) and an int
155 | // representing a number of bit positions, returns the 64bit int (as an
156 | // array of two 32bit ints) shifted left by that number of positions.
157 | //
158 |
159 | n %= 64;
160 |
161 | if (n === 0) {
162 | return m;
163 | }
164 |
165 | else if (n < 32) {
166 | return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n];
167 | }
168 |
169 | else {
170 | return [m[1] << (n - 32), 0];
171 | }
172 | }
173 |
174 |
175 | function _x64Xor(m, n) {
176 | //
177 | // Given two 64bit ints (as an array of two 32bit ints) returns the two
178 | // xored together as a 64bit int (as an array of two 32bit ints).
179 | //
180 |
181 | return [m[0] ^ n[0], m[1] ^ n[1]];
182 | }
183 |
184 |
185 | function _x64Fmix(h) {
186 | //
187 | // Given a block, returns murmurHash3's final x64 mix of that block.
188 | // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the
189 | // only place where we need to right shift 64bit ints.)
190 | //
191 |
192 | h = _x64Xor(h, [0, h[0] >>> 1]);
193 | h = _x64Multiply(h, [0xff51afd7, 0xed558ccd]);
194 | h = _x64Xor(h, [0, h[0] >>> 1]);
195 | h = _x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]);
196 | h = _x64Xor(h, [0, h[0] >>> 1]);
197 |
198 | return h;
199 | }
200 |
201 |
202 | // PUBLIC FUNCTIONS
203 | // ----------------
204 |
205 | library.x86.hash32 = function (key, seed) {
206 | //
207 | // Given a string and an optional seed as an int, returns a 32 bit hash
208 | // using the x86 flavor of MurmurHash3, as an unsigned int.
209 | //
210 |
211 | key = key || '';
212 | seed = seed || 0;
213 |
214 | var remainder = key.length % 4;
215 | var bytes = key.length - remainder;
216 |
217 | var h1 = seed;
218 |
219 | var k1 = 0;
220 |
221 | var c1 = 0xcc9e2d51;
222 | var c2 = 0x1b873593;
223 |
224 | for (var i = 0; i < bytes; i = i + 4) {
225 | k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24);
226 |
227 | k1 = _x86Multiply(k1, c1);
228 | k1 = _x86Rotl(k1, 15);
229 | k1 = _x86Multiply(k1, c2);
230 |
231 | h1 ^= k1;
232 | h1 = _x86Rotl(h1, 13);
233 | h1 = _x86Multiply(h1, 5) + 0xe6546b64;
234 | }
235 |
236 | k1 = 0;
237 |
238 | switch (remainder) {
239 | case 3:
240 | k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
241 |
242 | case 2:
243 | k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
244 |
245 | case 1:
246 | k1 ^= (key.charCodeAt(i) & 0xff);
247 | k1 = _x86Multiply(k1, c1);
248 | k1 = _x86Rotl(k1, 15);
249 | k1 = _x86Multiply(k1, c2);
250 | h1 ^= k1;
251 | }
252 |
253 | h1 ^= key.length;
254 | h1 = _x86Fmix(h1);
255 |
256 | return h1 >>> 0;
257 | };
258 |
259 |
260 | library.x86.hash128 = function (key, seed) {
261 | //
262 | // Given a string and an optional seed as an int, returns a 128 bit
263 | // hash using the x86 flavor of MurmurHash3, as an unsigned hex.
264 | //
265 |
266 | key = key || '';
267 | seed = seed || 0;
268 |
269 | var remainder = key.length % 16;
270 | var bytes = key.length - remainder;
271 |
272 | var h1 = seed;
273 | var h2 = seed;
274 | var h3 = seed;
275 | var h4 = seed;
276 |
277 | var k1 = 0;
278 | var k2 = 0;
279 | var k3 = 0;
280 | var k4 = 0;
281 |
282 | var c1 = 0x239b961b;
283 | var c2 = 0xab0e9789;
284 | var c3 = 0x38b34ae5;
285 | var c4 = 0xa1e38b93;
286 |
287 | for (var i = 0; i < bytes; i = i + 16) {
288 | k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24);
289 | k2 = ((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24);
290 | k3 = ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24);
291 | k4 = ((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24);
292 |
293 | k1 = _x86Multiply(k1, c1);
294 | k1 = _x86Rotl(k1, 15);
295 | k1 = _x86Multiply(k1, c2);
296 | h1 ^= k1;
297 |
298 | h1 = _x86Rotl(h1, 19);
299 | h1 += h2;
300 | h1 = _x86Multiply(h1, 5) + 0x561ccd1b;
301 |
302 | k2 = _x86Multiply(k2, c2);
303 | k2 = _x86Rotl(k2, 16);
304 | k2 = _x86Multiply(k2, c3);
305 | h2 ^= k2;
306 |
307 | h2 = _x86Rotl(h2, 17);
308 | h2 += h3;
309 | h2 = _x86Multiply(h2, 5) + 0x0bcaa747;
310 |
311 | k3 = _x86Multiply(k3, c3);
312 | k3 = _x86Rotl(k3, 17);
313 | k3 = _x86Multiply(k3, c4);
314 | h3 ^= k3;
315 |
316 | h3 = _x86Rotl(h3, 15);
317 | h3 += h4;
318 | h3 = _x86Multiply(h3, 5) + 0x96cd1c35;
319 |
320 | k4 = _x86Multiply(k4, c4);
321 | k4 = _x86Rotl(k4, 18);
322 | k4 = _x86Multiply(k4, c1);
323 | h4 ^= k4;
324 |
325 | h4 = _x86Rotl(h4, 13);
326 | h4 += h1;
327 | h4 = _x86Multiply(h4, 5) + 0x32ac3b17;
328 | }
329 |
330 | k1 = 0;
331 | k2 = 0;
332 | k3 = 0;
333 | k4 = 0;
334 |
335 | switch (remainder) {
336 | case 15:
337 | k4 ^= key.charCodeAt(i + 14) << 16;
338 |
339 | case 14:
340 | k4 ^= key.charCodeAt(i + 13) << 8;
341 |
342 | case 13:
343 | k4 ^= key.charCodeAt(i + 12);
344 | k4 = _x86Multiply(k4, c4);
345 | k4 = _x86Rotl(k4, 18);
346 | k4 = _x86Multiply(k4, c1);
347 | h4 ^= k4;
348 |
349 | case 12:
350 | k3 ^= key.charCodeAt(i + 11) << 24;
351 |
352 | case 11:
353 | k3 ^= key.charCodeAt(i + 10) << 16;
354 |
355 | case 10:
356 | k3 ^= key.charCodeAt(i + 9) << 8;
357 |
358 | case 9:
359 | k3 ^= key.charCodeAt(i + 8);
360 | k3 = _x86Multiply(k3, c3);
361 | k3 = _x86Rotl(k3, 17);
362 | k3 = _x86Multiply(k3, c4);
363 | h3 ^= k3;
364 |
365 | case 8:
366 | k2 ^= key.charCodeAt(i + 7) << 24;
367 |
368 | case 7:
369 | k2 ^= key.charCodeAt(i + 6) << 16;
370 |
371 | case 6:
372 | k2 ^= key.charCodeAt(i + 5) << 8;
373 |
374 | case 5:
375 | k2 ^= key.charCodeAt(i + 4);
376 | k2 = _x86Multiply(k2, c2);
377 | k2 = _x86Rotl(k2, 16);
378 | k2 = _x86Multiply(k2, c3);
379 | h2 ^= k2;
380 |
381 | case 4:
382 | k1 ^= key.charCodeAt(i + 3) << 24;
383 |
384 | case 3:
385 | k1 ^= key.charCodeAt(i + 2) << 16;
386 |
387 | case 2:
388 | k1 ^= key.charCodeAt(i + 1) << 8;
389 |
390 | case 1:
391 | k1 ^= key.charCodeAt(i);
392 | k1 = _x86Multiply(k1, c1);
393 | k1 = _x86Rotl(k1, 15);
394 | k1 = _x86Multiply(k1, c2);
395 | h1 ^= k1;
396 | }
397 |
398 | h1 ^= key.length;
399 | h2 ^= key.length;
400 | h3 ^= key.length;
401 | h4 ^= key.length;
402 |
403 | h1 += h2;
404 | h1 += h3;
405 | h1 += h4;
406 | h2 += h1;
407 | h3 += h1;
408 | h4 += h1;
409 |
410 | h1 = _x86Fmix(h1);
411 | h2 = _x86Fmix(h2);
412 | h3 = _x86Fmix(h3);
413 | h4 = _x86Fmix(h4);
414 |
415 | h1 += h2;
416 | h1 += h3;
417 | h1 += h4;
418 | h2 += h1;
419 | h3 += h1;
420 | h4 += h1;
421 |
422 | return ("00000000" + (h1 >>> 0).toString(16)).slice(-8) + ("00000000" + (h2 >>> 0).toString(16)).slice(-8) + ("00000000" + (h3 >>> 0).toString(16)).slice(-8) + ("00000000" + (h4 >>> 0).toString(16)).slice(-8);
423 | };
424 | library.x86.hash128_arraybuffer = function (message, seed, offset,chunksize) {
425 | if(offset == null){
426 | offset = 0;
427 | chunksize = message.length;
428 | }
429 | key = message;
430 | seed = seed || 0;
431 |
432 | var remainder = chunksize % 16;
433 | var bytes = chunksize - remainder;
434 |
435 | var h1 = seed;
436 | var h2 = seed;
437 | var h3 = seed;
438 | var h4 = seed;
439 |
440 | var k1 = 0;
441 | var k2 = 0;
442 | var k3 = 0;
443 | var k4 = 0;
444 |
445 | var c1 = 0x239b961b;
446 | var c2 = 0xab0e9789;
447 | var c3 = 0x38b34ae5;
448 | var c4 = 0xa1e38b93;
449 |
450 | for (var i = offset; i < offset+bytes; i = i + 16) {
451 | k1 = ((key[i] & 0xff)) | ((key[i + 1] & 0xff) << 8) | ((key[i + 2] & 0xff) << 16) | ((key[i + 3] & 0xff) << 24);
452 | k2 = ((key[i + 4] & 0xff)) | ((key[i + 5] & 0xff) << 8) | ((key[i + 6] & 0xff) << 16) | ((key[i + 7] & 0xff) << 24);
453 | k3 = ((key[i + 8] & 0xff)) | ((key[i + 9] & 0xff) << 8) | ((key[i + 10] & 0xff) << 16) | ((key[i + 11] & 0xff) << 24);
454 | k4 = ((key[i + 12] & 0xff)) | ((key[i + 13] & 0xff) << 8) | ((key[i + 14] & 0xff) << 16) | ((key[i + 15] & 0xff) << 24);
455 |
456 | k1 = _x86Multiply(k1, c1);
457 | k1 = _x86Rotl(k1, 15);
458 | k1 = _x86Multiply(k1, c2);
459 | h1 ^= k1;
460 |
461 | h1 = _x86Rotl(h1, 19);
462 | h1 += h2;
463 | h1 = _x86Multiply(h1, 5) + 0x561ccd1b;
464 |
465 | k2 = _x86Multiply(k2, c2);
466 | k2 = _x86Rotl(k2, 16);
467 | k2 = _x86Multiply(k2, c3);
468 | h2 ^= k2;
469 |
470 | h2 = _x86Rotl(h2, 17);
471 | h2 += h3;
472 | h2 = _x86Multiply(h2, 5) + 0x0bcaa747;
473 |
474 | k3 = _x86Multiply(k3, c3);
475 | k3 = _x86Rotl(k3, 17);
476 | k3 = _x86Multiply(k3, c4);
477 | h3 ^= k3;
478 |
479 | h3 = _x86Rotl(h3, 15);
480 | h3 += h4;
481 | h3 = _x86Multiply(h3, 5) + 0x96cd1c35;
482 |
483 | k4 = _x86Multiply(k4, c4);
484 | k4 = _x86Rotl(k4, 18);
485 | k4 = _x86Multiply(k4, c1);
486 | h4 ^= k4;
487 |
488 | h4 = _x86Rotl(h4, 13);
489 | h4 += h1;
490 | h4 = _x86Multiply(h4, 5) + 0x32ac3b17;
491 | }
492 |
493 | k1 = 0;
494 | k2 = 0;
495 | k3 = 0;
496 | k4 = 0;
497 |
498 | switch (remainder) {
499 | case 15:
500 | k4 ^= key[i + 14] << 16;
501 |
502 | case 14:
503 | k4 ^= key[i + 13] << 8;
504 |
505 | case 13:
506 | k4 ^= key[i + 12];
507 | k4 = _x86Multiply(k4, c4);
508 | k4 = _x86Rotl(k4, 18);
509 | k4 = _x86Multiply(k4, c1);
510 | h4 ^= k4;
511 |
512 | case 12:
513 | k3 ^= key[i + 11] << 24;
514 |
515 | case 11:
516 | k3 ^= key[i + 10] << 16;
517 |
518 | case 10:
519 | k3 ^= key[i + 9] << 8;
520 |
521 | case 9:
522 | k3 ^= key[i + 8];
523 | k3 = _x86Multiply(k3, c3);
524 | k3 = _x86Rotl(k3, 17);
525 | k3 = _x86Multiply(k3, c4);
526 | h3 ^= k3;
527 |
528 | case 8:
529 | k2 ^= key[i + 7] << 24;
530 |
531 | case 7:
532 | k2 ^= key[i + 6] << 16;
533 |
534 | case 6:
535 | k2 ^= key[i + 5] << 8;
536 |
537 | case 5:
538 | k2 ^= key[i + 4];
539 | k2 = _x86Multiply(k2, c2);
540 | k2 = _x86Rotl(k2, 16);
541 | k2 = _x86Multiply(k2, c3);
542 | h2 ^= k2;
543 |
544 | case 4:
545 | k1 ^= key[i + 3] << 24;
546 |
547 | case 3:
548 | k1 ^= key[i + 2] << 16;
549 |
550 | case 2:
551 | k1 ^= key[i + 1] << 8;
552 |
553 | case 1:
554 | k1 ^= key[i];
555 | k1 = _x86Multiply(k1, c1);
556 | k1 = _x86Rotl(k1, 15);
557 | k1 = _x86Multiply(k1, c2);
558 | h1 ^= k1;
559 | }
560 |
561 | // h1 ^= key.length;
562 | // h2 ^= key.length;
563 | // h3 ^= key.length;
564 | // h4 ^= key.length;
565 | h1 ^= chunksize;
566 | h2 ^= chunksize;
567 | h3 ^= chunksize;
568 | h4 ^= chunksize;
569 |
570 | h1 += h2;
571 | h1 += h3;
572 | h1 += h4;
573 | h2 += h1;
574 | h3 += h1;
575 | h4 += h1;
576 |
577 | h1 = _x86Fmix(h1);
578 | h2 = _x86Fmix(h2);
579 | h3 = _x86Fmix(h3);
580 | h4 = _x86Fmix(h4);
581 |
582 | h1 += h2;
583 | h1 += h3;
584 | h1 += h4;
585 | h2 += h1;
586 | h3 += h1;
587 | h4 += h1;
588 | // console.log('md5',offset,chunksize,new Uint32Array([h1,h2,h3,h4]));
589 | return new Uint32Array([h1,h2,h3,h4]);
590 | // return ("00000000" + (h1 >>> 0).toString(16)).slice(-8) + ("00000000" + (h2 >>> 0).toString(16)).slice(-8) + ("00000000" + (h3 >>> 0).toString(16)).slice(-8) + ("00000000" + (h4 >>> 0).toString(16)).slice(-8);
591 | };
592 | library.x64.hash128_arraybuffer = function(message,seed){
593 | //message is arraybuffer
594 | key = new Uint8Array(message);
595 | seed = seed || 0;
596 |
597 | var remainder = key.length % 16;
598 | var bytes = key.length - remainder;
599 |
600 | // var h1 = [0, seed];
601 | // var h2 = [0, seed];
602 |
603 | // var k1 = [0, 0];
604 | // var k2 = [0, 0];
605 | // var k1,k2;
606 |
607 | // var c1 = [0x87c37b91, 0x114253d5];
608 | // var c2 = [0x4cf5ad43, 0x2745937f];
609 |
610 | for (var i = 0; i < bytes; i = i + 16) {
611 | k1 = [((key[i + 4]& 0xff)) | ((key[i + 5] & 0xff) << 8) | ((key[i + 6] & 0xff) << 16) | ((key[i + 7] & 0xff) << 24), ((key[i] & 0xff)) | ((key[i + 1]& 0xff) << 8) | ((key[i + 2]& 0xff) << 16) | ((key[i + 3] & 0xff) << 24)];
612 | k2 = [((key[i + 12] & 0xff)) | ((key[i + 13] & 0xff) << 8) | ((key[i + 14] & 0xff) << 16) | ((key[i + 15] & 0xff) << 24), ((key[i + 8] & 0xff)) | ((key[i + 9] & 0xff) << 8) | ((key[i + 10] & 0xff) << 16) | ((key[i + 11] & 0xff) << 24)];
613 |
614 | k1 = _x64Multiply(k1, [0x87c37b91, 0x114253d5]);
615 | k1 = _x64Rotl(k1, 31);
616 | k1 = _x64Multiply(k1, [0x4cf5ad43, 0x2745937f]);
617 | // h1 = _x64Xor(h1, k1);
618 |
619 | // h1 = _x64Rotl(h1, 27);
620 | // h1 = _x64Add(h1, h2);
621 | // h1 = _x64Add(_x64Multiply(h1, [0, 5]), [0, 0x52dce729]);
622 | h1 = [0, seed];
623 | h2 = [0, seed];
624 |
625 | k2 = _x64Multiply(k2, [0x4cf5ad43, 0x2745937f]);
626 | k2 = _x64Rotl(k2, 33);
627 | k2 = _x64Multiply(k2, [0x87c37b91, 0x114253d5]);
628 | // h2 = _x64Xor(h2, k2);
629 | //
630 | // h2 = _x64Rotl(h2, 31);
631 | // h2 = _x64Add(h2, h1);
632 | // h2 = _x64Add(_x64Multiply(h2, [0, 5]), [0, 0x38495ab5]);
633 | }
634 |
635 | k1 = [0, 0];
636 | k2 = [0, 0];
637 |
638 | switch (remainder) {
639 | case 15:
640 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 14]], 48));
641 |
642 | case 14:
643 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 13]], 40));
644 |
645 | case 13:
646 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 12]], 32));
647 |
648 | case 12:
649 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 11]], 24));
650 |
651 | case 11:
652 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 10]], 16));
653 |
654 | case 10:
655 | k2 = _x64Xor(k2, _x64LeftShift([0, key[i + 9]], 8));
656 |
657 | case 9:
658 | k2 = _x64Xor(k2, [0, key[i + 8]]);
659 | k2 = _x64Multiply(k2, [0x4cf5ad43, 0x2745937f]);
660 | k2 = _x64Rotl(k2, 33);
661 | k2 = _x64Multiply(k2, [0x87c37b91, 0x114253d5]);
662 | h2 = _x64Xor(h2, k2);
663 |
664 | case 8:
665 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 7]], 56));
666 |
667 | case 7:
668 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 6]], 48));
669 |
670 | case 6:
671 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 5]], 40));
672 |
673 | case 5:
674 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 4]], 32));
675 |
676 | case 4:
677 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 3]], 24));
678 |
679 | case 3:
680 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 2]], 16));
681 |
682 | case 2:
683 | k1 = _x64Xor(k1, _x64LeftShift([0, key[i + 1]], 8));
684 |
685 | case 1:
686 | k1 = _x64Xor(k1, [0, key[i]]);
687 | k1 = _x64Multiply(k1, [0x87c37b91, 0x114253d5]);
688 | k1 = _x64Rotl(k1, 31);
689 | k1 = _x64Multiply(k1, [0x4cf5ad43, 0x2745937f]);
690 | h1 = _x64Xor(h1, k1);
691 | }
692 |
693 | h1 = _x64Xor(h1, [0, key.length]);
694 | h2 = _x64Xor(h2, [0, key.length]);
695 |
696 | h1 = _x64Add(h1, h2);
697 | h2 = _x64Add(h2, h1);
698 |
699 | h1 = _x64Fmix(h1);
700 | h2 = _x64Fmix(h2);
701 |
702 | h1 = _x64Add(h1, h2);
703 | h2 = _x64Add(h2, h1);
704 |
705 | return ("00000000" + (h1[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h1[1] >>> 0).toString(16)).slice(-8) + ("00000000" + (h2[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h2[1] >>> 0).toString(16)).slice(-8);
706 | }
707 | library.x64.hash128 = function (key, seed) {
708 | //
709 | // Given a string and an optional seed as an int, returns a 128 bit
710 | // hash using the x64 flavor of MurmurHash3, as an unsigned hex.
711 | //
712 |
713 | key = key || '';
714 | seed = seed || 0;
715 |
716 | var remainder = key.length % 16;
717 | var bytes = key.length - remainder;
718 |
719 | var h1 = [0, seed];
720 | var h2 = [0, seed];
721 |
722 | var k1 = [0, 0];
723 | var k2 = [0, 0];
724 |
725 | var c1 = [0x87c37b91, 0x114253d5];
726 | var c2 = [0x4cf5ad43, 0x2745937f];
727 |
728 | for (var i = 0; i < bytes; i = i + 16) {
729 | k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)];
730 | k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)];
731 |
732 | k1 = _x64Multiply(k1, c1);
733 | k1 = _x64Rotl(k1, 31);
734 | k1 = _x64Multiply(k1, c2);
735 | h1 = _x64Xor(h1, k1);
736 |
737 | h1 = _x64Rotl(h1, 27);
738 | h1 = _x64Add(h1, h2);
739 | h1 = _x64Add(_x64Multiply(h1, [0, 5]), [0, 0x52dce729]);
740 |
741 | k2 = _x64Multiply(k2, c2);
742 | k2 = _x64Rotl(k2, 33);
743 | k2 = _x64Multiply(k2, c1);
744 | h2 = _x64Xor(h2, k2);
745 |
746 | h2 = _x64Rotl(h2, 31);
747 | h2 = _x64Add(h2, h1);
748 | h2 = _x64Add(_x64Multiply(h2, [0, 5]), [0, 0x38495ab5]);
749 | }
750 |
751 | k1 = [0, 0];
752 | k2 = [0, 0];
753 |
754 | switch (remainder) {
755 | case 15:
756 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 14)], 48));
757 |
758 | case 14:
759 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 13)], 40));
760 |
761 | case 13:
762 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 12)], 32));
763 |
764 | case 12:
765 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 11)], 24));
766 |
767 | case 11:
768 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 10)], 16));
769 |
770 | case 10:
771 | k2 = _x64Xor(k2, _x64LeftShift([0, key.charCodeAt(i + 9)], 8));
772 |
773 | case 9:
774 | k2 = _x64Xor(k2, [0, key.charCodeAt(i + 8)]);
775 | k2 = _x64Multiply(k2, c2);
776 | k2 = _x64Rotl(k2, 33);
777 | k2 = _x64Multiply(k2, c1);
778 | h2 = _x64Xor(h2, k2);
779 |
780 | case 8:
781 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 7)], 56));
782 |
783 | case 7:
784 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 6)], 48));
785 |
786 | case 6:
787 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 5)], 40));
788 |
789 | case 5:
790 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 4)], 32));
791 |
792 | case 4:
793 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 3)], 24));
794 |
795 | case 3:
796 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 2)], 16));
797 |
798 | case 2:
799 | k1 = _x64Xor(k1, _x64LeftShift([0, key.charCodeAt(i + 1)], 8));
800 |
801 | case 1:
802 | k1 = _x64Xor(k1, [0, key.charCodeAt(i)]);
803 | k1 = _x64Multiply(k1, c1);
804 | k1 = _x64Rotl(k1, 31);
805 | k1 = _x64Multiply(k1, c2);
806 | h1 = _x64Xor(h1, k1);
807 | }
808 |
809 | h1 = _x64Xor(h1, [0, key.length]);
810 | h2 = _x64Xor(h2, [0, key.length]);
811 |
812 | h1 = _x64Add(h1, h2);
813 | h2 = _x64Add(h2, h1);
814 |
815 | h1 = _x64Fmix(h1);
816 | h2 = _x64Fmix(h2);
817 |
818 | h1 = _x64Add(h1, h2);
819 | h2 = _x64Add(h2, h1);
820 |
821 | return ("00000000" + (h1[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h1[1] >>> 0).toString(16)).slice(-8) + ("00000000" + (h2[0] >>> 0).toString(16)).slice(-8) + ("00000000" + (h2[1] >>> 0).toString(16)).slice(-8);
822 | };
823 | this.lib = library;
824 | }
825 |
826 | if(((typeof require) != "undefined") &&
827 | ((typeof module) != "undefined") &&
828 | ((typeof module.exports) != "undefined"))
829 | module.exports = MMHASH3;
830 |
--------------------------------------------------------------------------------
/public/js/bit-sync.js:
--------------------------------------------------------------------------------
1 | /**
2 | * bit-sync.js
3 | *
4 | * For more information see the readme.
5 | *
6 | * Source is located at https://github.com/claytongulick/bit-sync
7 | *
8 | * Licensed under the MIT License
9 | *
10 | * Copyright Clayton C. Gulick
11 | *
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy
13 | * of this software and associated documentation files (the "Software"), to deal
14 | * in the Software without restriction, including without limitation the rights
15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | * copies of the Software, and to permit persons to whom the Software is
17 | * furnished to do so, subject to the following conditions:
18 | *
19 | * The above copyright notice and this permission notice shall be included in
20 | * all copies or substantial portions of the Software.
21 | *
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 | * THE SOFTWARE.
29 | */
30 |
31 | var MMHASH3;
32 | if(!MMHASH3){
33 | MMHASH3 = require('./murmurhash3');
34 | SipHash = require('./siphash');
35 | var performance = Date;
36 | }
37 | var MOD_ADLER = 65521;
38 |
39 | var BSync = new function()
40 | {
41 |
42 | /******* Privates *********/
43 | //todo
44 | var md5_0 = function (message,seed,offset,chunksize) {
45 | message = message.slice(offset,offset+chunksize)
46 | // Convert to byte array
47 | if (message.constructor == String) message = UTF8.stringToBytes(message);
48 | /* else, assume byte array already */
49 | var bytesToWords = function (bytes) {
50 | for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
51 | words[b >>> 5] |= (bytes[i] & 0xFF) << (24 - b % 32);
52 | return words;
53 | }
54 |
55 | var m = bytesToWords(message),
56 | l = message.length * 8,
57 | a = 1732584193,
58 | b = -271733879,
59 | c = -1732584194,
60 | d = 271733878;
61 |
62 | // Swap endian
63 | for (var i = 0; i < m.length; i++) {
64 | m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF |
65 | ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00;
66 | }
67 |
68 | // Padding
69 | m[l >>> 5] |= 0x80 << (l % 32);
70 | m[(((l + 64) >>> 9) << 4) + 14] = l;
71 |
72 | // Method shortcuts
73 | // Auxiliary functions
74 | var FF = function (a, b, c, d, x, s, t) {
75 | var n = a + (b & c | ~b & d) + (x >>> 0) + t;
76 | return ((n << s) | (n >>> (32 - s))) + b;
77 | };
78 | var GG = function (a, b, c, d, x, s, t) {
79 | var n = a + (b & d | c & ~d) + (x >>> 0) + t;
80 | return ((n << s) | (n >>> (32 - s))) + b;
81 | };
82 | var HH = function (a, b, c, d, x, s, t) {
83 | var n = a + (b ^ c ^ d) + (x >>> 0) + t;
84 | return ((n << s) | (n >>> (32 - s))) + b;
85 | };
86 | var II = function (a, b, c, d, x, s, t) {
87 | var n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
88 | return ((n << s) | (n >>> (32 - s))) + b;
89 | };
90 |
91 | for (var i = 0; i < m.length; i += 16) {
92 |
93 | var aa = a,
94 | bb = b,
95 | cc = c,
96 | dd = d;
97 |
98 | a = FF(a, b, c, d, m[i+ 0], 7, -680876936);
99 | d = FF(d, a, b, c, m[i+ 1], 12, -389564586);
100 | c = FF(c, d, a, b, m[i+ 2], 17, 606105819);
101 | b = FF(b, c, d, a, m[i+ 3], 22, -1044525330);
102 | a = FF(a, b, c, d, m[i+ 4], 7, -176418897);
103 | d = FF(d, a, b, c, m[i+ 5], 12, 1200080426);
104 | c = FF(c, d, a, b, m[i+ 6], 17, -1473231341);
105 | b = FF(b, c, d, a, m[i+ 7], 22, -45705983);
106 | a = FF(a, b, c, d, m[i+ 8], 7, 1770035416);
107 | d = FF(d, a, b, c, m[i+ 9], 12, -1958414417);
108 | c = FF(c, d, a, b, m[i+10], 17, -42063);
109 | b = FF(b, c, d, a, m[i+11], 22, -1990404162);
110 | a = FF(a, b, c, d, m[i+12], 7, 1804603682);
111 | d = FF(d, a, b, c, m[i+13], 12, -40341101);
112 | c = FF(c, d, a, b, m[i+14], 17, -1502002290);
113 | b = FF(b, c, d, a, m[i+15], 22, 1236535329);
114 |
115 | a = GG(a, b, c, d, m[i+ 1], 5, -165796510);
116 | d = GG(d, a, b, c, m[i+ 6], 9, -1069501632);
117 | c = GG(c, d, a, b, m[i+11], 14, 643717713);
118 | b = GG(b, c, d, a, m[i+ 0], 20, -373897302);
119 | a = GG(a, b, c, d, m[i+ 5], 5, -701558691);
120 | d = GG(d, a, b, c, m[i+10], 9, 38016083);
121 | c = GG(c, d, a, b, m[i+15], 14, -660478335);
122 | b = GG(b, c, d, a, m[i+ 4], 20, -405537848);
123 | a = GG(a, b, c, d, m[i+ 9], 5, 568446438);
124 | d = GG(d, a, b, c, m[i+14], 9, -1019803690);
125 | c = GG(c, d, a, b, m[i+ 3], 14, -187363961);
126 | b = GG(b, c, d, a, m[i+ 8], 20, 1163531501);
127 | a = GG(a, b, c, d, m[i+13], 5, -1444681467);
128 | d = GG(d, a, b, c, m[i+ 2], 9, -51403784);
129 | c = GG(c, d, a, b, m[i+ 7], 14, 1735328473);
130 | b = GG(b, c, d, a, m[i+12], 20, -1926607734);
131 |
132 | a = HH(a, b, c, d, m[i+ 5], 4, -378558);
133 | d = HH(d, a, b, c, m[i+ 8], 11, -2022574463);
134 | c = HH(c, d, a, b, m[i+11], 16, 1839030562);
135 | b = HH(b, c, d, a, m[i+14], 23, -35309556);
136 | a = HH(a, b, c, d, m[i+ 1], 4, -1530992060);
137 | d = HH(d, a, b, c, m[i+ 4], 11, 1272893353);
138 | c = HH(c, d, a, b, m[i+ 7], 16, -155497632);
139 | b = HH(b, c, d, a, m[i+10], 23, -1094730640);
140 | a = HH(a, b, c, d, m[i+13], 4, 681279174);
141 | d = HH(d, a, b, c, m[i+ 0], 11, -358537222);
142 | c = HH(c, d, a, b, m[i+ 3], 16, -722521979);
143 | b = HH(b, c, d, a, m[i+ 6], 23, 76029189);
144 | a = HH(a, b, c, d, m[i+ 9], 4, -640364487);
145 | d = HH(d, a, b, c, m[i+12], 11, -421815835);
146 | c = HH(c, d, a, b, m[i+15], 16, 530742520);
147 | b = HH(b, c, d, a, m[i+ 2], 23, -995338651);
148 |
149 | a = II(a, b, c, d, m[i+ 0], 6, -198630844);
150 | d = II(d, a, b, c, m[i+ 7], 10, 1126891415);
151 | c = II(c, d, a, b, m[i+14], 15, -1416354905);
152 | b = II(b, c, d, a, m[i+ 5], 21, -57434055);
153 | a = II(a, b, c, d, m[i+12], 6, 1700485571);
154 | d = II(d, a, b, c, m[i+ 3], 10, -1894986606);
155 | c = II(c, d, a, b, m[i+10], 15, -1051523);
156 | b = II(b, c, d, a, m[i+ 1], 21, -2054922799);
157 | a = II(a, b, c, d, m[i+ 8], 6, 1873313359);
158 | d = II(d, a, b, c, m[i+15], 10, -30611744);
159 | c = II(c, d, a, b, m[i+ 6], 15, -1560198380);
160 | b = II(b, c, d, a, m[i+13], 21, 1309151649);
161 | a = II(a, b, c, d, m[i+ 4], 6, -145523070);
162 | d = II(d, a, b, c, m[i+11], 10, -1120210379);
163 | c = II(c, d, a, b, m[i+ 2], 15, 718787259);
164 | b = II(b, c, d, a, m[i+ 9], 21, -343485551);
165 |
166 | a = (a + aa) >>> 0;
167 | b = (b + bb) >>> 0;
168 | c = (c + cc) >>> 0;
169 | d = (d + dd) >>> 0;
170 |
171 | }
172 | var rotl = function (n, b) {
173 | return (n << b) | (n >>> (32 - b));
174 | }
175 | var endian = function (n) {
176 |
177 | // If number given, swap endian
178 | if (n.constructor == Number) {
179 | return rotl(n, 8) & 0x00FF00FF |
180 | rotl(n, 24) & 0xFF00FF00;
181 | }
182 |
183 | // Else, assume array and swap all items
184 | for (var i = 0; i < n.length; i++)
185 | n[i] = endian(n[i]);
186 | return n;
187 |
188 | }
189 | return new Uint32Array([a, b, c, d]);
190 |
191 | };
192 |
193 | var md5_1 = MMHASH3.lib.x86.hash128_arraybuffer;
194 |
195 | var md5 = function (message,seed,offset,chunksize) {
196 | var m = message.slice(offset,offset+chunksize);
197 | return SipHash.lib.hash(m);
198 | }
199 |
200 |
201 |
202 | /**
203 | * Create a fast 16 bit hash of a 32bit number. Just using a simple mod 2^16 for this for now.
204 | * TO: Evaluate the distribution of adler32 to see if simple modulus is appropriate as a hashing function, or wheter 2^16 should be replaced with a prime
205 | */
206 | function hash16(i)
207 | {
208 | // return num % 65536;
209 | var p = 1867;
210 | return ((i>>16)& 0xffff ^ ((i&0xffff) * p)) & 0xffff;
211 | }
212 |
213 | /**
214 | * Create a 32 bit checksum for the block, based on the adler-32 checksum, with M as 2^16
215 | * Used to feed the rollingChecksum function, so returns the broken out pieces that are required for fast calc (since there's no reason to do pointless
216 | * bit manipulation, we just cache the parts, like {a: ..., b: ..., checksum: ... }.
217 | *
218 | * Offset is the start, and end is the last byte for the block to be calculated. end - offset should equal the blockSize - 1
219 | *
220 | * Data should be a Uint8Array
221 | *
222 | * TDO: according to wikipedia, the zlib compression library has a much more efficient implementation of adler. To speed this up, it might be worth investigating whether that can be used here.
223 | */
224 | function adler32(offset, end, data)
225 | {
226 |
227 | var a = 1, b= 0;
228 |
229 | //adjust the end to make sure we don't exceed the extents of the data.
230 | if(end >= data.length)
231 | end = data.length - 1;
232 |
233 | for(i=offset; i <= end; i++)
234 | {
235 | a += data[i];
236 | b += a;
237 | a %= MOD_ADLER;
238 | b %= MOD_ADLER;
239 | }
240 |
241 | return {a: a>>>0, b: b>>>0, checksum: ((b << 16) | a) >>>0};
242 |
243 | }
244 |
245 | /**
246 | * Performs a very fast rolling checksum for incremental searching using Tridgell's modification of adler-32 for rolling checksum
247 | * Returns an object suitable for use in additional calls to rollingChecksum, same as the adler32 function. This needs to be called with an offset of at least 1!
248 | * It is the responsibility of the called to make sure we don't exceed the bounds of the data, i.e. end MUST be less than data.length
249 | */
250 | function rollingChecksum(adlerInfo, offset, end, data)
251 | {
252 | newdata = 0
253 | if(end < data.length)
254 | newdata = data[end]
255 | else
256 | end = data.length-1
257 | var temp = data[offset - 1]; //this is the first byte used in the previous iteration
258 | var a = ((adlerInfo.a - temp + newdata) % MOD_ADLER + MOD_ADLER)%MOD_ADLER;
259 | var b = ((adlerInfo.b - ((end - offset + 1) * temp) + a - 1) % MOD_ADLER + MOD_ADLER)%MOD_ADLER;
260 | return {a: a>>>0, b: b>>>0, checksum: ((b << 16) | a)>>>0};
261 | }
262 |
263 | /**
264 | * This is a function born of annoyance. You can't create a Uint32Array at a non 4 byte boundary. So this is necessary to read
265 | * a 32bit int from an arbitrary location. Lame.
266 | *
267 | * BTW: This assumes everything to be little endian.
268 | */
269 | function readInt32(uint8View, offset)
270 | {
271 | return (uint8View[offset] | uint8View[++offset] << 8 | uint8View[++offset] << 16 | uint8View[++offset] << 24) >>> 0;
272 | }
273 |
274 | /**
275 | * Create a document that contains all of the checksum information for each block in the destination data. Everything is little endian
276 | * Document structure:
277 | * First 4 bytes = block size
278 | * Next 4 bytes = number of blocks
279 | * 4 byes = byte length of file
280 | * Repeat for number of blocks:
281 | * 4 bytes, adler32 checksum
282 | * 16 bytes, md5 checksum
283 | *
284 | */
285 | function createChecksumDocument(blockSize, data)
286 | {
287 | var filebytelength = data.byteLength;
288 | var numBlocks = Math.ceil(data.byteLength / blockSize);
289 | var i=0;
290 | var docLength = ( numBlocks * //the number of blocks times
291 | ( 4 + //the 4 bytes for the adler32 plus
292 | 16) + //the 16 bytes for the md5
293 | 4 + //plus 4 bytes for block size
294 | 4 + 4); //plus 4 bytes for the number of blocks
295 |
296 | var doc = new ArrayBuffer(docLength);
297 | var dataView = new Uint8Array(data);
298 | var bufferView = new Uint32Array(doc);
299 | var offset = 3;
300 | var chunkSize = 5; //each chunk is 4 bytes for adler32 and 16 bytes for md5. for Uint32Array view, this is 20 bytes, or 5 4-byte uints
301 |
302 | bufferView[0] = blockSize;
303 | bufferView[1] = numBlocks;
304 | bufferView[2] = filebytelength;
305 |
306 | //spin through the data and create checksums for each block
307 | for(i=0; i < numBlocks; i++)
308 | {
309 | var start = i * blockSize;
310 | var end = (i * blockSize) + blockSize;
311 |
312 | //calculate the adler32 checksum
313 | bufferView[offset] = adler32(start, end - 1, dataView).checksum;
314 | offset++;
315 |
316 | //calculate the full md5 checksum
317 | var chunkLength = blockSize;
318 | if((start + blockSize) > data.byteLength)
319 | chunkLength = data.byteLength - start;
320 |
321 |
322 | var md5sum = md5(dataView,0,start,chunkLength);
323 | // var md5sum = [0,0,0,0]
324 | for(var j=0; j < 4; j++) bufferView[offset++] = md5sum[j];
325 |
326 | }
327 |
328 | return doc;
329 |
330 | }
331 |
332 | /**
333 | * Parse the checksum document into a hash table
334 | *
335 | * The hash table will have 2^16 entries. Each entry will point to an array that has the following strucutre:
336 | * [
337 | * [ [blockIndex, adler32sum, md5sum],[blockIndex, adler32sum, md5sum],... ]
338 | * [ [blockIndex, adler32sum, md5sum],[blockIndex, adler32sum, md5sum],... ]
339 | * ...
340 | * ]
341 | */
342 | function parseChecksumDocument(checksumDocument)
343 | {
344 | var fplist = [];
345 | var fp_chunk_size = 1*1024*1024;
346 |
347 |
348 |
349 | var ret = [];
350 | var linked_checksum = [];
351 | var i=0;
352 | var view = new Uint32Array(checksumDocument);
353 | var blockIndex = 1; //blockIndex is 1 based, not zero based
354 | var numBlocks = view[1];
355 | var filebytelength = view[2];
356 | var row;
357 | var hash;
358 |
359 | var fp_all_num = Math.ceil(filebytelength/fp_chunk_size);
360 |
361 | var offset = 0;
362 |
363 | //each chunk in the document is 20 bytes long. 32 bit view indexes 4 bytes, so increment by 5.
364 | for(i = 3; i <= view.length - 5; i += 5)
365 | {
366 | checksumInfo = [
367 | blockIndex, //the index of the block
368 | view[i], //the adler32sum
369 | [view[i+1],view[i+2],view[i+3],view[i+4]] //the md5sum
370 | ];
371 | hash = hash16(checksumInfo[1]);
372 | if(!ret[hash]) ret[hash] = [];
373 | ret[hash].push(checksumInfo);
374 | linked_checksum[blockIndex] = [view[i+1],view[i+2],view[i+3],view[i+4]];
375 | blockIndex++;
376 | }
377 |
378 | if(numBlocks != (blockIndex - 1))
379 | {
380 | throw "Error parsing checksum document. Document states the number of blocks is: " + numBlocks + " however, " + blockIndex - 1 + " blocks were discovered";
381 | }
382 | return [filebytelength,ret,linked_checksum];
383 |
384 | }
385 |
386 | /**
387 | * create match document that contains all matched block index
388 | * 4 bytes - blockSize
389 | * 4 bytes - num of matched blocks
390 | * for each matched block
391 | * 4 bytes - the index of the matched block
392 | * 4 bytes - the offset in the old file
393 | */
394 | function createMatchDocument(checksumDocument, data){
395 | function appendBuffer( buffer1, buffer2 ) {
396 | var tmp = new Uint8Array( buffer1.byteLength + buffer2.byteLength );
397 | tmp.set( new Uint8Array( buffer1 ), 0 );
398 | tmp.set( new Uint8Array( buffer2 ), buffer1.byteLength );
399 | return tmp.buffer;
400 | }
401 |
402 | /**
403 | * First, check to see if there's a match on the 16 bit hash
404 | * Then, look through all the entries in the hashtable row for an adler 32 match.
405 | * Finally, do a strong md5 comparison
406 | */
407 | function checkMatch(adlerInfo, hashTable,start,chunksize, block)
408 | {
409 | var hash = hash16(adlerInfo.checksum);
410 | // return false;
411 | if(!(hashTable[hash])) {
412 | // console.log('adler 32 missing');
413 | return false;
414 | }
415 | // var testblock = block.slice(start,start+chunksize);
416 |
417 | var row = hashTable[hash];
418 | this.hash16_coll += row.length - 1;
419 | var i=0;
420 | var matchedIndex=0;
421 |
422 | for(i=0; i data_len)
479 | {
480 | chunkSize = data_len - i;
481 | // adlerInfo=null; //need to reset this because the rolling checksum doesn't work correctly on a final non-aligned block
482 | }
483 | else
484 | chunkSize = blockSize;
485 |
486 | //locality optimized
487 | // prematching = false;
488 | if(prematching){
489 | var predict_index = preindex+1;
490 | //predict_checksum
491 | var md5sum2 = linked_checksum[predict_index];
492 | if(md5sum2){
493 | // console.log("predict success!");
494 | md5sum1 = md5(dataUint8,0,i,chunkSize);
495 |
496 | if(
497 | md5sum1[0] == md5sum2[0] &&
498 | md5sum1[1] == md5sum2[1] &&
499 | md5sum1[2] == md5sum2[2] &&
500 | md5sum1[3] == md5sum2[3]
501 | ){
502 | var matchedBlock = predict_index;
503 | matchedBlocksUint32[2*matchCount] = matchedBlock;
504 | matchedBlocksUint32[2*matchCount+1] = i;
505 | matchCount++;
506 | //check to see if we need more memory for the matched blocks
507 | if(2*matchCount >= matchedBlocksUint32.length)
508 | {
509 | matchedBlocks = appendBuffer(matchedBlocks, new ArrayBuffer(10000));
510 | matchedBlocksUint32 = new Uint32Array(matchedBlocks);
511 | }
512 |
513 | lastMatchIndex = matchedBlock;
514 | i+=blockSize;
515 | if(i >= dataUint8.length -1 ) break;
516 | adlerInfo=null;
517 | prematching = true;
518 | preindex = matchedBlock;
519 | continue;
520 | }
521 | }
522 | }
523 | // resuse md5 checksum
524 | chunkSize = blockSize;
525 |
526 | if(adlerInfo){
527 | adlerInfo = rollingChecksum(adlerInfo, i, i + chunkSize - 1, dataUint8);
528 | }
529 |
530 | else
531 | adlerInfo = adler32(i, i + chunkSize - 1, dataUint8);
532 |
533 | var matchedBlock = checkMatch(adlerInfo, hashTable,i,chunkSize,dataUint8);
534 | if(matchedBlock)
535 | {
536 | //if we have a match, do the following:
537 | //1) add the matched block index to our tracking buffer
538 | //2) add match block into match cache
539 | //3) jump forward blockSize bytes and continue
540 | matchedBlocksUint32[2*matchCount] = matchedBlock;
541 | matchedBlocksUint32[2*matchCount+1] = i;
542 | matchCount++;
543 | //check to see if we need more memory for the matched blocks
544 | if(2*matchCount >= matchedBlocksUint32.length)
545 | {
546 | matchedBlocks = appendBuffer(matchedBlocks, new ArrayBuffer(10000));
547 | matchedBlocksUint32 = new Uint32Array(matchedBlocks);
548 | }
549 |
550 | lastMatchIndex = matchedBlock;
551 | i+=blockSize;
552 | if(i >= dataUint8.length -1 ) break;
553 | adlerInfo=null;
554 | prematching = true;
555 | preindex = matchedBlock;
556 | continue;
557 | }else{
558 | content_traffic++;
559 | }
560 | prematching = false;
561 | if((i) >= dataUint8.length -1) break;
562 | i++;
563 | } //end for each byte in the data
564 |
565 |
566 | var test1 = performance.now();
567 | console.log("########## match doc create time: " + (test1 - startTime));
568 |
569 | console.log('########## content traffic is',content_traffic);
570 | var patchDocumentView32 = new Uint32Array(patchDocument);
571 | patchDocumentView32[0] = blockSize;
572 | patchDocumentView32[1] = matchCount;
573 | patchDocument = appendBuffer(patchDocument, matchedBlocks.slice(0,matchCount * 4 * 2));
574 |
575 |
576 | return [patchDocument,filebytelength];
577 | }
578 |
579 | /**
580 | * Apply the patch to the destination data, making it into a duplicate of the source data
581 | * Due to the inability to modify the size of ArrayBuffers once they have been allocated, this function
582 | * will return a new ArrayBuffer with the update file data. Note that this will consume a good bit of extra memory.
583 | */
584 | function applyPatch(patchDocument, data)
585 | {
586 | function appendBlock( buffer, blockUint8) {
587 | var tmp = new Uint8Array( buffer.byteLength + blockUint8.length);
588 | tmp.set( new Uint8Array( buffer ), 0 );
589 | tmp.set( blockUint8, buffer.byteLength );
590 | return tmp.buffer;
591 | }
592 |
593 | var patchDocumentView32 = new Uint32Array(patchDocument,0,3);
594 | var blockSize = patchDocumentView32[0];
595 | var patchCount = patchDocumentView32[1];
596 | var matchCount = patchDocumentView32[2];
597 | var matchedBlockView32 = new Uint32Array(patchDocument,12,matchCount);
598 | var i=0;
599 | var j=0;
600 |
601 | //first, let's deal with the simple case where we fully match. This is just an optimization for the unchanged file case.
602 | //to determine this, the number of matches must exactly equal ceil of data / blockSize, and num patches must be zero
603 | //additionally, the matched block indexes must start with 1 and be in order. This is to deal with the extreme edge case of a block being relocated
604 | //on an exact block boundary
605 | if(patchCount == 0)
606 | if(Math.ceil(data.byteLength / blockSize) == matchCount)
607 | for(i = 1; i <= matchCount; i++)
608 | if(matchedBlockView32[i-1] != i) { break; }
609 | if((i - 1) == matchCount) return data; //exact match
610 |
611 | //there was a modification. We need to construct the new document.
612 | //the way this works is as follows:
613 | //1) for each patch, get the last index of the matching block
614 | //2) loop through the matchedBlocks, appending blocks up to the index from step 1
615 | //3) append the patch at that point
616 | //4) after all patches have been applied, continue to loop through the matchedBlocks appending each one in order
617 | var offset = 12 + (matchCount * 4); //offset to the start of the patches
618 | var lastMatchingBlockIndex=0;
619 | var patchSize=0;
620 | var patchView8;
621 | var matchIndex=0; //the index into the matching blocks array
622 | var blockIndex=0; //the index of the block in the matching blocks array
623 | var ret = new ArrayBuffer(0);
624 | var patchDocumentView8 = new Uint8Array(patchDocument);
625 | var chunkSize=0;
626 | for(i=0; i< patchCount; i++)
627 | {
628 | lastMatchingBlockIndex = readInt32(patchDocumentView8,offset);
629 | patchSize = readInt32(patchDocumentView8,offset + 4);
630 | patchView8 = new Uint8Array(patchDocument, offset + 8, patchSize);
631 | offset = offset + 8 + patchSize;
632 |
633 | for(;matchIndex < matchedBlockView32.length; matchIndex++)
634 | {
635 | blockIndex = matchedBlockView32[matchIndex];
636 | if(blockIndex > lastMatchingBlockIndex) break;
637 | if((blockIndex * blockSize) > data.byteLength)
638 | chunkSize = data.byteLength % blockSize;
639 | else chunkSize = blockSize;
640 | ret = appendBlock(ret, new Uint8Array(data, (blockIndex-1) * blockSize, chunkSize));
641 | }
642 |
643 | ret = appendBlock(ret, patchView8);
644 | }
645 |
646 | //we're done with all the patches, add the remaining blocks
647 | for(;matchIndex < matchedBlockView32.length; matchIndex++)
648 | {
649 | blockIndex = matchedBlockView32[matchIndex];
650 | if((blockIndex * blockSize) > data.byteLength)
651 | chunkSize = data.byteLength % blockSize;
652 | else chunkSize = blockSize;
653 | ret = appendBlock(ret, new Uint8Array(data, (blockIndex-1) * blockSize, chunkSize));
654 | }
655 |
656 | return ret;
657 | }
658 | /*
659 | * parse match document
660 | * use hash table to store match document: because js object is hash table
661 | */
662 | function parseMatchDocument(matchDocument)
663 | {
664 | var ret = [];
665 | var view = new Uint32Array(matchDocument);
666 | var blockIndex = 1; //blockIndex is 1 based, not zero based
667 | var numBlocks = view[1];
668 | var row;
669 | var hash;
670 |
671 | //each chunk in the document is 20 bytes long. 32 bit view indexes 4 bytes, so increment by 5.
672 | for(i = 2; i < view.length;)
673 | {
674 | match_blockIndex = view[i++];
675 | match_blockoffset = view[i++];
676 | ret[match_blockIndex] = match_blockoffset;
677 | }
678 | return ret;
679 | }
680 |
681 | /******** Public API ***********/
682 | this.createChecksumDocument = createChecksumDocument;
683 | // this.createPatchDocument = createPatchDocument;
684 | this.createMatchDocument = createMatchDocument;
685 | this.parseMatchDocument = parseMatchDocument;
686 | this.applyPatch = applyPatch;
687 | this.hash16_coll = 0;
688 | this.util = {md5: md5, adler32: adler32, rollingChecksum: rollingChecksum, readInt32: readInt32}; //mostly exposing these for the purposes of unit tests, but hey, if they are useful to someone, have at it!
689 | };
690 |
691 |
692 | if(((typeof require) != "undefined") &&
693 | ((typeof module) != "undefined") &&
694 | ((typeof module.exports) != "undefined"))
695 | module.exports = BSync;
696 |
697 |
698 |
--------------------------------------------------------------------------------
/public/js/socket.io-1.4.5.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.io=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0){this.extraHeaders=opts.extraHeaders}}this.open()}Socket.priorWebsocketSuccess=false;Emitter(Socket.prototype);Socket.protocol=parser.protocol;Socket.Socket=Socket;Socket.Transport=_dereq_("./transport");Socket.transports=_dereq_("./transports");Socket.parser=_dereq_("engine.io-parser");Socket.prototype.createTransport=function(name){debug('creating transport "%s"',name);var query=clone(this.query);query.EIO=parser.protocol;query.transport=name;if(this.id)query.sid=this.id;var transport=new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate,extraHeaders:this.extraHeaders});return transport};function clone(obj){var o={};for(var i in obj){if(obj.hasOwnProperty(i)){o[i]=obj[i]}}return o}Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&this.transports.indexOf("websocket")!=-1){transport="websocket"}else if(0===this.transports.length){var self=this;setTimeout(function(){self.emit("error","No transports available")},0);return}else{transport=this.transports[0]}this.readyState="opening";try{transport=this.createTransport(transport)}catch(e){this.transports.shift();this.open();return}transport.open();this.setTransport(transport)};Socket.prototype.setTransport=function(transport){debug("setting transport %s",transport.name);var self=this;if(this.transport){debug("clearing existing transport %s",this.transport.name);this.transport.removeAllListeners()}this.transport=transport;transport.on("drain",function(){self.onDrain()}).on("packet",function(packet){self.onPacket(packet)}).on("error",function(e){self.onError(e)}).on("close",function(){self.onClose("transport close")})};Socket.prototype.probe=function(name){debug('probing transport "%s"',name);var transport=this.createTransport(name,{probe:1}),failed=false,self=this;Socket.priorWebsocketSuccess=false;function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}if(failed)return;debug('probe transport "%s" opened',name);transport.send([{type:"ping",data:"probe"}]);transport.once("packet",function(msg){if(failed)return;if("pong"==msg.type&&"probe"==msg.data){debug('probe transport "%s" pong',name);self.upgrading=true;self.emit("upgrading",transport);if(!transport)return;Socket.priorWebsocketSuccess="websocket"==transport.name;debug('pausing current transport "%s"',self.transport.name);self.transport.pause(function(){if(failed)return;if("closed"==self.readyState)return;debug("changing transport and sending upgrade packet");cleanup();self.setTransport(transport);transport.send([{type:"upgrade"}]);self.emit("upgrade",transport);transport=null;self.upgrading=false;self.flush()})}else{debug('probe transport "%s" failed',name);var err=new Error("probe error");err.transport=transport.name;self.emit("upgradeError",err)}})}function freezeTransport(){if(failed)return;failed=true;cleanup();transport.close();transport=null}function onerror(err){var error=new Error("probe error: "+err);error.transport=transport.name;freezeTransport();debug('probe transport "%s" failed because of error: %s',name,err);self.emit("upgradeError",error)}function onTransportClose(){onerror("transport closed")}function onclose(){onerror("socket closed")}function onupgrade(to){if(transport&&to.name!=transport.name){debug('"%s" works - aborting "%s"',to.name,transport.name);freezeTransport()}}function cleanup(){transport.removeListener("open",onTransportOpen);transport.removeListener("error",onerror);transport.removeListener("close",onTransportClose);self.removeListener("close",onclose);self.removeListener("upgrading",onupgrade)}transport.once("open",onTransportOpen);transport.once("error",onerror);transport.once("close",onTransportClose);this.once("close",onclose);this.once("upgrading",onupgrade);transport.open()};Socket.prototype.onOpen=function(){debug("socket open");this.readyState="open";Socket.priorWebsocketSuccess="websocket"==this.transport.name;this.emit("open");this.flush();if("open"==this.readyState&&this.upgrade&&this.transport.pause){debug("starting upgrade probes");for(var i=0,l=this.upgrades.length;i';iframe=document.createElement(html)}catch(e){iframe=document.createElement("iframe");iframe.name=self.iframeId;iframe.src="javascript:0"}iframe.id=self.iframeId;self.form.appendChild(iframe);self.iframe=iframe}initIframe();data=data.replace(rEscapedNewline,"\\\n");this.area.value=data.replace(rNewline,"\\n");try{this.form.submit()}catch(e){}if(this.iframe.attachEvent){this.iframe.onreadystatechange=function(){if(self.iframe.readyState=="complete"){complete()}}}else{this.iframe.onload=complete}}}).call(this,typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:{})},{"./polling":8,"component-inherit":16}],7:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_("xmlhttprequest-ssl");var Polling=_dereq_("./polling");var Emitter=_dereq_("component-emitter");var inherit=_dereq_("component-inherit");var debug=_dereq_("debug")("engine.io-client:polling-xhr");module.exports=XHR;module.exports.Request=Request;function empty(){}function XHR(opts){Polling.call(this,opts);if(global.location){var isSSL="https:"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}this.xd=opts.hostname!=global.location.hostname||port!=opts.port;this.xs=opts.secure!=isSSL}else{this.extraHeaders=opts.extraHeaders}}inherit(XHR,Polling);XHR.prototype.supportsBinary=true;XHR.prototype.request=function(opts){opts=opts||{};opts.uri=this.uri();opts.xd=this.xd;opts.xs=this.xs;opts.agent=this.agent||false;opts.supportsBinary=this.supportsBinary;opts.enablesXDR=this.enablesXDR;opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;opts.extraHeaders=this.extraHeaders;return new Request(opts)};XHR.prototype.doWrite=function(data,fn){var isBinary=typeof data!=="string"&&data!==undefined;var req=this.request({method:"POST",data:data,isBinary:isBinary});var self=this;req.on("success",fn);req.on("error",function(err){self.onError("xhr post error",err)});this.sendXhr=req};XHR.prototype.doPoll=function(){debug("xhr poll");var req=this.request();var self=this;req.on("data",function(data){self.onData(data)});req.on("error",function(err){self.onError("xhr poll error",err)});this.pollXhr=req};function Request(opts){this.method=opts.method||"GET";this.uri=opts.uri;this.xd=!!opts.xd;this.xs=!!opts.xs;this.async=false!==opts.async;this.data=undefined!=opts.data?opts.data:null;this.agent=opts.agent;this.isBinary=opts.isBinary;this.supportsBinary=opts.supportsBinary;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized;this.extraHeaders=opts.extraHeaders;this.create()}Emitter(Request.prototype);Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts);var self=this;try{debug("xhr open %s: %s",this.method,this.uri);xhr.open(this.method,this.uri,this.async);try{if(this.extraHeaders){xhr.setDisableHeaderCheck(true);for(var i in this.extraHeaders){if(this.extraHeaders.hasOwnProperty(i)){xhr.setRequestHeader(i,this.extraHeaders[i])}}}}catch(e){}if(this.supportsBinary){xhr.responseType="arraybuffer"}if("POST"==this.method){try{if(this.isBinary){xhr.setRequestHeader("Content-type","application/octet-stream")}else{xhr.setRequestHeader("Content-type","text/plain;charset=UTF-8")}}catch(e){}}if("withCredentials"in xhr){xhr.withCredentials=true}if(this.hasXDR()){xhr.onload=function(){self.onLoad()};xhr.onerror=function(){self.onError(xhr.responseText)}}else{xhr.onreadystatechange=function(){if(4!=xhr.readyState)return;if(200==xhr.status||1223==xhr.status){self.onLoad()}else{setTimeout(function(){self.onError(xhr.status)},0)}}}debug("xhr data %s",this.data);xhr.send(this.data)}catch(e){setTimeout(function(){self.onError(e)},0);return}if(global.document){this.index=Request.requestsCount++;Request.requests[this.index]=this}};Request.prototype.onSuccess=function(){this.emit("success");this.cleanup()};Request.prototype.onData=function(data){this.emit("data",data);this.onSuccess()};Request.prototype.onError=function(err){this.emit("error",err);this.cleanup(true)};Request.prototype.cleanup=function(fromError){if("undefined"==typeof this.xhr||null===this.xhr){return}if(this.hasXDR()){this.xhr.onload=this.xhr.onerror=empty}else{this.xhr.onreadystatechange=empty}if(fromError){try{this.xhr.abort()}catch(e){}}if(global.document){delete Request.requests[this.index]}this.xhr=null};Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader("Content-Type").split(";")[0]}catch(e){}if(contentType==="application/octet-stream"){data=this.xhr.response}else{if(!this.supportsBinary){data=this.xhr.responseText}else{try{data=String.fromCharCode.apply(null,new Uint8Array(this.xhr.response))}catch(e){var ui8Arr=new Uint8Array(this.xhr.response);var dataArray=[];for(var idx=0,length=ui8Arr.length;idxbytes){end=bytes}if(start>=bytes||start>=end||bytes===0){return new ArrayBuffer(0)}var abv=new Uint8Array(arraybuffer);var result=new Uint8Array(end-start);for(var i=start,ii=0;i>2];
2 | base64+=chars[(bytes[i]&3)<<4|bytes[i+1]>>4];base64+=chars[(bytes[i+1]&15)<<2|bytes[i+2]>>6];base64+=chars[bytes[i+2]&63]}if(len%3===2){base64=base64.substring(0,base64.length-1)+"="}else if(len%3===1){base64=base64.substring(0,base64.length-2)+"=="}return base64};exports.decode=function(base64){var bufferLength=base64.length*.75,len=base64.length,i,p=0,encoded1,encoded2,encoded3,encoded4;if(base64[base64.length-1]==="="){bufferLength--;if(base64[base64.length-2]==="="){bufferLength--}}var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i>4;bytes[p++]=(encoded2&15)<<4|encoded3>>2;bytes[p++]=(encoded3&3)<<6|encoded4&63}return arraybuffer}})("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")},{}],14:[function(_dereq_,module,exports){(function(global){var BlobBuilder=global.BlobBuilder||global.WebKitBlobBuilder||global.MSBlobBuilder||global.MozBlobBuilder;var blobSupported=function(){try{var a=new Blob(["hi"]);return a.size===2}catch(e){return false}}();var blobSupportsArrayBufferView=blobSupported&&function(){try{var b=new Blob([new Uint8Array([1,2])]);return b.size===2}catch(e){return false}}();var blobBuilderSupported=BlobBuilder&&BlobBuilder.prototype.append&&BlobBuilder.prototype.getBlob;function mapArrayBufferViews(ary){for(var i=0;i=31}exports.formatters.j=function(v){return JSON.stringify(v)};function formatArgs(){var args=arguments;var useColors=this.useColors;args[0]=(useColors?"%c":"")+this.namespace+(useColors?" %c":" ")+args[0]+(useColors?"%c ":" ")+"+"+exports.humanize(this.diff);if(!useColors)return args;var c="color: "+this.color;args=[args[0],c,"color: inherit"].concat(Array.prototype.slice.call(args,1));var index=0;var lastC=0;args[0].replace(/%[a-z%]/g,function(match){if("%%"===match)return;index++;if("%c"===match){lastC=index}});args.splice(lastC,0,c);return args}function log(){return"object"===typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{if(null==namespaces){exports.storage.removeItem("debug")}else{exports.storage.debug=namespaces}}catch(e){}}function load(){var r;try{r=exports.storage.debug}catch(e){}return r}exports.enable(load());function localstorage(){try{return window.localStorage}catch(e){}}},{"./debug":18}],18:[function(_dereq_,module,exports){exports=module.exports=debug;exports.coerce=coerce;exports.disable=disable;exports.enable=enable;exports.enabled=enabled;exports.humanize=_dereq_("ms");exports.names=[];exports.skips=[];exports.formatters={};var prevColor=0;var prevTime;function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}disabled.enabled=false;function enabled(){var self=enabled;var curr=+new Date;var ms=curr-(prevTime||curr);self.diff=ms;self.prev=prevTime;self.curr=curr;prevTime=curr;if(null==self.useColors)self.useColors=exports.useColors();if(null==self.color&&self.useColors)self.color=selectColor();var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]);if("string"!==typeof args[0]){args=["%o"].concat(args)}var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if(match==="%%")return match;index++;var formatter=exports.formatters[format];if("function"===typeof formatter){var val=args[index];match=formatter.call(self,val);args.splice(index,1);index--}return match});if("function"===typeof exports.formatArgs){args=exports.formatArgs.apply(self,args)}var logFn=enabled.log||exports.log||console.log.bind(console);logFn.apply(self,args)}enabled.enabled=true;var fn=exports.enabled(namespace)?enabled:disabled;fn.namespace=namespace;return fn}function enable(namespaces){exports.save(namespaces);var split=(namespaces||"").split(/[\s,]+/);var len=split.length;for(var i=0;i1){return{type:packetslist[type],data:data.substring(1)}}else{return{type:packetslist[type]}}}var asArray=new Uint8Array(data);var type=asArray[0];var rest=sliceBuffer(data,1);if(Blob&&binaryType==="blob"){rest=new Blob([rest])}return{type:packetslist[type],data:rest}};exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer){return{type:type,data:{base64:true,data:msg.substr(1)}}}var data=base64encoder.decode(msg.substr(1));if(binaryType==="blob"&&Blob){data=new Blob([data])}return{type:type,data:data}};exports.encodePayload=function(packets,supportsBinary,callback){if(typeof supportsBinary=="function"){callback=supportsBinary;supportsBinary=null}var isBinary=hasBinary(packets);if(supportsBinary&&isBinary){if(Blob&&!dontSendBlobs){return exports.encodePayloadAsBlob(packets,callback)}return exports.encodePayloadAsArrayBuffer(packets,callback)}if(!packets.length){return callback("0:")}function setLengthHeader(message){return message.length+":"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!isBinary?false:supportsBinary,true,function(message){doneCallback(null,setLengthHeader(message))})}map(packets,encodeOne,function(err,results){return callback(results.join(""))})};function map(ary,each,done){var result=new Array(ary.length);var next=after(ary.length,done);var eachWithIndex=function(i,el,cb){each(el,function(error,msg){result[i]=msg;cb(error,result)})};for(var i=0;i0){var tailArray=new Uint8Array(bufferTail);var isString=tailArray[0]===0;var msgLength="";for(var i=1;;i++){if(tailArray[i]==255)break;if(msgLength.length>310){numberTooLong=true;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length);msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString){try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg="";for(var i=0;i1e4)return;var match=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]);var type=(match[2]||"ms").toLowerCase();switch(type){case"years":case"year":case"yrs":case"yr":case"y":return n*y;case"days":case"day":case"d":return n*d;case"hours":case"hour":case"hrs":case"hr":case"h":return n*h;case"minutes":case"minute":case"mins":case"min":case"m":return n*m;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}function short(ms){if(ms>=d)return Math.round(ms/d)+"d";if(ms>=h)return Math.round(ms/h)+"h";if(ms>=m)return Math.round(ms/m)+"m";if(ms>=s)return Math.round(ms/s)+"s";return ms+"ms"}function long(ms){return plural(ms,d,"day")||plural(ms,h,"hour")||plural(ms,m,"minute")||plural(ms,s,"second")||ms+" ms"}function plural(ms,n,name){if(ms=55296&&value<=56319&&counter65535){value-=65536;output+=stringFromCharCode(value>>>10&1023|55296);value=56320|value&1023}output+=stringFromCharCode(value)}return output}function checkScalarValue(codePoint){if(codePoint>=55296&&codePoint<=57343){throw Error("Lone surrogate U+"+codePoint.toString(16).toUpperCase()+" is not a scalar value")}}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if((codePoint&4294967168)==0){return stringFromCharCode(codePoint)}var symbol="";if((codePoint&4294965248)==0){symbol=stringFromCharCode(codePoint>>6&31|192)}else if((codePoint&4294901760)==0){checkScalarValue(codePoint);symbol=stringFromCharCode(codePoint>>12&15|224);symbol+=createByte(codePoint,6)}else if((codePoint&4292870144)==0){symbol=stringFromCharCode(codePoint>>18&7|240);symbol+=createByte(codePoint,12);symbol+=createByte(codePoint,6)}symbol+=stringFromCharCode(codePoint&63|128);return symbol}function utf8encode(string){var codePoints=ucs2decode(string);var length=codePoints.length;var index=-1;var codePoint;var byteString="";while(++index=byteCount){throw Error("Invalid byte index")}var continuationByte=byteArray[byteIndex]&255;byteIndex++;if((continuationByte&192)==128){return continuationByte&63}throw Error("Invalid continuation byte")}function decodeSymbol(){var byte1;var byte2;var byte3;var byte4;var codePoint;if(byteIndex>byteCount){throw Error("Invalid byte index")}if(byteIndex==byteCount){return false}byte1=byteArray[byteIndex]&255;byteIndex++;if((byte1&128)==0){return byte1}if((byte1&224)==192){var byte2=readContinuationByte();codePoint=(byte1&31)<<6|byte2;if(codePoint>=128){return codePoint}else{throw Error("Invalid continuation byte")}}if((byte1&240)==224){byte2=readContinuationByte();byte3=readContinuationByte();codePoint=(byte1&15)<<12|byte2<<6|byte3;if(codePoint>=2048){checkScalarValue(codePoint);return codePoint}else{throw Error("Invalid continuation byte")}}if((byte1&248)==240){byte2=readContinuationByte();byte3=readContinuationByte();byte4=readContinuationByte();codePoint=(byte1&15)<<18|byte2<<12|byte3<<6|byte4;if(codePoint>=65536&&codePoint<=1114111){return codePoint}}throw Error("Invalid UTF-8 detected")}var byteArray;var byteCount;var byteIndex;function utf8decode(byteString){byteArray=ucs2decode(byteString);byteCount=byteArray.length;byteIndex=0;var codePoints=[];var tmp;while((tmp=decodeSymbol())!==false){codePoints.push(tmp)}return ucs2encode(codePoints)}var utf8={version:"2.0.0",encode:utf8encode,decode:utf8decode};if(typeof define=="function"&&typeof define.amd=="object"&&define.amd){define(function(){return utf8})}else if(freeExports&&!freeExports.nodeType){if(freeModule){freeModule.exports=utf8}else{var object={};var hasOwnProperty=object.hasOwnProperty;for(var key in utf8){hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}}}else{root.utf8=utf8}})(this)}).call(this,typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:{})},{}],30:[function(_dereq_,module,exports){"use strict";var alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),length=64,map={},seed=0,i=0,prev;function encode(num){var encoded="";do{encoded=alphabet[num%length]+encoded;num=Math.floor(num/length)}while(num>0);return encoded}function decode(str){var decoded=0;for(i=0;i0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}};Manager.prototype.cleanup=function(){debug("cleanup");var sub;while(sub=this.subs.shift())sub.destroy();this.packetBuffer=[];this.encoding=false;this.lastPing=null;this.decoder.destroy()};Manager.prototype.close=Manager.prototype.disconnect=function(){debug("disconnect");this.skipReconnect=true;this.reconnecting=false;if("opening"==this.readyState){this.cleanup()}this.backoff.reset();this.readyState="closed";if(this.engine)this.engine.close()};Manager.prototype.onclose=function(reason){debug("onclose");this.cleanup();this.backoff.reset();this.readyState="closed";this.emit("close",reason);if(this._reconnection&&!this.skipReconnect){this.reconnect()}};Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts){debug("reconnect failed");this.backoff.reset();this.emitAll("reconnect_failed");this.reconnecting=false}else{var delay=this.backoff.duration();debug("will wait %dms before reconnect attempt",delay);this.reconnecting=true;var timer=setTimeout(function(){if(self.skipReconnect)return;debug("attempting reconnect");self.emitAll("reconnect_attempt",self.backoff.attempts);self.emitAll("reconnecting",self.backoff.attempts);if(self.skipReconnect)return;self.open(function(err){if(err){debug("reconnect attempt error");self.reconnecting=false;self.reconnect();self.emitAll("reconnect_error",err.data)}else{debug("reconnect success");self.onreconnect()}})},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}};Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=false;this.backoff.reset();this.updateSocketIds();this.emitAll("reconnect",attempt)}},{"./on":33,"./socket":34,backo2:36,"component-bind":37,"component-emitter":38,debug:39,"engine.io-client":1,indexof:42,"socket.io-parser":47}],33:[function(_dereq_,module,exports){module.exports=on;function on(obj,ev,fn){obj.on(ev,fn);return{destroy:function(){obj.removeListener(ev,fn)}}}},{}],34:[function(_dereq_,module,exports){var parser=_dereq_("socket.io-parser");var Emitter=_dereq_("component-emitter");var toArray=_dereq_("to-array");var on=_dereq_("./on");var bind=_dereq_("component-bind");var debug=_dereq_("debug")("socket.io-client:socket");var hasBin=_dereq_("has-binary");module.exports=exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,connecting:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1,ping:1,pong:1};var emit=Emitter.prototype.emit;function Socket(io,nsp){this.io=io;this.nsp=nsp;this.json=this;this.ids=0;this.acks={};this.receiveBuffer=[];this.sendBuffer=[];this.connected=false;this.disconnected=true;if(this.io.autoConnect)this.open()}Emitter(Socket.prototype);Socket.prototype.subEvents=function(){if(this.subs)return;var io=this.io;this.subs=[on(io,"open",bind(this,"onopen")),on(io,"packet",bind(this,"onpacket")),on(io,"close",bind(this,"onclose"))]};Socket.prototype.open=Socket.prototype.connect=function(){if(this.connected)return this;this.subEvents();this.io.open();if("open"==this.io.readyState)this.onopen();this.emit("connecting");return this};Socket.prototype.send=function(){var args=toArray(arguments);args.unshift("message");this.emit.apply(this,args);return this};Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev)){emit.apply(this,arguments);return this}var args=toArray(arguments);var parserType=parser.EVENT;if(hasBin(args)){parserType=parser.BINARY_EVENT}var packet={type:parserType,data:args};packet.options={};packet.options.compress=!this.flags||false!==this.flags.compress;if("function"==typeof args[args.length-1]){debug("emitting packet with ack id %d",this.ids);this.acks[this.ids]=args.pop();packet.id=this.ids++}if(this.connected){this.packet(packet)}else{this.sendBuffer.push(packet)}delete this.flags;return this};Socket.prototype.packet=function(packet){packet.nsp=this.nsp;this.io.packet(packet)};Socket.prototype.onopen=function(){debug("transport is open - connecting");if("/"!=this.nsp){this.packet({type:parser.CONNECT})}};Socket.prototype.onclose=function(reason){debug("close (%s)",reason);this.connected=false;this.disconnected=true;delete this.id;this.emit("disconnect",reason)};Socket.prototype.onpacket=function(packet){if(packet.nsp!=this.nsp)return;switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit("error",packet.data);break}};Socket.prototype.onevent=function(packet){var args=packet.data||[];debug("emitting event %j",args);if(null!=packet.id){debug("attaching ack callback to event");args.push(this.ack(packet.id))}if(this.connected){emit.apply(this,args)}else{this.receiveBuffer.push(args)}};Socket.prototype.ack=function(id){var self=this;var sent=false;return function(){if(sent)return;sent=true;var args=toArray(arguments);debug("sending ack %j",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}};Socket.prototype.onack=function(packet){var ack=this.acks[packet.id];if("function"==typeof ack){debug("calling ack %s with %j",packet.id,packet.data);ack.apply(this,packet.data);delete this.acks[packet.id]}else{debug("bad ack %s",packet.id)}};Socket.prototype.onconnect=function(){this.connected=true;this.disconnected=false;this.emit("connect");this.emitBuffered()};Socket.prototype.emitBuffered=function(){var i;for(i=0;i0&&opts.jitter<=1?opts.jitter:0;this.attempts=0}Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random();var deviation=Math.floor(rand*this.jitter*ms);ms=(Math.floor(rand*10)&1)==0?ms-deviation:ms+deviation}return Math.min(ms,this.max)|0};Backoff.prototype.reset=function(){this.attempts=0};Backoff.prototype.setMin=function(min){this.ms=min};Backoff.prototype.setMax=function(max){this.max=max};Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],37:[function(_dereq_,module,exports){var slice=[].slice;module.exports=function(obj,fn){if("string"==typeof fn)fn=obj[fn];if("function"!=typeof fn)throw new Error("bind() requires a function");var args=slice.call(arguments,2);return function(){return fn.apply(obj,args.concat(slice.call(arguments)))}}},{}],38:[function(_dereq_,module,exports){module.exports=Emitter;function Emitter(obj){if(obj)return mixin(obj)}function mixin(obj){for(var key in Emitter.prototype){obj[key]=Emitter.prototype[key]}return obj}Emitter.prototype.on=Emitter.prototype.addEventListener=function(event,fn){this._callbacks=this._callbacks||{};(this._callbacks["$"+event]=this._callbacks["$"+event]||[]).push(fn);return this};Emitter.prototype.once=function(event,fn){function on(){this.off(event,on);fn.apply(this,arguments)}on.fn=fn;this.on(event,on);return this};Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(event,fn){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var callbacks=this._callbacks["$"+event];if(!callbacks)return this;if(1==arguments.length){delete this._callbacks["$"+event];return this}var cb;for(var i=0;i1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)}}if(!(isProperty=objectProto.hasOwnProperty)){isProperty=function(property){var members={},constructor;if((members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass){isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);this.__proto__=original;return result}}else{constructor=members.constructor;isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}}members=null;return isProperty.call(this,property)}}forEach=function(object,callback){var size=0,Properties,members,property;(Properties=function(){this.valueOf=0}).prototype.valueOf=0;members=new Properties;for(property in members){if(isProperty.call(members,property)){size++}}Properties=members=null;if(!size){members=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,length;var hasProperty=!isFunction&&typeof object.constructor!="function"&&objectTypes[typeof object.hasOwnProperty]&&object.hasOwnProperty||isProperty;for(property in object){if(!(isFunction&&property=="prototype")&&hasProperty.call(object,property)){callback(property)}}for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}}else if(size==2){forEach=function(object,callback){var members={},isFunction=getClass.call(object)==functionClass,property;for(property in object){if(!(isFunction&&property=="prototype")&&!isProperty.call(members,property)&&(members[property]=1)&&isProperty.call(object,property)){callback(property)}}}}else{forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,isConstructor;for(property in object){if(!(isFunction&&property=="prototype")&&isProperty.call(object,property)&&!(isConstructor=property==="constructor")){callback(property)}}if(isConstructor||isProperty.call(object,property="constructor")){callback(property)}}}return forEach(object,callback)};if(!has("json-stringify")){var Escapes={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"};var leadingZeroes="000000";var toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)};var unicodePrefix="\\u00";var quote=function(value){var result='"',index=0,length=value.length,useCharIndex=!charIndexBuggy||length>10;var symbols=useCharIndex&&(charIndexBuggy?value.split(""):value);for(;index-1/0&&value<1/0){if(getDay){date=floor(value/864e5);for(year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month);time=(value%864e5+864e5)%864e5;hours=floor(time/36e5)%24;minutes=floor(time/6e4)%60;seconds=floor(time/1e3)%60;milliseconds=time%1e3}else{year=value.getUTCFullYear();month=value.getUTCMonth();date=value.getUTCDate();hours=value.getUTCHours();minutes=value.getUTCMinutes();seconds=value.getUTCSeconds();milliseconds=value.getUTCMilliseconds()}value=(year<=0||year>=1e4?(year<0?"-":"+")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+"-"+toPaddedString(2,month+1)+"-"+toPaddedString(2,date)+"T"+toPaddedString(2,hours)+":"+toPaddedString(2,minutes)+":"+toPaddedString(2,seconds)+"."+toPaddedString(3,milliseconds)+"Z"}else{value=null}}else if(typeof value.toJSON=="function"&&(className!=numberClass&&className!=stringClass&&className!=arrayClass||isProperty.call(value,"toJSON"))){value=value.toJSON(property)}}if(callback){value=callback.call(object,property,value)}if(value===null){return"null"}className=getClass.call(value);if(className==booleanClass){return""+value}else if(className==numberClass){return value>-1/0&&value<1/0?""+value:"null"}else if(className==stringClass){return quote(""+value)}if(typeof value=="object"){for(length=stack.length;length--;){if(stack[length]===value){throw TypeError()}}stack.push(value);results=[];prefix=indentation;indentation+=whitespace;if(className==arrayClass){for(index=0,length=value.length;index0){for(whitespace="",width>10&&(width=10);whitespace.length=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70)){abort()}}value+=fromCharCode("0x"+source.slice(begin,Index));break;default:abort()}}else{if(charCode==34){break}charCode=source.charCodeAt(Index);begin=Index;while(charCode>=32&&charCode!=92&&charCode!=34){charCode=source.charCodeAt(++Index)}value+=source.slice(begin,Index)}}if(source.charCodeAt(Index)==34){Index++;return value}abort();default:begin=Index;if(charCode==45){isSigned=true;charCode=source.charCodeAt(++Index)}if(charCode>=48&&charCode<=57){if(charCode==48&&(charCode=source.charCodeAt(Index+1),charCode>=48&&charCode<=57)){abort()}isSigned=false;for(;Index=48&&charCode<=57);Index++);if(source.charCodeAt(Index)==46){position=++Index;for(;position=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}charCode=source.charCodeAt(Index);if(charCode==101||charCode==69){charCode=source.charCodeAt(++Index);if(charCode==43||charCode==45){Index++}for(position=Index;position=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}return+source.slice(begin,Index)}if(isSigned){abort()}if(source.slice(Index,Index+4)=="true"){Index+=4;return true}else if(source.slice(Index,Index+5)=="false"){Index+=5;return false}else if(source.slice(Index,Index+4)=="null"){Index+=4;return null}abort()}}return"$"};var get=function(value){var results,hasMembers;if(value=="$"){abort()}if(typeof value=="string"){if((charIndexBuggy?value.charAt(0):value[0])=="@"){return value.slice(1)}if(value=="["){results=[];for(;;hasMembers||(hasMembers=true)){value=lex();if(value=="]"){break}if(hasMembers){if(value==","){value=lex();if(value=="]"){abort()}}else{abort()}}if(value==","){abort()}results.push(get(value))}return results}else if(value=="{"){results={};for(;;hasMembers||(hasMembers=true)){value=lex();if(value=="}"){break}if(hasMembers){if(value==","){value=lex();if(value=="}"){abort()}}else{abort()}}if(value==","||typeof value!="string"||(charIndexBuggy?value.charAt(0):value[0])!="@"||lex()!=":"){abort()}results[value.slice(1)]=get(lex())
4 | }return results}abort()}return value};var update=function(source,property,callback){var element=walk(source,property,callback);if(element===undef){delete source[property]}else{source[property]=element}};var walk=function(source,property,callback){var value=source[property],length;if(typeof value=="object"&&value){if(getClass.call(value)==arrayClass){for(length=value.length;length--;){update(value,length,callback)}}else{forEach(value,function(property){update(value,property,callback)})}}return callback.call(source,property,value)};exports.parse=function(source,callback){var result,value;Index=0;Source=""+source;result=get(lex());if(lex()!="$"){abort()}Index=Source=null;return callback&&getClass.call(callback)==functionClass?walk((value={},value[""]=result,value),"",callback):result}}}exports["runInContext"]=runInContext;return exports}if(freeExports&&!isLoader){runInContext(root,freeExports)}else{var nativeJSON=root.JSON,previousJSON=root["JSON3"],isRestored=false;var JSON3=runInContext(root,root["JSON3"]={noConflict:function(){if(!isRestored){isRestored=true;root.JSON=nativeJSON;root["JSON3"]=previousJSON;nativeJSON=previousJSON=null}return JSON3}});root.JSON={parse:JSON3.parse,stringify:JSON3.stringify}}if(isLoader){define(function(){return JSON3})}}).call(this)}).call(this,typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:{})},{}],51:[function(_dereq_,module,exports){module.exports=toArray;function toArray(list,index){var array=[];index=index||0;for(var i=index||0;i