vines 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/Rakefile +33 -53
- data/conf/certs/README +10 -3
- data/conf/certs/ca-bundle.crt +55 -410
- data/lib/vines/cluster/connection.rb +1 -1
- data/lib/vines/command/ldap.rb +1 -1
- data/lib/vines/command/schema.rb +1 -1
- data/lib/vines/config.rb +11 -5
- data/lib/vines/jid.rb +3 -3
- data/lib/vines/stanza/iq/disco_items.rb +1 -1
- data/lib/vines/storage/local.rb +1 -0
- data/lib/vines/store.rb +50 -9
- data/lib/vines/stream.rb +5 -9
- data/lib/vines/stream/client/session.rb +1 -1
- data/lib/vines/stream/http.rb +3 -1
- data/lib/vines/stream/http/ready.rb +5 -1
- data/lib/vines/stream/http/request.rb +22 -0
- data/lib/vines/version.rb +1 -1
- data/test/config/host_test.rb +9 -9
- data/test/config/pubsub_test.rb +2 -2
- data/test/config_test.rb +5 -3
- data/test/jid_test.rb +9 -0
- data/test/rake_test_loader.rb +1 -1
- data/test/router_test.rb +7 -7
- data/test/stanza/iq/disco_info_test.rb +2 -2
- data/test/stanza/iq/private_storage_test.rb +1 -1
- data/test/stanza/iq_test.rb +1 -1
- data/test/stanza/presence/subscribe_test.rb +1 -1
- data/test/stanza/pubsub/subscribe_test.rb +3 -3
- data/test/stanza/pubsub/unsubscribe_test.rb +3 -3
- data/test/storage_test.rb +15 -8
- data/test/store_test.rb +131 -0
- data/test/stream/client/ready_test.rb +6 -6
- data/test/stream/component/ready_test.rb +1 -1
- data/test/stream/http/ready_test.rb +46 -11
- data/test/stream/http/request_test.rb +83 -11
- data/test/stream/http/sessions_test.rb +2 -2
- data/web/chat/coffeescripts/chat.coffee +1 -1
- data/web/chat/index.html +9 -10
- data/web/chat/javascripts/app.js +1 -1
- data/web/lib/coffeescripts/button.coffee +1 -1
- data/web/lib/coffeescripts/contact.coffee +2 -2
- data/web/lib/coffeescripts/filter.coffee +1 -1
- data/web/lib/coffeescripts/layout.coffee +2 -2
- data/web/lib/coffeescripts/login.coffee +1 -1
- data/web/lib/coffeescripts/logout.coffee +2 -2
- data/web/lib/coffeescripts/navbar.coffee +1 -1
- data/web/lib/coffeescripts/notification.coffee +1 -1
- data/web/lib/coffeescripts/router.coffee +1 -1
- data/web/lib/coffeescripts/session.coffee +1 -1
- data/web/lib/coffeescripts/transfer.coffee +1 -1
- data/web/lib/javascripts/base.js +10 -9
- metadata +65 -43
- data/web/chat/javascripts/chat.js +0 -390
- data/web/chat/javascripts/init.js +0 -21
- data/web/lib/javascripts/button.js +0 -39
- data/web/lib/javascripts/contact.js +0 -94
- data/web/lib/javascripts/filter.js +0 -88
- data/web/lib/javascripts/layout.js +0 -48
- data/web/lib/javascripts/login.js +0 -88
- data/web/lib/javascripts/logout.js +0 -11
- data/web/lib/javascripts/navbar.js +0 -69
- data/web/lib/javascripts/notification.js +0 -26
- data/web/lib/javascripts/router.js +0 -105
- data/web/lib/javascripts/session.js +0 -291
- data/web/lib/javascripts/transfer.js +0 -124
@@ -1,291 +0,0 @@
|
|
1
|
-
var Session;
|
2
|
-
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
3
|
-
Session = (function() {
|
4
|
-
function Session() {
|
5
|
-
this.xmpp = new Strophe.Connection('/xmpp');
|
6
|
-
this.roster = {};
|
7
|
-
this.listeners = {
|
8
|
-
card: [],
|
9
|
-
message: [],
|
10
|
-
presence: [],
|
11
|
-
roster: []
|
12
|
-
};
|
13
|
-
}
|
14
|
-
Session.prototype.connect = function(jid, password, callback) {
|
15
|
-
return this.xmpp.connect(jid, password, __bind(function(status) {
|
16
|
-
switch (status) {
|
17
|
-
case Strophe.Status.AUTHFAIL:
|
18
|
-
case Strophe.Status.CONNFAIL:
|
19
|
-
return callback(false);
|
20
|
-
case Strophe.Status.CONNECTED:
|
21
|
-
this.xmpp.addHandler((__bind(function(el) {
|
22
|
-
return this.handleIq(el);
|
23
|
-
}, this)), null, 'iq');
|
24
|
-
this.xmpp.addHandler((__bind(function(el) {
|
25
|
-
return this.handleMessage(el);
|
26
|
-
}, this)), null, 'message');
|
27
|
-
this.xmpp.addHandler((__bind(function(el) {
|
28
|
-
return this.handlePresence(el);
|
29
|
-
}, this)), null, 'presence');
|
30
|
-
callback(true);
|
31
|
-
return this.findRoster(__bind(function() {
|
32
|
-
this.notify('roster');
|
33
|
-
this.xmpp.send(this.xml('<presence/>'));
|
34
|
-
return this.findCards();
|
35
|
-
}, this));
|
36
|
-
}
|
37
|
-
}, this));
|
38
|
-
};
|
39
|
-
Session.prototype.disconnect = function() {
|
40
|
-
return this.xmpp.disconnect();
|
41
|
-
};
|
42
|
-
Session.prototype.onCard = function(callback) {
|
43
|
-
return this.listeners['card'].push(callback);
|
44
|
-
};
|
45
|
-
Session.prototype.onRoster = function(callback) {
|
46
|
-
return this.listeners['roster'].push(callback);
|
47
|
-
};
|
48
|
-
Session.prototype.onMessage = function(callback) {
|
49
|
-
return this.listeners['message'].push(callback);
|
50
|
-
};
|
51
|
-
Session.prototype.onPresence = function(callback) {
|
52
|
-
return this.listeners['presence'].push(callback);
|
53
|
-
};
|
54
|
-
Session.prototype.connected = function() {
|
55
|
-
return this.xmpp.jid && this.xmpp.jid.length > 0;
|
56
|
-
};
|
57
|
-
Session.prototype.jid = function() {
|
58
|
-
return this.xmpp.jid;
|
59
|
-
};
|
60
|
-
Session.prototype.bareJid = function() {
|
61
|
-
return this.xmpp.jid.split('/')[0];
|
62
|
-
};
|
63
|
-
Session.prototype.uniqueId = function() {
|
64
|
-
return this.xmpp.getUniqueId();
|
65
|
-
};
|
66
|
-
Session.prototype.avatar = function(jid) {
|
67
|
-
var card;
|
68
|
-
card = this.loadCard(jid);
|
69
|
-
if (card && card.photo) {
|
70
|
-
return "data:" + card.photo.type + ";base64," + card.photo.binval;
|
71
|
-
} else {
|
72
|
-
return '/lib/images/default-user.png';
|
73
|
-
}
|
74
|
-
};
|
75
|
-
Session.prototype.loadCard = function(jid) {
|
76
|
-
var found;
|
77
|
-
jid = jid.split('/')[0];
|
78
|
-
found = localStorage['vcard:' + jid];
|
79
|
-
if (found) {
|
80
|
-
return JSON.parse(found);
|
81
|
-
}
|
82
|
-
};
|
83
|
-
Session.prototype.storeCard = function(card) {
|
84
|
-
return localStorage['vcard:' + card.jid] = JSON.stringify(card);
|
85
|
-
};
|
86
|
-
Session.prototype.findCards = function() {
|
87
|
-
var contacts, jid, jids, success;
|
88
|
-
jids = (function() {
|
89
|
-
var _ref, _results;
|
90
|
-
_ref = this.roster;
|
91
|
-
_results = [];
|
92
|
-
for (jid in _ref) {
|
93
|
-
contacts = _ref[jid];
|
94
|
-
if (!this.loadCard(jid)) {
|
95
|
-
_results.push(jid);
|
96
|
-
}
|
97
|
-
}
|
98
|
-
return _results;
|
99
|
-
}).call(this);
|
100
|
-
if (!this.loadCard(this.bareJid())) {
|
101
|
-
jids.push(this.bareJid());
|
102
|
-
}
|
103
|
-
success = __bind(function(card) {
|
104
|
-
this.findCard(jids.shift(), success);
|
105
|
-
if (card) {
|
106
|
-
this.storeCard(card);
|
107
|
-
return this.notify('card', card);
|
108
|
-
}
|
109
|
-
}, this);
|
110
|
-
return this.findCard(jids.shift(), success);
|
111
|
-
};
|
112
|
-
Session.prototype.findCard = function(jid, callback) {
|
113
|
-
var node;
|
114
|
-
if (!jid) {
|
115
|
-
return;
|
116
|
-
}
|
117
|
-
node = this.xml("<iq id=\"" + (this.uniqueId()) + "\" to=\"" + jid + "\" type=\"get\">\n <vCard xmlns=\"vcard-temp\"/>\n</iq>");
|
118
|
-
return this.sendIQ(node, function(result) {
|
119
|
-
var bin, card, photo, type, vcard;
|
120
|
-
card = $('vCard', result);
|
121
|
-
photo = $('PHOTO', card);
|
122
|
-
type = $('TYPE', photo).text();
|
123
|
-
bin = $('BINVAL', photo).text();
|
124
|
-
photo = type && bin ? {
|
125
|
-
type: type,
|
126
|
-
binval: bin.replace(/\n/g, '')
|
127
|
-
} : null;
|
128
|
-
vcard = {
|
129
|
-
jid: jid,
|
130
|
-
photo: photo,
|
131
|
-
retrieved: new Date()
|
132
|
-
};
|
133
|
-
return callback(card.size() > 0 ? vcard : null);
|
134
|
-
});
|
135
|
-
};
|
136
|
-
Session.prototype.parseRoster = function(node) {
|
137
|
-
return $('item', node).map(function() {
|
138
|
-
return new Contact(this);
|
139
|
-
}).get();
|
140
|
-
};
|
141
|
-
Session.prototype.findRoster = function(callback) {
|
142
|
-
var node;
|
143
|
-
node = this.xml("<iq id='" + (this.uniqueId()) + "' type=\"get\">\n <query xmlns=\"jabber:iq:roster\"/>\n</iq>");
|
144
|
-
return this.sendIQ(node, __bind(function(result) {
|
145
|
-
var contact, contacts, _i, _len;
|
146
|
-
contacts = this.parseRoster(result);
|
147
|
-
for (_i = 0, _len = contacts.length; _i < _len; _i++) {
|
148
|
-
contact = contacts[_i];
|
149
|
-
this.roster[contact.jid] = contact;
|
150
|
-
}
|
151
|
-
return callback();
|
152
|
-
}, this));
|
153
|
-
};
|
154
|
-
Session.prototype.sendMessage = function(jid, message) {
|
155
|
-
var node;
|
156
|
-
node = this.xml("<message id=\"" + (this.uniqueId()) + "\" to=\"" + jid + "\" type=\"chat\">\n <body></body>\n</message>");
|
157
|
-
$('body', node).text(message);
|
158
|
-
return this.xmpp.send(node);
|
159
|
-
};
|
160
|
-
Session.prototype.sendPresence = function(away, status) {
|
161
|
-
var node;
|
162
|
-
node = $(this.xml('<presence/>'));
|
163
|
-
if (away) {
|
164
|
-
node.append($(this.xml('<show>xa</show>')));
|
165
|
-
if (status !== 'Away') {
|
166
|
-
node.append($(this.xml('<status/>')).text(status));
|
167
|
-
}
|
168
|
-
} else {
|
169
|
-
if (status !== 'Available') {
|
170
|
-
node.append($(this.xml('<status/>')).text(status));
|
171
|
-
}
|
172
|
-
}
|
173
|
-
return this.xmpp.send(node);
|
174
|
-
};
|
175
|
-
Session.prototype.sendIQ = function(node, callback) {
|
176
|
-
return this.xmpp.sendIQ(node, callback, callback, 5000);
|
177
|
-
};
|
178
|
-
Session.prototype.updateContact = function(contact, add) {
|
179
|
-
var group, node, _i, _len, _ref;
|
180
|
-
node = this.xml("<iq id=\"" + (this.uniqueId()) + "\" type=\"set\">\n <query xmlns=\"jabber:iq:roster\">\n <item name=\"\" jid=\"" + contact.jid + "\"/>\n </query>\n</iq>");
|
181
|
-
$('item', node).attr('name', contact.name);
|
182
|
-
_ref = contact.groups;
|
183
|
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
184
|
-
group = _ref[_i];
|
185
|
-
$('item', node).append($(this.xml('<group></group>')).text(group));
|
186
|
-
}
|
187
|
-
this.xmpp.send(node);
|
188
|
-
if (add) {
|
189
|
-
return this.sendSubscribe(contact.jid);
|
190
|
-
}
|
191
|
-
};
|
192
|
-
Session.prototype.removeContact = function(jid) {
|
193
|
-
var node;
|
194
|
-
node = this.xml("<iq id=\"" + (this.uniqueId()) + "\" type=\"set\">\n <query xmlns=\"jabber:iq:roster\">\n <item jid=\"" + jid + "\" subscription=\"remove\"/>\n </query>\n</iq>");
|
195
|
-
return this.xmpp.send(node);
|
196
|
-
};
|
197
|
-
Session.prototype.sendSubscribe = function(jid) {
|
198
|
-
return this.xmpp.send(this.presence(jid, 'subscribe'));
|
199
|
-
};
|
200
|
-
Session.prototype.sendSubscribed = function(jid) {
|
201
|
-
return this.xmpp.send(this.presence(jid, 'subscribed'));
|
202
|
-
};
|
203
|
-
Session.prototype.sendUnsubscribed = function(jid) {
|
204
|
-
return this.xmpp.send(this.presence(jid, 'unsubscribed'));
|
205
|
-
};
|
206
|
-
Session.prototype.presence = function(to, type) {
|
207
|
-
return this.xml("<presence\n id=\"" + (this.uniqueId()) + "\"\n to=\"" + to + "\"\n type=\"" + type + "\"/>");
|
208
|
-
};
|
209
|
-
Session.prototype.handleIq = function(node) {
|
210
|
-
var contact, contacts, ns, old, type, _i, _len;
|
211
|
-
node = $(node);
|
212
|
-
type = node.attr('type');
|
213
|
-
ns = node.find('query').attr('xmlns');
|
214
|
-
if (type === 'set' && ns === 'jabber:iq:roster') {
|
215
|
-
contacts = this.parseRoster(node);
|
216
|
-
for (_i = 0, _len = contacts.length; _i < _len; _i++) {
|
217
|
-
contact = contacts[_i];
|
218
|
-
if (contact.subscription === 'remove') {
|
219
|
-
delete this.roster[contact.jid];
|
220
|
-
} else {
|
221
|
-
old = this.roster[contact.jid];
|
222
|
-
if (old) {
|
223
|
-
contact.presence = old.presence;
|
224
|
-
}
|
225
|
-
this.roster[contact.jid] = contact;
|
226
|
-
}
|
227
|
-
}
|
228
|
-
this.notify('roster');
|
229
|
-
}
|
230
|
-
return true;
|
231
|
-
};
|
232
|
-
Session.prototype.handleMessage = function(node) {
|
233
|
-
var body, from, thread, to, type;
|
234
|
-
node = $(node);
|
235
|
-
to = node.attr('to');
|
236
|
-
from = node.attr('from');
|
237
|
-
type = node.attr('type');
|
238
|
-
thread = node.find('thread').first();
|
239
|
-
body = node.find('body').first();
|
240
|
-
this.notify('message', {
|
241
|
-
to: to,
|
242
|
-
from: from,
|
243
|
-
type: type,
|
244
|
-
thread: thread.text(),
|
245
|
-
text: body.text(),
|
246
|
-
received: new Date(),
|
247
|
-
node: node
|
248
|
-
});
|
249
|
-
return true;
|
250
|
-
};
|
251
|
-
Session.prototype.handlePresence = function(node) {
|
252
|
-
var contact, from, presence, show, status, to, type;
|
253
|
-
node = $(node);
|
254
|
-
to = node.attr('to');
|
255
|
-
from = node.attr('from');
|
256
|
-
type = node.attr('type');
|
257
|
-
show = node.find('show').first();
|
258
|
-
status = node.find('status').first();
|
259
|
-
presence = {
|
260
|
-
to: to,
|
261
|
-
from: from,
|
262
|
-
status: status.text(),
|
263
|
-
show: show.text(),
|
264
|
-
type: type,
|
265
|
-
offline: type === 'unavailable' || type === 'error',
|
266
|
-
away: show.text() === 'away' || show.text() === 'xa',
|
267
|
-
dnd: show.text() === 'dnd',
|
268
|
-
node: node
|
269
|
-
};
|
270
|
-
contact = this.roster[from.split('/')[0]];
|
271
|
-
if (contact) {
|
272
|
-
contact.update(presence);
|
273
|
-
}
|
274
|
-
this.notify('presence', presence);
|
275
|
-
return true;
|
276
|
-
};
|
277
|
-
Session.prototype.notify = function(type, obj) {
|
278
|
-
var callback, _i, _len, _ref, _results;
|
279
|
-
_ref = this.listeners[type] || [];
|
280
|
-
_results = [];
|
281
|
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
282
|
-
callback = _ref[_i];
|
283
|
-
_results.push(callback(obj));
|
284
|
-
}
|
285
|
-
return _results;
|
286
|
-
};
|
287
|
-
Session.prototype.xml = function(xml) {
|
288
|
-
return $.parseXML(xml).documentElement;
|
289
|
-
};
|
290
|
-
return Session;
|
291
|
-
})();
|
@@ -1,124 +0,0 @@
|
|
1
|
-
var Transfer;
|
2
|
-
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
3
|
-
Transfer = (function() {
|
4
|
-
var Chunks;
|
5
|
-
function Transfer(options) {
|
6
|
-
this.session = options.session;
|
7
|
-
this.file = options.file;
|
8
|
-
this.to = options.to;
|
9
|
-
this.progress = options.progress;
|
10
|
-
this.complete = options.complete;
|
11
|
-
this.chunks = new Chunks(this.file);
|
12
|
-
this.opened = false;
|
13
|
-
this.closed = false;
|
14
|
-
this.sid = this.session.uniqueId();
|
15
|
-
this.seq = 0;
|
16
|
-
this.sent = 0;
|
17
|
-
}
|
18
|
-
Transfer.prototype.start = function() {
|
19
|
-
var node;
|
20
|
-
node = $("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + this.to + "\" type=\"set\">\n <si xmlns=\"http://jabber.org/protocol/si\" id=\"" + (this.session.uniqueId()) + "\" profile=\"http://jabber.org/protocol/si/profile/file-transfer\">\n <file xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\" name=\"\" size=\"" + this.file.size + "\"/>\n <feature xmlns=\"http://jabber.org/protocol/feature-neg\">\n <x xmlns=\"jabber:x:data\" type=\"form\">\n <field var=\"stream-method\" type=\"list-single\">\n <option><value>http://jabber.org/protocol/ibb</value></option>\n </field>\n </x>\n </feature>\n </si>\n</iq>");
|
21
|
-
$('file', node).attr('name', this.file.name);
|
22
|
-
return this.session.sendIQ(node.get(0), __bind(function(result) {
|
23
|
-
var m, methods, ok;
|
24
|
-
methods = $('si feature x field[var="stream-method"] value', result);
|
25
|
-
ok = ((function() {
|
26
|
-
var _i, _len, _results;
|
27
|
-
_results = [];
|
28
|
-
for (_i = 0, _len = methods.length; _i < _len; _i++) {
|
29
|
-
m = methods[_i];
|
30
|
-
if ($(m).text() === 'http://jabber.org/protocol/ibb') {
|
31
|
-
_results.push(true);
|
32
|
-
}
|
33
|
-
}
|
34
|
-
return _results;
|
35
|
-
})()).length > 0;
|
36
|
-
if (ok) {
|
37
|
-
return this.open();
|
38
|
-
}
|
39
|
-
}, this));
|
40
|
-
};
|
41
|
-
Transfer.prototype.open = function() {
|
42
|
-
var node;
|
43
|
-
node = $("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + this.to + "\" type=\"set\">\n <open xmlns=\"http://jabber.org/protocol/ibb\" sid=\"" + this.sid + "\" block-size=\"4096\"/>\n</iq>");
|
44
|
-
return this.session.sendIQ(node.get(0), __bind(function(result) {
|
45
|
-
if (this.ok(result)) {
|
46
|
-
this.opened = true;
|
47
|
-
return this.sendChunk();
|
48
|
-
}
|
49
|
-
}, this));
|
50
|
-
};
|
51
|
-
Transfer.prototype.sendChunk = function() {
|
52
|
-
if (this.closed) {
|
53
|
-
return;
|
54
|
-
}
|
55
|
-
return this.chunks.chunk(__bind(function(chunk) {
|
56
|
-
var node;
|
57
|
-
if (!chunk) {
|
58
|
-
this.close();
|
59
|
-
return;
|
60
|
-
}
|
61
|
-
node = $("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + this.to + "\" type=\"set\">\n <data xmlns=\"http://jabber.org/protocol/ibb\" sid=\"" + this.sid + "\" seq=\"" + (this.seq++) + "\">" + chunk + "</data>\n</iq>");
|
62
|
-
if (this.seq > 65535) {
|
63
|
-
this.seq = 0;
|
64
|
-
}
|
65
|
-
return this.session.sendIQ(node.get(0), __bind(function(result) {
|
66
|
-
var pct;
|
67
|
-
if (!this.ok(result)) {
|
68
|
-
return;
|
69
|
-
}
|
70
|
-
pct = Math.ceil(++this.sent / this.chunks.total * 100);
|
71
|
-
this.progress(pct);
|
72
|
-
return this.sendChunk();
|
73
|
-
}, this));
|
74
|
-
}, this));
|
75
|
-
};
|
76
|
-
Transfer.prototype.close = function() {
|
77
|
-
var node;
|
78
|
-
if (this.closed) {
|
79
|
-
return;
|
80
|
-
}
|
81
|
-
this.closed = true;
|
82
|
-
node = $("<iq id=\"" + (this.session.uniqueId()) + "\" to=\"" + this.to + "\" type=\"set\">\n <close xmlns=\"http://jabber.org/protocol/ibb\" sid=\"" + this.sid + "\"/>\n</iq>");
|
83
|
-
this.session.sendIQ(node.get(0), function() {});
|
84
|
-
return this.complete();
|
85
|
-
};
|
86
|
-
Transfer.prototype.stop = function() {
|
87
|
-
if (this.opened) {
|
88
|
-
return this.close();
|
89
|
-
} else {
|
90
|
-
return this.complete();
|
91
|
-
}
|
92
|
-
};
|
93
|
-
Transfer.prototype.ok = function(result) {
|
94
|
-
return $(result).attr('type') === 'result';
|
95
|
-
};
|
96
|
-
Chunks = (function() {
|
97
|
-
var CHUNK_SIZE;
|
98
|
-
CHUNK_SIZE = 3 / 4 * 4096;
|
99
|
-
function Chunks(file) {
|
100
|
-
this.file = file;
|
101
|
-
this.total = Math.ceil(this.file.size / CHUNK_SIZE);
|
102
|
-
this.slice = this.file.slice || this.file.webkitSlice || this.file.mozSlice;
|
103
|
-
this.pos = 0;
|
104
|
-
}
|
105
|
-
Chunks.prototype.chunk = function(callback) {
|
106
|
-
var chunk, end, reader, start;
|
107
|
-
start = this.pos;
|
108
|
-
end = this.pos + CHUNK_SIZE;
|
109
|
-
this.pos = end;
|
110
|
-
if (start > this.file.size) {
|
111
|
-
return callback(null);
|
112
|
-
} else {
|
113
|
-
chunk = this.slice.call(this.file, start, end);
|
114
|
-
reader = new FileReader();
|
115
|
-
reader.onload = function(event) {
|
116
|
-
return callback(btoa(event.target.result));
|
117
|
-
};
|
118
|
-
return reader.readAsBinaryString(chunk);
|
119
|
-
}
|
120
|
-
};
|
121
|
-
return Chunks;
|
122
|
-
})();
|
123
|
-
return Transfer;
|
124
|
-
})();
|