28 | )
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/background/lib/torrent-stream/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2014 Mathias Buus Madsen
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/background/lib/local-storage.js:
--------------------------------------------------------------------------------
1 | var Jsonfile = require('jsonfile')
2 | var Defer = require("node-promise").defer
3 | var App = require('app')
4 |
5 | var CLIENTS_JSON_FILE_PATH = App.getPath('userCache') + '/' + 'clients.json';
6 | var SETTING_JSON_FILE_PATH = App.getPath('userCache') + '/' + 'setting.json';
7 |
8 | var LocalStorage = function() {
9 | function saveDefaultPath() {
10 |
11 | }
12 |
13 | function saveSettings() {
14 |
15 | }
16 |
17 | function saveClients(clients) {
18 | var deferred = Defer();
19 | Jsonfile.writeFile(CLIENTS_JSON_FILE_PATH, clients, function(err) {
20 | deferred.resolve();
21 | });
22 | return deferred.promise;
23 | }
24 |
25 | function getClients() {
26 | var deferred = Defer();
27 | Jsonfile.readFile(CLIENTS_JSON_FILE_PATH, function (err, clients) {
28 | if (!err && clients) {
29 | deferred.resolve(clients);
30 | }
31 | });
32 | return deferred.promise;
33 | }
34 |
35 | return {
36 | saveClients: saveClients,
37 | getClients: getClients
38 | }
39 | }
40 |
41 | module.exports = new LocalStorage;
42 |
--------------------------------------------------------------------------------
/app/routes/routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Route, DefaultRoute } from 'react-router'
3 |
4 | import AppContainer from '../containers/AppContainer'
5 |
6 | import QueueAllContainer from '../containers/QueueAllContainer'
7 | import QueueDownloadContainer from '../containers/QueueDownloadContainer'
8 | import QueueStopContainer from '../containers/QueueStopContainer'
9 | import QueueCompleteContainer from '../containers/QueueCompleteContainer'
10 |
11 | import PageSettingContainer from '../containers/PageSettingContainer'
12 | import PageAboutContainer from '../containers/PageAboutContainer'
13 |
14 |
15 | export default (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | )
25 |
--------------------------------------------------------------------------------
/app/containers/PageSettingContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | import { Input } from 'react-bootstrap'
4 |
5 | export default class PageSettingContainer extends React.Component {
6 |
7 | render() {
8 | return (
9 |
293 | )
294 | }
295 |
296 | }
297 |
--------------------------------------------------------------------------------
/background/lib/torrent-stream/index.js:
--------------------------------------------------------------------------------
1 | var hat = require('hat');
2 | var pws = require('peer-wire-swarm');
3 | var bncode = require('bncode');
4 | var crypto = require('crypto');
5 | var bitfield = require('bitfield');
6 | var parseTorrent = require('parse-torrent');
7 | var mkdirp = require('mkdirp');
8 | var events = require('events');
9 | var path = require('path');
10 | var fs = require('fs');
11 | var os = require('os');
12 | var eos = require('end-of-stream');
13 |
14 | var peerDiscovery = require('./lib/peer-discovery');
15 | var blocklist = require('ip-set');
16 | var exchangeMetadata = require('./lib/exchange-metadata');
17 | var storage = require('./lib/storage');
18 | var storageBuffer = require('./lib/storage-buffer');
19 | var fileStream = require('./lib/file-stream');
20 | var piece = require('./lib/piece');
21 |
22 | var MAX_REQUESTS = 5;
23 | var CHOKE_TIMEOUT = 5000;
24 | var REQUEST_TIMEOUT = 30000;
25 | var SPEED_THRESHOLD = 3 * piece.BLOCK_SIZE;
26 | var DEFAULT_PORT = 6881;
27 |
28 | var BAD_PIECE_STRIKES_MAX = 3;
29 | var BAD_PIECE_STRIKES_DURATION = 120000; // 2 minutes
30 |
31 | var RECHOKE_INTERVAL = 10000;
32 | var RECHOKE_OPTIMISTIC_DURATION = 2;
33 |
34 | var TMP = fs.existsSync('/tmp') ? '/tmp' : os.tmpDir();
35 |
36 | var noop = function() {};
37 |
38 | var sha1 = function(data) {
39 | return crypto.createHash('sha1').update(data).digest('hex');
40 | };
41 |
42 | var thruthy = function() {
43 | return true;
44 | };
45 |
46 | var falsy = function() {
47 | return false;
48 | };
49 |
50 | var toNumber = function(val) {
51 | return val === true ? 1 : (val || 0);
52 | };
53 |
54 | var torrentStream = function(link, opts, cb) {
55 | if (typeof opts === 'function') return torrentStream(link, null, opts);
56 |
57 | link = parseTorrent(link);
58 | var metadata = link.infoBuffer || null;
59 | var infoHash = link.infoHash;
60 |
61 | if (!opts) opts = {};
62 | if (!opts.id) opts.id = '-TS0008-'+hat(48);
63 | if (!opts.tmp) opts.tmp = TMP;
64 | if (!opts.name) opts.name = 'torrent-stream';
65 | if (!opts.flood) opts.flood = 0; // Pulse defaults:
66 | if (!opts.pulse) opts.pulse = Number.MAX_SAFE_INTEGER; // Do not pulse
67 |
68 | var usingTmp = false;
69 | var destroyed = false;
70 |
71 | if (!opts.path) {
72 | usingTmp = true;
73 | opts.path = path.join(opts.tmp, opts.name, infoHash);
74 | }
75 |
76 | var engine = new events.EventEmitter();
77 | var swarm = pws(infoHash, opts.id, { size: (opts.connections || opts.size), speed: 10 });
78 | var torrentPath = path.join(opts.tmp, opts.name, infoHash + '.torrent');
79 |
80 | if (cb) engine.on('ready', cb.bind(null, engine));
81 |
82 | engine.ready = function (cb) {
83 | if (engine.torrent) cb();
84 | else engine.once('ready', cb);
85 | }
86 |
87 | var wires = swarm.wires;
88 | var critical = [];
89 | var refresh = noop;
90 |
91 | var rechokeSlots = (opts.uploads === false || opts.uploads === 0) ? 0 : (+opts.uploads || 10);
92 | var rechokeOptimistic = null;
93 | var rechokeOptimisticTime = 0;
94 | var rechokeIntervalId;
95 |
96 | engine.infoHash = infoHash;
97 | engine.metadata = metadata;
98 | engine.path = opts.path;
99 | engine.files = [];
100 | engine.selection = [];
101 | engine.torrent = null;
102 | engine.bitfield = null;
103 | engine.amInterested = false;
104 | engine.store = null;
105 | engine.swarm = swarm;
106 | engine._flood = opts.flood;
107 | engine._pulse = opts.pulse;
108 |
109 | var discovery = peerDiscovery(opts);
110 | var blocked = blocklist(opts.blocklist);
111 |
112 | discovery.on('peer', function(addr) {
113 | if (blocked.contains(addr.split(':')[0])) {
114 | engine.emit('blocked-peer', addr);
115 | } else {
116 | engine.emit('peer', addr);
117 | engine.connect(addr);
118 | }
119 | });
120 |
121 | var ontorrent = function(torrent) {
122 | engine.store = storageBuffer((opts.storage || storage(opts.path))(torrent, opts));
123 | engine.torrent = torrent;
124 | engine.bitfield = bitfield(torrent.pieces.length);
125 |
126 | var pieceLength = torrent.pieceLength;
127 | var pieceRemainder = (torrent.length % pieceLength) || pieceLength;
128 |
129 | var pieces = torrent.pieces.map(function(hash, i) {
130 | return piece(i === torrent.pieces.length-1 ? pieceRemainder : pieceLength);
131 | });
132 | var reservations = torrent.pieces.map(function() {
133 | return [];
134 | });
135 |
136 | discovery.setTorrent(torrent);
137 |
138 |
139 | // Customize Total Progress API
140 | engine.getProgress = function() {
141 | var completePiecesLength = 0;
142 |
143 | pieces.forEach(function(piece) {
144 | if (!piece)
145 | completePiecesLength++;
146 | });
147 |
148 | return completePiecesLength / pieces.length;
149 | };
150 |
151 | // Customize File Progress API
152 | engine.torrent.files.forEach(function(file) {
153 | file.getProgress = function() {
154 | var fileStart = file.offset;
155 | var fileEnd = file.offset + file.length;
156 |
157 | var firstPiece = Math.floor(fileStart / pieceLength);
158 | var lastPiece = Math.floor((fileEnd - 1) / pieceLength);
159 |
160 | var completePiecesLength = 0;
161 | var filePieceLength = lastPiece - firstPiece + 1;
162 |
163 | for (var i = firstPiece; i <= lastPiece; i++) {
164 | if (!pieces[i])
165 | completePiecesLength++;
166 | }
167 |
168 | return completePiecesLength / filePieceLength;
169 | }
170 | });
171 |
172 | engine.files = torrent.files.map(function(file) {
173 | file = Object.create(file);
174 | var offsetPiece = (file.offset / torrent.pieceLength) | 0;
175 | var endPiece = ((file.offset+file.length-1) / torrent.pieceLength) | 0;
176 |
177 | file.deselect = function() {
178 | engine.deselect(offsetPiece, endPiece, false);
179 | };
180 |
181 | file.select = function() {
182 | engine.select(offsetPiece, endPiece, false);
183 | };
184 |
185 | file.createReadStream = function(opts) {
186 | var stream = fileStream(engine, file, opts);
187 |
188 | var notify = stream.notify.bind(stream);
189 | engine.select(stream.startPiece, stream.endPiece, true, notify);
190 | eos(stream, function() {
191 | engine.deselect(stream.startPiece, stream.endPiece, true, notify);
192 | });
193 |
194 | return stream;
195 | };
196 |
197 | return file;
198 | });
199 |
200 | // Customize Total Progress API
201 | engine.getProgress = function() {
202 | var completePiecesLength = 0;
203 |
204 | pieces.forEach(function(piece) {
205 | if (!piece)
206 | completePiecesLength++;
207 | });
208 |
209 | return completePiecesLength / pieces.length;
210 | };
211 |
212 | // Customize File Progress API
213 | engine.files.forEach(function(file) {
214 | file.getProgress = function() {
215 | var fileStart = file.offset;
216 | var fileEnd = file.offset + file.length;
217 |
218 | var firstPiece = Math.floor(fileStart / pieceLength);
219 | var lastPiece = Math.floor((fileEnd - 1) / pieceLength);
220 |
221 | var completePiecesLength = 0;
222 | var filePieceLength = lastPiece - firstPiece + 1;
223 |
224 | for (var i = firstPiece; i <= lastPiece; i++) {
225 | if (!pieces[i])
226 | completePiecesLength++;
227 | }
228 |
229 | return completePiecesLength / filePieceLength;
230 | }
231 | });
232 |
233 | var oninterestchange = function() {
234 | var prev = engine.amInterested;
235 | engine.amInterested = !!engine.selection.length;
236 |
237 | wires.forEach(function(wire) {
238 | if (engine.amInterested) wire.interested();
239 | else wire.uninterested();
240 | });
241 |
242 | if (prev === engine.amInterested) return;
243 | if (engine.amInterested) engine.emit('interested');
244 | else engine.emit('uninterested');
245 | };
246 |
247 | var gc = function() {
248 | for (var i = 0; i < engine.selection.length; i++) {
249 | var s = engine.selection[i];
250 | var oldOffset = s.offset;
251 |
252 | while (!pieces[s.from+s.offset] && s.from+s.offset < s.to) s.offset++;
253 |
254 | if (oldOffset !== s.offset) s.notify();
255 | if (s.to !== s.from+s.offset) continue;
256 | if (pieces[s.from+s.offset]) continue;
257 |
258 | engine.selection.splice(i, 1);
259 | i--; // -1 to offset splice
260 | s.notify();
261 | oninterestchange();
262 | }
263 |
264 | if (!engine.selection.length) engine.emit('idle');
265 | };
266 |
267 | var onpiececomplete = function(index, buffer) {
268 | if (!pieces[index]) return;
269 |
270 | pieces[index] = null;
271 | reservations[index] = null;
272 | engine.bitfield.set(index, true);
273 |
274 | for (var i = 0; i < wires.length; i++) wires[i].have(index);
275 |
276 | engine.emit('verify', index);
277 | engine.emit('download', index, buffer);
278 |
279 | engine.store.write(index, buffer);
280 | gc();
281 | };
282 |
283 | var onhotswap = opts.hotswap === false ? falsy : function(wire, index) {
284 | var speed = wire.downloadSpeed();
285 | if (speed < piece.BLOCK_SIZE) return;
286 | if (!reservations[index] || !pieces[index]) return;
287 |
288 | var r = reservations[index];
289 | var minSpeed = Infinity;
290 | var min;
291 |
292 | for (var i = 0; i < r.length; i++) {
293 | var other = r[i];
294 | if (!other || other === wire) continue;
295 |
296 | var otherSpeed = other.downloadSpeed();
297 | if (otherSpeed >= SPEED_THRESHOLD) continue;
298 | if (2 * otherSpeed > speed || otherSpeed > minSpeed) continue;
299 |
300 | min = other;
301 | minSpeed = otherSpeed;
302 | }
303 |
304 | if (!min) return false;
305 |
306 | for (i = 0; i < r.length; i++) {
307 | if (r[i] === min) r[i] = null;
308 | }
309 |
310 | for (i = 0; i < min.requests.length; i++) {
311 | var req = min.requests[i];
312 | if (req.piece !== index) continue;
313 | pieces[index].cancel((req.offset / piece.BLOCK_SIZE) | 0);
314 | }
315 |
316 | engine.emit('hotswap', min, wire, index);
317 | return true;
318 | };
319 |
320 | var onupdatetick = function() {
321 | process.nextTick(onupdate);
322 | };
323 |
324 | var onrequest = function(wire, index, hotswap) {
325 | if (!pieces[index]) return false;
326 |
327 | var p = pieces[index];
328 | var reservation = p.reserve();
329 |
330 | if (reservation === -1 && hotswap && onhotswap(wire, index)) reservation = p.reserve();
331 | if (reservation === -1) return false;
332 |
333 | var r = reservations[index] || [];
334 | var offset = p.offset(reservation);
335 | var size = p.size(reservation);
336 |
337 | var i = r.indexOf(null);
338 | if (i === -1) i = r.length;
339 | r[i] = wire;
340 |
341 | wire.request(index, offset, size, function(err, block) {
342 | if (r[i] === wire) r[i] = null;
343 |
344 | if (p !== pieces[index]) return onupdatetick();
345 |
346 | if (err) {
347 | p.cancel(reservation);
348 | onupdatetick();
349 | return;
350 | }
351 |
352 | if (!p.set(reservation, block, wire)) return onupdatetick();
353 |
354 | var sources = p.sources;
355 | var buffer = p.flush();
356 |
357 | if (sha1(buffer) !== torrent.pieces[index]) {
358 | pieces[index] = piece(p.length);
359 | engine.emit('invalid-piece', index, buffer);
360 | onupdatetick();
361 |
362 | sources.forEach(function(wire) {
363 | var now = Date.now();
364 |
365 | wire.badPieceStrikes = wire.badPieceStrikes.filter(function(strike) {
366 | return (now - strike) < BAD_PIECE_STRIKES_DURATION;
367 | });
368 |
369 | wire.badPieceStrikes.push(now);
370 |
371 | if (wire.badPieceStrikes.length > BAD_PIECE_STRIKES_MAX) {
372 | engine.block(wire.peerAddress);
373 | }
374 | });
375 |
376 | return;
377 | }
378 |
379 | onpiececomplete(index, buffer);
380 | onupdatetick();
381 | });
382 |
383 | return true;
384 | };
385 |
386 | var onvalidatewire = function(wire) {
387 | if (wire.requests.length) return;
388 |
389 | for (var i = engine.selection.length-1; i >= 0; i--) {
390 | var next = engine.selection[i];
391 | for (var j = next.to; j >= next.from + next.offset; j--) {
392 | if (!wire.peerPieces[j]) continue;
393 | if (onrequest(wire, j, false)) return;
394 | }
395 | }
396 | };
397 |
398 | var speedRanker = function(wire) {
399 | var speed = wire.downloadSpeed() || 1;
400 | if (speed > SPEED_THRESHOLD) return thruthy;
401 |
402 | var secs = MAX_REQUESTS * piece.BLOCK_SIZE / speed;
403 | var tries = 10;
404 | var ptr = 0;
405 |
406 | return function(index) {
407 | if (!tries || !pieces[index]) return true;
408 |
409 | var missing = pieces[index].missing;
410 | for (; ptr < wires.length; ptr++) {
411 | var other = wires[ptr];
412 | var otherSpeed = other.downloadSpeed();
413 |
414 | if (otherSpeed < SPEED_THRESHOLD) continue;
415 | if (otherSpeed <= speed || !other.peerPieces[index]) continue;
416 | if ((missing -= otherSpeed * secs) > 0) continue;
417 |
418 | tries--;
419 | return false;
420 | }
421 |
422 | return true;
423 | };
424 | };
425 |
426 | var shufflePriority = function(i) {
427 | var last = i;
428 | for (var j = i; j < engine.selection.length && engine.selection[j].priority; j++) {
429 | last = j;
430 | }
431 | var tmp = engine.selection[i];
432 | engine.selection[i] = engine.selection[last];
433 | engine.selection[last] = tmp;
434 | };
435 |
436 | var select = function(wire, hotswap) {
437 | if (wire.requests.length >= MAX_REQUESTS) return true;
438 |
439 | // Pulse, or flood (default)
440 | if (swarm.downloaded > engine._flood && swarm.downloadSpeed() > engine._pulse)
441 | return true;
442 |
443 | var rank = speedRanker(wire);
444 |
445 | for (var i = 0; i < engine.selection.length; i++) {
446 | var next = engine.selection[i];
447 | for (var j = next.from + next.offset; j <= next.to; j++) {
448 | if (!wire.peerPieces[j] || !rank(j)) continue;
449 | while (wire.requests.length < MAX_REQUESTS && onrequest(wire, j, critical[j] || hotswap));
450 | if (wire.requests.length < MAX_REQUESTS) continue;
451 | if (next.priority) shufflePriority(i);
452 | return true;
453 | }
454 | }
455 |
456 | return false;
457 | };
458 |
459 | var onupdatewire = function(wire) {
460 | if (wire.peerChoking) return;
461 | if (!wire.downloaded) return onvalidatewire(wire);
462 | select(wire, false) || select(wire, true);
463 | };
464 |
465 | var onupdate = function() {
466 | wires.forEach(onupdatewire);
467 | };
468 |
469 | var onwire = function(wire) {
470 | wire.setTimeout(opts.timeout || REQUEST_TIMEOUT, function() {
471 | engine.emit('timeout', wire);
472 | wire.destroy();
473 | });
474 |
475 | if (engine.selection.length) wire.interested();
476 |
477 | var timeout = CHOKE_TIMEOUT;
478 | var id;
479 |
480 | var onchoketimeout = function() {
481 | if (swarm.queued > 2 * (swarm.size - swarm.wires.length) && wire.amInterested) return wire.destroy();
482 | id = setTimeout(onchoketimeout, timeout);
483 | };
484 |
485 | wire.on('close', function() {
486 | clearTimeout(id);
487 | });
488 |
489 | wire.on('choke', function() {
490 | clearTimeout(id);
491 | id = setTimeout(onchoketimeout, timeout);
492 | });
493 |
494 | wire.on('unchoke', function() {
495 | clearTimeout(id);
496 | });
497 |
498 | wire.on('request', function(index, offset, length, cb) {
499 | if (pieces[index]) return;
500 | engine.store.read(index, { offset: offset, length: length }, function(err, buffer) {
501 | if (err) return cb(err);
502 | engine.emit('upload', index, offset, length);
503 | cb(null, buffer);
504 | });
505 | });
506 |
507 | wire.on('unchoke', onupdate);
508 | wire.on('bitfield', onupdate);
509 | wire.on('have', onupdate);
510 |
511 | wire.isSeeder = false;
512 |
513 | var i = 0;
514 | var checkseeder = function() {
515 | if (wire.peerPieces.length !== torrent.pieces.length) return;
516 | for (; i < torrent.pieces.length; ++i) {
517 | if (!wire.peerPieces[i]) return;
518 | }
519 | wire.isSeeder = true;
520 | };
521 |
522 | wire.on('bitfield', checkseeder);
523 | wire.on('have', checkseeder);
524 | checkseeder();
525 |
526 | wire.badPieceStrikes = [];
527 |
528 | id = setTimeout(onchoketimeout, timeout);
529 | };
530 |
531 | var rechokeSort = function(a, b) {
532 | // Prefer higher download speed
533 | if (a.downSpeed !== b.downSpeed) return a.downSpeed > b.downSpeed ? -1 : 1;
534 | // Prefer higher upload speed
535 | if (a.upSpeed !== b.upSpeed) return a.upSpeed > b.upSpeed ? -1 : 1;
536 | // Prefer unchoked
537 | if (a.wasChoked !== b.wasChoked) return a.wasChoked ? 1 : -1;
538 | // Random order
539 | return a.salt - b.salt;
540 | };
541 |
542 | var onrechoke = function() {
543 | if (rechokeOptimisticTime > 0) --rechokeOptimisticTime;
544 | else rechokeOptimistic = null;
545 |
546 | var peers = [];
547 |
548 | wires.forEach(function(wire) {
549 | if (wire.isSeeder) {
550 | if (!wire.amChoking) wire.choke();
551 | } else if (wire !== rechokeOptimistic) {
552 | peers.push({
553 | wire: wire,
554 | downSpeed: wire.downloadSpeed(),
555 | upSpeed: wire.uploadSpeed(),
556 | salt: Math.random(),
557 | interested: wire.peerInterested,
558 | wasChoked: wire.amChoking,
559 | isChoked: true
560 | });
561 | }
562 | });
563 |
564 | peers.sort(rechokeSort);
565 |
566 | var i = 0;
567 | var unchokeInterested = 0;
568 | for (; i < peers.length && unchokeInterested < rechokeSlots; ++i) {
569 | peers[i].isChoked = false;
570 | if (peers[i].interested) ++unchokeInterested;
571 | }
572 |
573 | if (!rechokeOptimistic && i < peers.length && rechokeSlots) {
574 | var candidates = peers.slice(i).filter(function(peer) { return peer.interested; });
575 | var optimistic = candidates[(Math.random() * candidates.length) | 0];
576 |
577 | if (optimistic) {
578 | optimistic.isChoked = false;
579 | rechokeOptimistic = optimistic.wire;
580 | rechokeOptimisticTime = RECHOKE_OPTIMISTIC_DURATION;
581 | }
582 | }
583 |
584 | peers.forEach(function(peer) {
585 | if (peer.wasChoked !== peer.isChoked) {
586 | if (peer.isChoked) peer.wire.choke();
587 | else peer.wire.unchoke();
588 | }
589 | });
590 | };
591 |
592 | var onready = function() {
593 | swarm.on('wire', onwire);
594 | swarm.wires.forEach(onwire);
595 |
596 | refresh = function() {
597 | process.nextTick(gc);
598 | oninterestchange();
599 | onupdate();
600 | };
601 |
602 | rechokeIntervalId = setInterval(onrechoke, RECHOKE_INTERVAL);
603 |
604 | engine.emit('ready');
605 | refresh();
606 | };
607 |
608 | if (opts.verify === false) return onready();
609 |
610 | engine.emit('verifying');
611 |
612 | var loop = function(i) {
613 | if (i >= torrent.pieces.length) return onready();
614 | engine.store.read(i, function(_, buf) {
615 | if (!buf || sha1(buf) !== torrent.pieces[i] || !pieces[i]) return loop(i+1);
616 | pieces[i] = null;
617 | engine.bitfield.set(i, true);
618 | engine.emit('verify', i);
619 | loop(i+1);
620 | });
621 | };
622 |
623 | loop(0);
624 | };
625 |
626 | var exchange = exchangeMetadata(engine, function(metadata) {
627 | var buf = bncode.encode({
628 | info: bncode.decode(metadata),
629 | 'announce-list': []
630 | });
631 |
632 | ontorrent(parseTorrent(buf));
633 |
634 | mkdirp(path.dirname(torrentPath), function(err) {
635 | if (err) return engine.emit('error', err);
636 | fs.writeFile(torrentPath, buf, function(err) {
637 | if (err) engine.emit('error', err);
638 | });
639 | });
640 | });
641 |
642 | swarm.on('wire', function(wire) {
643 | engine.emit('wire', wire);
644 | exchange(wire);
645 | if (engine.bitfield) wire.bitfield(engine.bitfield);
646 | });
647 |
648 | swarm.pause();
649 |
650 | if (link.files && engine.metadata) {
651 | swarm.resume();
652 | ontorrent(link);
653 | } else {
654 | fs.readFile(torrentPath, function(_, buf) {
655 | if (destroyed) return;
656 | swarm.resume();
657 |
658 | // We know only infoHash here, not full infoDictionary.
659 | // But infoHash is enough to connect to trackers and get peers.
660 | if (!buf) return discovery.setTorrent(link);
661 |
662 | var torrent = parseTorrent(buf);
663 |
664 | // Bad cache file - fetch it again
665 | if (torrent.infoHash !== infoHash) return discovery.setTorrent(link);
666 |
667 | if (!torrent.announce || !torrent.announce.length) {
668 | opts.trackers = [].concat(opts.trackers || []).concat(link.announce || []);
669 | }
670 |
671 | engine.metadata = torrent.infoBuffer;
672 | ontorrent(torrent);
673 | });
674 | }
675 |
676 | engine.critical = function(piece, width) {
677 | for (var i = 0; i < (width || 1); i++) critical[piece+i] = true;
678 | };
679 |
680 | engine.select = function(from, to, priority, notify) {
681 | engine.selection.push({
682 | from:from,
683 | to:to,
684 | offset:0,
685 | priority: toNumber(priority),
686 | notify: notify || noop
687 | });
688 |
689 | engine.selection.sort(function(a, b) {
690 | return b.priority - a.priority;
691 | });
692 |
693 | refresh();
694 | };
695 |
696 | engine.deselect = function(from, to, priority, notify) {
697 | notify = notify || noop;
698 | for (var i = 0; i < engine.selection.length; i++) {
699 | var s = engine.selection[i];
700 | if (s.from !== from || s.to !== to) continue;
701 | if (s.priority !== toNumber(priority)) continue;
702 | if (s.notify !== notify) continue;
703 | engine.selection.splice(i, 1);
704 | i--;
705 | break;
706 | }
707 |
708 | refresh();
709 | };
710 |
711 | engine.setPulse = function(bps) {
712 | // Set minimum byte/second pulse starting now (dynamic)
713 | // Eg. Start pulsing at minimum 312 KBps:
714 | // engine.setPulse(312*1024);
715 |
716 | engine._pulse = bps;
717 | };
718 |
719 | engine.setFlood = function(b) {
720 | // Set bytes to flood starting now (dynamic)
721 | // Eg. Start flooding for next 10 MB:
722 | // engine.setFlood(10*1024*1024)
723 |
724 | engine._flood = b + swarm.downloaded;
725 | };
726 |
727 | engine.setFloodedPulse = function(b, bps) {
728 | // Set bytes to flood before starting a minimum byte/second pulse (dynamic)
729 | // Eg. Start flooding for next 10 MB, then start pulsing at minimum 312 KBps:
730 | // engine.setFloodedPulse(10*1024*1024, 312*1024);
731 |
732 | engine.setFlood(b);
733 | engine.setPulse(bps);
734 | };
735 |
736 | engine.flood = function() {
737 | // Reset flood/pulse values to default (dynamic)
738 | // Eg. Flood the network starting now:
739 | // engine.flood();
740 |
741 | engine._flood = 0;
742 | engine._pulse = Number.MAX_SAFE_INTEGER;
743 | };
744 |
745 | engine.connect = function(addr) {
746 | swarm.add(addr);
747 | };
748 |
749 | engine.disconnect = function(addr) {
750 | swarm.remove(addr);
751 | };
752 |
753 | engine.block = function(addr) {
754 | blocked.add(addr.split(':')[0]);
755 | engine.disconnect(addr);
756 | engine.emit('blocking', addr);
757 | };
758 |
759 | var removeTorrent = function(cb) {
760 | fs.unlink(torrentPath, function(err) {
761 | if (err) return cb(err);
762 | fs.rmdir(path.dirname(torrentPath), function(err) {
763 | if (err && err.code !== 'ENOTEMPTY') return cb(err);
764 | cb();
765 | });
766 | });
767 | };
768 |
769 | var removeTmp = function(cb) {
770 | if (!usingTmp) return removeTorrent(cb);
771 | fs.rmdir(opts.path, function(err) {
772 | if (err) return cb(err);
773 | removeTorrent(cb);
774 | });
775 | };
776 |
777 | engine.remove = function(keepPieces, cb) {
778 | if (typeof keepPieces === 'function') {
779 | cb = keepPieces;
780 | keepPieces = false;
781 | }
782 |
783 | if (keepPieces || !engine.store || !engine.store.remove) return removeTmp(cb);
784 |
785 | engine.store.remove(function(err) {
786 | if (err) return cb(err);
787 | removeTmp(cb);
788 | });
789 | };
790 |
791 | engine.destroy = function(cb) {
792 | destroyed = true;
793 | swarm.destroy();
794 | clearInterval(rechokeIntervalId);
795 | discovery.stop();
796 | if (engine.store && engine.store.remove) {
797 | engine.store.close(cb);
798 | } else if (cb) {
799 | process.nextTick(cb);
800 | }
801 | };
802 |
803 | var findPort = function(def, cb) {
804 | var net = require('net')
805 | var s = net.createServer()
806 |
807 | s.on('error', function() {
808 | findPort(0, cb)
809 | })
810 |
811 | s.listen(def, function() {
812 | var port = s.address().port
813 | s.close(function() {
814 | engine.listen(port, cb)
815 | })
816 | })
817 | }
818 |
819 | engine.listen = function(port, cb) {
820 | if (typeof port === 'function') return engine.listen(0, port);
821 | if (!port) return findPort(opts.port || DEFAULT_PORT, cb);
822 | engine.port = port
823 | swarm.listen(engine.port, cb);
824 | discovery.updatePort(engine.port);
825 | };
826 |
827 | return engine;
828 | };
829 |
830 | module.exports = torrentStream;
831 |
--------------------------------------------------------------------------------
/background/lib/torrent-stream/test/data/Lorem ipsum.txt:
--------------------------------------------------------------------------------
1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam et iaculis neque. Nam sodales volutpat turpis, at adipiscing sem ornare sed. Nullam molestie ac lorem sit amet viverra. Etiam blandit nibh nisi, quis sodales lectus rhoncus fringilla. Nam velit orci, auctor vel mollis et, lobortis in quam. Vivamus vehicula commodo dolor. Quisque nec nunc vitae nisl ornare tempor. Donec semper nisl ac nisl ullamcorper volutpat. Donec in iaculis nisl, vel volutpat tellus. Curabitur sit amet ultricies libero, in tempus nulla. Quisque id nunc sed sapien eleifend faucibus eget vitae neque.
2 |
3 | Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum purus risus, accumsan sit amet fermentum quis, pellentesque non ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam eu neque consectetur, consectetur velit non, vehicula orci. Donec elit massa, dapibus ut tellus in, bibendum auctor arcu. Curabitur ullamcorper arcu et arcu placerat, nec adipiscing arcu sodales. Proin mattis bibendum tempor. Nunc auctor, turpis id hendrerit venenatis, augue urna vehicula arcu, sit amet vehicula nisi justo et sem. Curabitur porta, odio ut pellentesque adipiscing, justo nisl laoreet eros, ut auctor urna mi vel nulla. Morbi vel tortor vel leo sollicitudin volutpat. Duis blandit lacinia nibh nec euismod.
4 |
5 | Etiam tincidunt imperdiet eros, quis sollicitudin mi blandit et. Duis facilisis, dui ut varius feugiat, leo arcu dapibus ipsum, eu fringilla elit sapien et odio. Phasellus a tortor mi. Curabitur eget fermentum eros. Cras eget purus vel lectus porttitor congue. Etiam diam lorem, eleifend nec dictum ac, dapibus non risus. Vestibulum convallis molestie purus, vitae mattis nisi aliquet ac. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis id purus ut ipsum sodales fermentum. Aliquam vitae ante mauris. Sed dapibus sem in turpis elementum tempor. Aliquam lorem erat, convallis sed ante vitae, interdum pellentesque tortor. Phasellus lobortis quis massa nec rutrum. Curabitur in nibh a arcu varius vehicula. Donec arcu dolor, imperdiet at nisi at, vehicula molestie nunc. Phasellus nunc dolor, blandit non dolor in, bibendum pellentesque urna.
6 |
7 | Vivamus eu ante a purus dapibus accumsan ut nec eros. In luctus quam nibh, id dapibus leo condimentum scelerisque. Nulla aliquam tellus erat, quis consequat libero pellentesque eget. Duis lacinia elementum tempus. In elementum elementum leo eu feugiat. Sed ac suscipit diam. Duis consectetur quam at turpis aliquam ullamcorper. Pellentesque sit amet viverra erat, id faucibus purus.
8 |
9 | Nullam vel turpis tempus, elementum risus vel, eleifend purus. Maecenas laoreet turpis in mattis iaculis. Ut pharetra sed ipsum et bibendum. Proin porta nec nisl a tincidunt. Pellentesque iaculis cursus dui, eget cursus diam aliquet vel. Fusce sapien mi, placerat vitae eros semper, semper varius nisi. Suspendisse semper sit amet mauris sit amet rutrum. Duis viverra in velit convallis pellentesque. Integer convallis metus vel pharetra tristique.
10 |
11 | Proin interdum tortor id iaculis interdum. Praesent non elit nec tortor condimentum venenatis quis eu lectus. Suspendisse dictum felis at malesuada viverra. Nam metus erat, sagittis ut adipiscing non, euismod vitae odio. Sed sed odio non diam hendrerit fermentum nec vel arcu. Quisque cursus diam in urna egestas elementum. Maecenas sapien nunc, ullamcorper eget felis sed, faucibus tristique dolor. Pellentesque pellentesque porta magna, non sodales est hendrerit quis. Curabitur sodales nibh quis tincidunt varius. Aenean eu augue mauris. Vestibulum vel euismod magna. In adipiscing ultricies erat, id pretium nisi mattis facilisis. Praesent eget mi et enim aliquam ullamcorper.
12 |
13 | Proin risus urna, pulvinar a ultricies sed, blandit lobortis augue. Etiam ac gravida tortor, vel tincidunt risus. Sed a augue magna. Donec aliquet consectetur porta. Curabitur sit amet viverra quam. Nunc et tincidunt elit, ut ultrices augue. Phasellus sodales, purus vel mattis fringilla, arcu felis tincidunt erat, non eleifend urna turpis quis massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
14 |
15 | Donec semper est vitae nisi fermentum ornare. Vivamus congue ultrices rhoncus. Duis in aliquet augue. Nullam ac adipiscing neque. Praesent vel velit et diam accumsan bibendum ut at eros. Pellentesque congue dolor dignissim porta eleifend. Vestibulum ac ultrices eros, sed auctor libero. Nulla facilisi. Nunc mattis lorem lectus, at mollis enim fermentum ac. Donec varius cursus massa ut iaculis. Ut convallis ante id felis hendrerit faucibus. Suspendisse laoreet tristique mi sit amet imperdiet. Aliquam molestie, nisi volutpat molestie iaculis, purus neque porttitor eros, ac pretium massa lacus commodo risus. Nullam luctus, tellus a suscipit egestas, mauris nibh faucibus orci, eget ornare risus libero id lacus. Donec ullamcorper at urna ac feugiat.
16 |
17 | Donec fringilla varius felis a porttitor. Duis diam elit, sollicitudin vel risus ac, tempor volutpat augue. Nullam volutpat, dui in tristique tristique, orci nulla ornare ante, ac elementum augue felis vitae ligula. Nam metus velit, lobortis ut dui at, condimentum facilisis sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam porttitor faucibus sem eget consectetur. Donec blandit diam ac metus pellentesque convallis. Vestibulum eu dignissim nunc, ut accumsan nibh. Ut enim tellus, molestie rutrum cursus in, condimentum eu risus.
18 |
19 | Suspendisse pharetra vitae nibh sed eleifend. In rhoncus dapibus elit, id aliquet velit. Aliquam ac orci ligula. Mauris nec mattis metus. Ut gravida scelerisque mauris id varius. Integer gravida tristique mattis. Ut blandit suscipit ligula et porttitor. Vestibulum congue lorem ut nisl sagittis sollicitudin. Maecenas vulputate luctus scelerisque. Sed vestibulum molestie tellus a vehicula. Sed hendrerit varius nisl. Donec pellentesque, ipsum ut laoreet auctor, quam turpis porttitor felis, eu vulputate purus quam ac sapien. Mauris sit amet diam ac nibh feugiat semper nec a massa.
20 |
21 | Quisque vitae dictum neque. Proin fermentum ornare sapien ac consequat. Nullam nulla purus, pretium ut accumsan at, auctor eu mi. Phasellus at urna justo. Donec elit quam, dictum vitae elementum et, volutpat ut leo. Maecenas felis purus, commodo non arcu nec, commodo placerat elit. Praesent sit amet tincidunt ipsum. Phasellus risus velit, sagittis sed augue ac, accumsan iaculis nunc. Aliquam erat volutpat. Nam egestas diam eu euismod pulvinar. Nulla at neque ut nibh rhoncus euismod quis at mi. Vestibulum tristique in tortor ultrices venenatis. Quisque eu velit orci. Proin blandit metus dolor, quis luctus mi pretium sit amet. Cras vel neque in nisl scelerisque ullamcorper vel vel magna.
22 |
23 | Donec non libero venenatis, ullamcorper eros non, tristique sem. Mauris tincidunt nisl erat. Quisque cursus odio massa, at tempor nunc tincidunt id. Vestibulum lacinia eget purus et viverra. Donec lobortis mi et justo lobortis, ac placerat metus dapibus. In ut bibendum nunc, nec bibendum eros. Curabitur suscipit sodales luctus. Quisque luctus interdum libero, nec cursus lorem auctor quis.
24 |
25 | Ut placerat est eu nisi imperdiet fringilla. Nullam felis purus, gravida sit amet dapibus vitae, tincidunt vitae sem. Maecenas eu tellus condimentum, vulputate purus convallis, interdum justo. Donec molestie ultrices porta. Suspendisse et diam sem. Aenean vel lacus et augue fringilla sollicitudin ut sit amet nulla. Donec nec tincidunt massa. Cras blandit consectetur augue ac fermentum. Fusce feugiat, orci a convallis luctus, turpis libero semper lacus, sed pretium massa magna quis eros. Etiam lacinia felis id auctor fringilla. Donec posuere eros facilisis pulvinar ultrices. Vestibulum interdum in enim at volutpat. Vivamus eu pharetra odio, vitae accumsan neque. Phasellus a ligula sed augue luctus pulvinar.
26 |
27 | Fusce ut tellus a elit eleifend pulvinar in eu orci. Sed ut magna felis. Integer non suscipit nibh. Maecenas vitae tellus consequat, imperdiet lectus eu, mattis quam. Etiam id tincidunt eros. Fusce risus sem, pellentesque in ullamcorper id, molestie ut mi. Donec eget lectus mollis, gravida est sed, porttitor lorem. Nullam blandit tristique ullamcorper. Nulla auctor et tellus quis auctor. Morbi eu dui aliquet, vulputate odio a, tincidunt neque. Sed mattis pharetra nunc non cursus.
28 |
29 | Vestibulum hendrerit at ligula ac pharetra. Etiam sagittis suscipit pulvinar. Donec luctus diam turpis, id tempus metus porta at. Donec nec lacus consectetur, aliquam nisl ut, ullamcorper dolor. Sed porttitor est quis felis molestie, et adipiscing erat vestibulum. Vestibulum ac ipsum auctor, blandit eros facilisis, blandit mi. Sed non magna elit. Aenean risus augue, gravida dapibus mauris ac, convallis pellentesque ligula. Integer eros tortor, scelerisque id eros ac, posuere volutpat ipsum. Quisque accumsan volutpat tellus ac sagittis. Praesent pellentesque turpis quis libero tempor mattis. Duis at mi laoreet, aliquet ante vel, consectetur orci. Maecenas vehicula ultrices nisl sed pharetra. Vestibulum hendrerit dignissim arcu ut venenatis.
30 |
31 | In nec pulvinar eros. Vivamus ligula tellus, dignissim in malesuada in, malesuada ut ipsum. Curabitur a laoreet magna, a tristique nulla. Pellentesque congue dui velit, et aliquam augue auctor scelerisque. Donec ullamcorper elit dui, in posuere magna viverra vitae. Donec bibendum urna sit amet suscipit mattis. Phasellus sed vulputate libero. Maecenas pellentesque, velit laoreet ornare facilisis, neque eros aliquet elit, non semper velit tortor id massa. Aliquam laoreet tempus erat vitae dictum. Aenean ut semper sem.
32 |
33 | Ut condimentum tempor turpis id porttitor. Nullam ultrices dui eget accumsan lacinia. Ut cursus pharetra arcu, non porta nisi iaculis at. Aenean eget felis eu leo rutrum ullamcorper et in urna. Etiam vitae ullamcorper erat. Etiam bibendum lacus libero. Nunc porta lacus vitae egestas sagittis. Ut pellentesque leo nulla, et gravida lectus eleifend at. Curabitur feugiat metus ut vestibulum varius.
34 |
35 | Aliquam massa magna, lacinia sed hendrerit quis, lobortis nec nunc. Etiam ultrices velit ut magna tristique, non placerat mauris sagittis. Mauris lacinia ultricies tincidunt. Integer aliquet sodales urna, sed faucibus erat dictum sit amet. Fusce id risus scelerisque, suscipit nisi vel, vestibulum mi. Nam tempus suscipit luctus. Suspendisse rutrum tincidunt odio et dictum. Mauris ligula nibh, pharetra eu augue sed, varius aliquet erat. Vivamus aliquet, ante eu porta blandit, felis nisl bibendum tellus, fermentum ornare arcu nisi et leo. Ut scelerisque neque diam, tincidunt tempus tellus viverra sed. Mauris tristique nec odio sed condimentum. Fusce feugiat tempor augue, vel consequat purus molestie quis. Quisque et gravida diam. Sed ornare diam consequat mauris placerat vulputate. Donec libero neque, eleifend a vulputate quis, elementum et nibh. Pellentesque id dapibus metus.
36 |
37 | Nullam condimentum, nibh sed condimentum sagittis, ante justo tincidunt quam, vitae dignissim turpis mi non dui. Nunc sit amet ullamcorper orci, at hendrerit nulla. Pellentesque interdum viverra congue. Nunc sit amet nulla ut eros malesuada posuere. Nunc rutrum mauris at tempor pretium. Proin porta nisi at faucibus placerat. Fusce sodales, lectus id posuere scelerisque, massa mauris fermentum libero, eget eleifend nisl odio id sapien.
38 |
39 | Sed ac sem eget ligula fringilla vulputate ut quis quam. Sed elit nisi, egestas sit amet adipiscing nec, dapibus a augue. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas dignissim auctor libero vel dignissim. Quisque porta a sapien nec eleifend. Morbi eu augue augue. Aliquam erat volutpat. Sed gravida ut neque at fermentum. Praesent metus est, convallis mattis viverra nec, imperdiet at augue. Donec id dolor mollis, congue purus ac, auctor risus. Vestibulum eget ornare nibh.
40 |
41 | Nunc sem lorem, tincidunt quis venenatis et, malesuada eget eros. Nullam libero felis, tristique at laoreet ut, vulputate eget nisl. Aliquam vitae elit tellus. Donec in turpis non nibh fringilla facilisis sed non urna. Maecenas lorem sem, rhoncus vel fermentum at, molestie in velit. Proin vitae euismod urna. Pellentesque vitae purus elementum, ultrices libero vitae, egestas lectus. Vestibulum ultricies diam nec libero dictum tristique. Morbi auctor enim arcu, quis semper turpis pretium ut. Donec consectetur sodales nulla in dapibus. Nullam commodo magna velit, eu egestas urna posuere et. Phasellus vestibulum erat ac vehicula vehicula. Morbi ullamcorper eu orci in malesuada. Aliquam condimentum turpis sed suscipit pellentesque.
42 |
43 | In velit dolor, molestie sit amet quam at, rutrum convallis enim. Vivamus viverra mi tincidunt ultricies feugiat. Vivamus pulvinar odio ut blandit auctor. Ut eleifend at tellus id varius. Duis placerat vitae elit eu imperdiet. Curabitur tortor mauris, dapibus quis orci eget, iaculis vulputate urna. Nulla pellentesque augue quis tincidunt tincidunt. Sed pharetra porta suscipit. Phasellus tristique lectus neque, id adipiscing dolor semper nec. Nunc et faucibus risus. Sed condimentum faucibus ante, at dignissim lectus fringilla nec. Aenean posuere eleifend enim, ac fringilla nulla scelerisque volutpat. Curabitur sollicitudin varius purus quis placerat. Etiam metus urna, pretium mattis urna venenatis, dapibus mollis augue. Nulla viverra, sem accumsan vestibulum sagittis, sapien nulla vehicula metus, vel ornare lacus sem sit amet neque.
44 |
45 | Nullam dui purus, fermentum nec dolor id, rhoncus posuere purus. Sed nunc enim, condimentum non tempus ac, posuere quis urna. Vestibulum vestibulum tempus metus, ac laoreet sem tincidunt at. Fusce nec nisl scelerisque, tincidunt tortor a, vestibulum risus. In vitae sollicitudin nibh. In vulputate, nunc vel ultricies rutrum, nibh ante pharetra velit, vitae pharetra sapien tortor sed orci. Fusce lacinia bibendum ornare. Pellentesque et imperdiet nibh. Ut nisi erat, volutpat in commodo sed, vulputate sit amet ligula. Nullam gravida nisl diam, et imperdiet libero vehicula eu. Nullam eget mauris at turpis mollis vulputate. Quisque mauris felis, gravida nec tortor quis, vulputate consequat sem. Fusce imperdiet in nisi sed egestas. Curabitur rhoncus condimentum ligula eu eleifend. Morbi massa sem, bibendum sed enim id, tempus imperdiet leo.
46 |
47 | Aliquam dolor mauris, laoreet non lacus et, posuere vehicula augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas id urna consectetur, dapibus lacus id, mattis enim. Fusce felis turpis, sodales aliquet pharetra sit amet, imperdiet nec mi. Nullam facilisis ante ac arcu pellentesque, eu dignissim turpis convallis. Fusce scelerisque lacinia interdum. Proin placerat felis et elit luctus, eget laoreet lacus ullamcorper. Vestibulum suscipit luctus sollicitudin. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
48 |
49 | In eget felis pharetra, posuere libero facilisis, consequat orci. Donec aliquam leo non libero placerat volutpat. Maecenas cursus sodales ultrices. Nunc in rutrum justo, eu fermentum leo. Pellentesque semper dui varius nibh commodo lacinia. Praesent feugiat neque sed gravida ultrices. Mauris posuere lobortis ante, nec varius nisl pretium ut. Aliquam rutrum placerat gravida. Maecenas laoreet, turpis aliquet tempor ultrices, velit risus consequat neque, eget ullamcorper leo libero non justo. Curabitur gravida turpis eu nulla mollis ultrices. Nunc enim eros, pharetra vitae quam vitae, dapibus luctus enim.
50 |
51 | Donec sollicitudin accumsan nibh et auctor. Donec fermentum felis a sem suscipit pellentesque. Sed aliquam dui nec varius dignissim. Vivamus egestas dui eu sapien euismod rhoncus. Nam nisl lorem, tempus ac egestas eu, auctor ac lectus. Quisque adipiscing justo nunc, a sodales ante consectetur non. Curabitur aliquet nulla vitae lobortis pharetra. Aenean volutpat tincidunt risus sed rutrum. In hac habitasse platea dictumst. Duis lectus elit, malesuada adipiscing porta eget, posuere ut urna. Duis aliquet at odio id mattis. Nulla facilisi. Nullam accumsan diam eu erat rutrum gravida. Cras tempus quam vel libero sollicitudin bibendum.
52 |
53 | Interdum et malesuada fames ac ante ipsum primis in faucibus. In pharetra dolor vitae vehicula semper. Curabitur at nisl ac sem placerat tincidunt vitae ut erat. Maecenas ullamcorper, justo non consequat condimentum, augue erat condimentum ipsum, vitae sollicitudin lorem dolor vitae massa. Suspendisse vitae tortor a dui tristique accumsan. Integer sagittis mollis eros sit amet semper. Praesent rutrum, dui sed sollicitudin gravida, ligula ante elementum tortor, eget euismod risus ipsum et elit. Vestibulum interdum sapien quis felis tempor aliquet. Curabitur eu tincidunt arcu, quis lacinia diam.
54 |
55 | Etiam pretium ante quis est hendrerit, in tempor diam gravida. Morbi dictum neque interdum metus congue, in tincidunt sapien elementum. Duis nibh tellus, vehicula in mollis nec, egestas sollicitudin felis. Aliquam quis consectetur orci, eget blandit augue. Mauris pharetra, nunc eget rutrum tempor, purus dolor vestibulum velit, vel rutrum nulla diam sit amet arcu. In faucibus commodo nunc, eget facilisis nisl facilisis vitae. In tempor viverra lorem, eu malesuada orci porta at. Proin sit amet ornare tortor.
56 |
57 | Duis tempus quis eros fringilla porttitor. Cras id nisi ante. Aliquam eleifend quam vitae imperdiet tempor. Morbi egestas ultricies dui et varius. In hac habitasse platea dictumst. Nulla quis tortor quis diam condimentum dapibus ut nec metus. Nulla at pulvinar diam. Sed mollis turpis ac tortor imperdiet, sed porttitor magna fringilla. Sed mauris justo, pretium eget dapibus id, condimentum id ante. Integer et arcu luctus, aliquam diam non, hendrerit sapien. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed eu ante dui. Quisque sit amet malesuada mi, et vulputate massa. Nulla in nisi eget nisi accumsan dapibus. Nulla convallis sollicitudin mauris quis ultricies.
58 |
59 | Suspendisse tincidunt aliquet lacus, et interdum justo malesuada id. Praesent laoreet velit quis purus eleifend semper. Donec adipiscing tristique elit, ac condimentum diam interdum a. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis ullamcorper consequat neque et pharetra. Nulla rhoncus nulla nec sagittis condimentum. Maecenas hendrerit dignissim vestibulum. Proin dignissim quis risus at bibendum.
60 |
61 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi tincidunt justo sit amet mi feugiat commodo. Nulla ultrices dui enim, non tempus sapien accumsan at. Quisque adipiscing egestas metus egestas rutrum. Donec ultrices mi ac lectus egestas, a egestas elit eleifend. Aenean at magna condimentum, sagittis nibh posuere, dapibus lacus. Duis porttitor turpis urna, vulputate ornare nibh hendrerit ut. Curabitur ut enim lacus. Sed scelerisque felis eu felis luctus, ut tincidunt libero pulvinar. Vestibulum ac enim commodo, vulputate purus in, viverra velit. Duis interdum libero molestie sem tincidunt cursus.
62 |
63 | Nullam semper massa urna, vel euismod tortor molestie eu. Suspendisse potenti. Mauris eros arcu, auctor sed mi vel, interdum gravida nulla. Sed interdum porttitor semper. Phasellus tempus congue ante sed tempor. Pellentesque quis velit sed libero aliquam iaculis non venenatis turpis. Integer mattis, nisl a blandit iaculis, mauris nibh suscipit libero, ut tempus nunc lectus at arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent accumsan tincidunt mauris, et iaculis enim tincidunt quis. In lacinia, augue ac convallis sollicitudin, mauris justo iaculis ante, a dictum dui nunc quis arcu. Quisque eget dapibus lorem. Aliquam eget rhoncus lorem.
64 |
65 | Nunc commodo tincidunt pharetra. Cras ultricies velit sed libero porta posuere. Sed posuere commodo faucibus. Suspendisse sodales purus non massa lobortis, sit amet auctor quam lobortis. Curabitur sit amet ultricies est, id lobortis enim. Quisque malesuada dolor mauris. Quisque tincidunt, ipsum ut viverra adipiscing, nisi orci vulputate purus, sit amet egestas augue mauris eu nunc. Sed consequat nunc eu enim laoreet, id pulvinar nisi porta. Sed eu ante scelerisque, pharetra dui a, congue diam. Curabitur sapien quam, posuere vitae facilisis quis, tincidunt lobortis turpis. Nam ac orci eu sapien ultrices sollicitudin. Curabitur eget eros purus. Phasellus pretium et quam non accumsan. Suspendisse tempor lacus a dolor luctus, ut viverra nibh bibendum. Aliquam sagittis ornare massa sit amet placerat.
66 |
67 | Curabitur mattis dui ac augue viverra, eu hendrerit ipsum dictum. Aenean ullamcorper placerat sem, eget feugiat ipsum laoreet nec. In varius ullamcorper ligula in pulvinar. Suspendisse eget nisi vitae urna aliquet vestibulum. Vestibulum ipsum erat, malesuada at tristique non, posuere id dui. In blandit interdum luctus. Sed ac dui ut purus aliquam mollis. Cras at adipiscing tellus, at interdum nulla.
68 |
69 | Mauris vitae justo congue, elementum risus nec, lacinia augue. Maecenas sit amet magna fermentum, tempus neque ut, tincidunt tellus. Donec pharetra venenatis pulvinar. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec dignissim leo non varius congue. Vivamus ultricies scelerisque arcu, sed lobortis nisl euismod id. Nulla pellentesque consequat magna, consequat scelerisque diam fringilla blandit.
70 |
71 | Donec posuere tincidunt erat, vitae luctus erat gravida vel. Sed pretium, nisi a luctus porttitor, lacus magna placerat ipsum, aliquam faucibus leo purus vitae sem. Curabitur convallis sem et consequat porttitor. Vestibulum odio turpis, porttitor non facilisis a, accumsan ut velit. Nullam interdum ipsum erat, at porta enim varius quis. Sed molestie velit sed metus egestas tincidunt. Curabitur mattis felis sed mauris lacinia tempor. Curabitur et tellus risus. Nunc nisl nisi, faucibus feugiat orci eu, pulvinar cursus risus. Etiam volutpat velit magna, nec malesuada nisi ornare et. Mauris porttitor rhoncus nulla ac mollis. Phasellus faucibus, felis varius dictum volutpat, elit est aliquet elit, ut venenatis sapien nisi eget leo. Nullam convallis velit a odio consequat aliquet.
72 |
73 | Maecenas convallis metus eget lorem varius fermentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam justo nibh, mollis sit amet imperdiet non, facilisis id massa. Maecenas tincidunt leo elit, sit amet pretium libero cursus vel. Fusce et tincidunt urna. Donec in tellus malesuada, dignissim nisl vel, rutrum erat. In imperdiet, purus quis viverra egestas, lorem ipsum auctor nisl, nec aliquet tellus enim et mauris. Donec et orci imperdiet arcu ultricies blandit tristique quis velit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec erat lorem, eleifend eget nisi a, tincidunt adipiscing nulla. Mauris suscipit in lacus in elementum. Maecenas pharetra lobortis dolor in tempus. Nam a libero diam. Donec semper elit a neque molestie dignissim.
74 |
75 | Suspendisse in nisi ut eros tincidunt laoreet eu eu nunc. Fusce venenatis suscipit dolor nec consectetur. Curabitur vel luctus purus. Aenean sem magna, porttitor ultricies iaculis ac, pellentesque eu mi. Nunc risus tellus, laoreet non risus nec, imperdiet tempus risus. Praesent condimentum ipsum vel magna pharetra, et viverra eros iaculis. Quisque bibendum facilisis orci. Praesent varius eget urna at hendrerit.
76 |
77 | Nam gravida auctor fringilla. Nam lobortis ante eget rutrum iaculis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam erat volutpat. Pellentesque et adipiscing turpis. Aenean sed ultricies ante, interdum accumsan felis. Quisque rutrum pulvinar nisl vehicula dictum.
78 |
79 | Duis mauris mi, auctor ac mauris id, venenatis bibendum libero. Pellentesque ac eleifend quam. Nulla turpis orci, fermentum aliquam tortor sed, egestas scelerisque nisl. In convallis a velit a vulputate. Suspendisse iaculis nec mauris eget convallis. Duis ante sem, viverra id velit nec, scelerisque dapibus tellus. Ut ultricies, mi in rutrum lobortis, risus ante condimentum erat, eu ornare ipsum augue sed mi. Donec mi turpis, elementum in est in, elementum mattis orci.
80 |
81 | Aliquam pulvinar convallis congue. Sed non turpis id lorem tincidunt hendrerit eget vel justo. Aliquam tempus nulla quis metus viverra, at elementum sem dictum. Etiam condimentum velit eu nisi suscipit suscipit. Cras quis quam non purus mattis rhoncus non in leo. Proin tincidunt condimentum urna tempus cursus. Sed placerat elementum tortor, id aliquam metus. Etiam ac lorem eget erat auctor aliquam. Etiam in dictum leo, sed sagittis erat. Phasellus laoreet velit eget velit porta, quis blandit eros luctus. Donec suscipit, felis eu dignissim pulvinar, risus velit adipiscing urna, et semper tortor mauris sit amet ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur rhoncus, justo eget pretium aliquet, arcu sem dictum tortor, sed ultricies odio leo quis erat. Suspendisse vitae aliquam ipsum. Sed adipiscing, nisi quis aliquet euismod, velit ante placerat risus, vel gravida tellus elit et orci. Integer nibh elit, adipiscing sed ipsum non, viverra facilisis tellus.
82 |
83 | Vivamus malesuada lorem in felis auctor, vitae lacinia augue condimentum. Nam tortor mauris, condimentum vel fermentum nec, malesuada eget purus. Fusce ultricies lectus justo, ac cursus erat ultricies eget. Quisque aliquet sem ut lacinia tincidunt. Praesent quis quam quis leo ultrices auctor eu at sem. Mauris pulvinar ac risus vitae ullamcorper. Pellentesque ut placerat est. Ut nisl massa, fringilla a nisi in, porta varius purus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque fringilla ullamcorper condimentum. Aliquam non porttitor diam. Suspendisse sodales, velit ut laoreet gravida, odio nunc volutpat purus, vel feugiat leo magna sit amet sapien. Donec nec tellus cursus lectus molestie viverra. Maecenas mollis scelerisque massa, vitae dictum orci vestibulum et. Sed viverra ultricies dui vitae sagittis. Nunc sed justo id urna consequat fermentum.
84 |
85 | Cras convallis odio vitae lobortis sodales. Fusce condimentum posuere tellus, eget semper urna tincidunt vel. Nullam porta nisi et ligula blandit ullamcorper. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas eleifend, felis sit amet pretium dictum, urna erat rutrum massa, dapibus tempus purus nisi id felis. Curabitur aliquet enim id ornare fringilla. Nullam luctus dignissim mi, nec vehicula quam vehicula eget. Nunc sed nulla vitae nunc vehicula molestie. Maecenas sollicitudin, neque sed cursus facilisis, tortor ipsum congue eros, eu aliquam ante magna sit amet magna.
86 |
87 | Nulla convallis et tellus ac posuere. Aliquam in nulla quis lacus euismod tempus. Aenean a orci in purus blandit aliquet. Sed ac tortor massa. Suspendisse potenti. Maecenas imperdiet massa a sapien elementum, ut vestibulum lectus sagittis. Vivamus ac ligula et leo aliquet tempus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque sed turpis commodo, sollicitudin dolor eu, fermentum massa. Suspendisse et orci nunc. Sed convallis hendrerit ligula, in blandit mi tincidunt in. Proin mattis erat neque, vel porttitor ipsum congue quis. Phasellus dictum metus lorem, ac fringilla augue mollis tristique. Suspendisse potenti. Fusce neque urna, vestibulum sed sapien at, molestie mattis turpis. Nunc sapien elit, vulputate nec tortor a, ornare volutpat ipsum.
88 |
89 | Suspendisse vestibulum volutpat ante sed suscipit. Etiam eu leo vel ante faucibus commodo a sodales enim. Praesent et lorem venenatis, rutrum augue at, eleifend nulla. Proin ornare molestie lacus, in semper neque imperdiet consequat. Aliquam iaculis elit eu lorem elementum mattis. Donec consectetur lacus et ligula iaculis, sit amet consequat diam dictum. Praesent congue ipsum id nisl elementum, id lobortis tortor laoreet. Integer at mauris semper, tempus ipsum sed, interdum lectus. Vestibulum sed augue nec orci dignissim consequat. Quisque malesuada dignissim diam, sed semper risus convallis a. Praesent sed vulputate metus.
90 |
91 | Nunc porttitor eros eu euismod elementum. Quisque eget magna ornare, tempor nisi at, tempus mauris. Sed tincidunt nec ligula a rhoncus. Suspendisse a volutpat nisl. Fusce rutrum orci neque, non iaculis purus suscipit sed. Donec eros tortor, dapibus eget justo id, euismod dignissim ipsum. Vestibulum id vulputate quam. Donec faucibus nulla in erat blandit elementum. Sed bibendum malesuada diam vitae accumsan. Nullam congue venenatis dui a vestibulum. Aliquam gravida nec erat vel molestie. In posuere sollicitudin turpis sit amet bibendum. Fusce adipiscing adipiscing eros, et luctus leo pharetra mattis. Sed a pretium mauris. Maecenas ante urna, adipiscing nec suscipit sit amet, condimentum sit amet diam. Vivamus commodo sem at ante mattis, eget elementum sapien posuere.
92 |
93 | Vestibulum tristique, magna ut pulvinar facilisis, lectus felis malesuada augue, quis porttitor leo purus a mauris. Sed in scelerisque tortor. Mauris molestie tempus leo, vitae tempus odio viverra ac. Ut augue massa, convallis eu molestie vitae, tristique sed arcu. Donec sagittis purus eros, in consectetur tortor ultrices id. Sed pulvinar faucibus velit, non tempor felis aliquam a. Donec imperdiet nisi orci, eu ultrices lorem adipiscing vitae. Praesent egestas quam suscipit, faucibus nisl a, scelerisque turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
94 |
95 | Aenean enim sem, vulputate id ligula quis, vehicula adipiscing odio. Cras nec iaculis massa, eu ultricies leo. Nunc pellentesque purus sem, ut elementum turpis pellentesque non. Etiam rhoncus venenatis urna at congue. Nullam quis rutrum urna, vitae dignissim risus. Ut ac lacus sed ipsum feugiat lacinia a non sapien. In pharetra turpis id sagittis sagittis. Suspendisse scelerisque auctor tortor id pellentesque. Ut viverra malesuada libero sed laoreet.
96 |
97 | Nulla mauris felis, ornare quis dapibus sed, bibendum at nisl. Nam sed odio ipsum. Nunc ac lorem libero. Vivamus tincidunt risus sit amet quam rutrum, vitae luctus enim consectetur. Nam vitae purus vitae lectus euismod faucibus. Nulla facilisi. Nam dictum nunc vitae ullamcorper gravida. Ut sit amet ante sed elit fermentum tristique in id urna. Nam dictum tincidunt risus, id blandit justo tristique eget. Aliquam erat volutpat.
98 |
99 | Nullam vel turpis convallis, rhoncus mauris vitae, feugiat sapien. Sed libero sapien, hendrerit non augue vel, facilisis porttitor sapien. Praesent convallis aliquet mi, a vulputate neque commodo id. Sed non ullamcorper lorem, in eleifend tortor. Nunc sagittis faucibus sem, quis fringilla nisl elementum sagittis. Etiam gravida sed justo id malesuada. Proin et ultricies arcu. Curabitur nisl diam, molestie ac nibh non, lobortis dictum erat. Nunc eget scelerisque dolor, vitae consectetur sapien. Nulla convallis mi massa, quis dictum tortor lobortis eu. Vivamus lorem elit, auctor pellentesque condimentum in, consequat nec enim. Duis non ultrices magna, nec suscipit dui. Ut porta, erat sit amet volutpat convallis, nulla magna hendrerit felis, id semper ante lectus id augue. Aenean euismod sem quis tincidunt hendrerit.
100 |
101 | Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus erat nisi, viverra nec egestas vel, mattis et diam. Morbi quam leo, commodo id sapien ac, aliquet vehicula mauris. Vestibulum rhoncus nec ipsum at eleifend. Sed vel turpis congue, dapibus turpis at, suscipit neque. Curabitur feugiat odio quis tristique fringilla. Nunc fermentum elementum ligula volutpat dictum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nam suscipit ante sit amet odio mattis, ut condimentum erat posuere. In placerat, purus vitae congue bibendum, elit purus pretium eros, a consectetur nisl erat eget augue. Fusce eleifend et mi vel viverra. Mauris nec fringilla mi. Nulla enim magna, fringilla eget lorem at, consequat pharetra augue. Fusce at tincidunt sapien, sit amet laoreet risus. Pellentesque sollicitudin commodo nulla sit amet sagittis. Interdum et malesuada fames ac ante ipsum primis in faucibus.
102 |
103 | Nulla ac diam leo. Cras et elit vitae erat mattis volutpat. Quisque adipiscing luctus lacinia. Aenean eget ipsum convallis, tristique quam non, ultrices nulla. Mauris nibh nisl, suscipit ac elit at, molestie ornare sem. Fusce rutrum tristique nulla in suscipit. Quisque tincidunt ultricies dolor nec euismod. Morbi eros diam, molestie a semper quis, tincidunt sed quam.
104 |
105 | Suspendisse porta, felis a imperdiet sodales, nisl ipsum fermentum lorem, a bibendum nisi dui ut turpis. In quis purus rhoncus, sodales est sed, aliquam mauris. Quisque eu nisi vestibulum, feugiat odio quis, malesuada velit. Integer purus quam, pretium a lectus sed, pharetra porta turpis. In elementum nisi quis ipsum sollicitudin bibendum. Integer pharetra dolor sit amet lacus placerat, ac placerat justo suscipit. Aliquam quis lacus quis odio gravida dapibus gravida id turpis. Donec bibendum, mi eget pretium pretium, erat velit hendrerit nibh, non eleifend nulla lectus et lorem. Sed suscipit ut ligula et rhoncus. Duis egestas fringilla tortor sit amet ultrices. Nulla luctus lectus quis consectetur lacinia. Aliquam erat volutpat. Etiam velit enim, tincidunt vitae aliquet eu, elementum molestie libero. Quisque tincidunt mi urna, consequat tempor mauris cursus eu. Ut pretium sagittis pharetra. Duis id magna vitae sem blandit tempor.
106 |
107 | In ut faucibus odio. Nunc nibh orci, gravida non nibh eu, sodales lobortis quam. Curabitur euismod varius est, in facilisis odio gravida suscipit. Suspendisse potenti. Donec porttitor fringilla nisi nec semper. In sagittis accumsan risus, id aliquet tortor consectetur cursus. Maecenas sed vulputate orci, id fermentum dolor.
108 |
109 | Sed vitae posuere tellus, id interdum sem. Ut lobortis lacinia lectus, ut pulvinar ligula dictum sit amet. Mauris rhoncus, nisl quis molestie commodo, quam tellus eleifend quam, sit amet suscipit odio lorem ac nulla. Ut id pretium dolor. Cras nec felis sit amet justo condimentum ornare. Aliquam luctus libero eget tortor convallis cursus. Aliquam varius, justo vel tincidunt tincidunt, eros dolor placerat sem, a laoreet magna velit ut est. Vivamus tristique eget orci vel tincidunt. Praesent faucibus lacus ornare lacus accumsan, a molestie dolor feugiat. Nullam mollis massa quis sollicitudin malesuada.
110 |
111 | Integer id porta leo. In pulvinar nulla non lacus tincidunt, sed molestie dolor congue. Etiam sollicitudin, nunc at scelerisque placerat, nibh lectus viverra lacus, sed elementum nibh ante quis augue. Nulla nisl massa, aliquam et velit vitae, euismod dictum neque. Suspendisse at sapien pretium nibh rhoncus aliquet vel id sem. Donec quis erat lorem. Proin consectetur velit a dui adipiscing, et venenatis erat tempus. Mauris sodales at nunc lacinia condimentum. In consectetur tristique lorem non porttitor.
112 |
113 | Nunc vitae erat iaculis, lobortis orci eget, fringilla risus. Cras lorem odio, mollis ut lorem ac, vestibulum accumsan diam. Proin viverra iaculis est, blandit cursus nulla blandit quis. Vivamus a ligula facilisis, tempor metus ut, commodo dui. Duis semper dapibus metus, sit amet semper purus. Etiam fermentum aliquet elementum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent feugiat a velit a placerat. Donec ultricies nec erat a sollicitudin. Fusce tempus tortor nec sapien vehicula blandit. Maecenas mauris velit, sodales quis consectetur id, bibendum at magna. Pellentesque rutrum nibh vel nibh pretium rutrum. Sed pellentesque sollicitudin velit. Sed rutrum scelerisque imperdiet. Sed id posuere felis, eu mattis sem.
114 |
115 | Nunc blandit vitae lorem sit amet faucibus. Vivamus dapibus, augue nec rhoncus porttitor, turpis urna sollicitudin dui, vel scelerisque sem dolor eget enim. Nunc et accumsan sapien, vitae varius orci. In hac habitasse cras amet.
--------------------------------------------------------------------------------