pax_global_header00006660000000000000000000000064127054272000014511gustar00rootroot0000000000000052 comment=7c279d66989a3bdde45f1eb661edaa846540d984 tar-stream-1.5.2/000077500000000000000000000000001270542720000135755ustar00rootroot00000000000000tar-stream-1.5.2/.gitignore000066400000000000000000000000301270542720000155560ustar00rootroot00000000000000node_modules sandbox.js tar-stream-1.5.2/.travis.yml000066400000000000000000000001011270542720000156760ustar00rootroot00000000000000language: node_js node_js: - "0.10" - '0.12' - '4' - '5' tar-stream-1.5.2/LICENSE000066400000000000000000000020661270542720000146060ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Mathias Buus 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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.tar-stream-1.5.2/README.md000066400000000000000000000103021270542720000150500ustar00rootroot00000000000000# tar-stream tar-stream is a streaming tar parser and generator and nothing else. It is streams2 and operates purely using streams which means you can easily extract/parse tarballs without ever hitting the file system. Note that you still need to gunzip your data if you have a `.tar.gz`. We recommend using [gunzip-maybe](https://github.com/mafintosh/gunzip-maybe) in conjunction with this. ``` npm install tar-stream ``` [![build status](https://secure.travis-ci.org/mafintosh/tar-stream.png)](http://travis-ci.org/mafintosh/tar-stream) ## Usage tar-stream exposes two streams, [pack](https://github.com/mafintosh/tar-stream#packing) which creates tarballs and [extract](https://github.com/mafintosh/tar-stream#extracting) which extracts tarballs. To [modify an existing tarball](https://github.com/mafintosh/tar-stream#modifying-existing-tarballs) use both. It implementes USTAR with additional support for pax extended headers. It should be compatible with all popular tar distributions out there (gnutar, bsdtar etc) ## Related If you want to pack/unpack directories on the file system check out [tar-fs](https://github.com/mafintosh/tar-fs) which provides file system bindings to this module. ## Packing To create a pack stream use `tar.pack()` and call `pack.entry(header, [callback])` to add tar entries. ``` js var tar = require('tar-stream') var pack = tar.pack() // pack is a streams2 stream // add a file called my-test.txt with the content "Hello World!" pack.entry({ name: 'my-test.txt' }, 'Hello World!') // add a file called my-stream-test.txt from a stream var entry = pack.entry({ name: 'my-stream-test.txt', size: 11 }, function(err) { // the stream was added // no more entries pack.finalize() }) entry.write('hello') entry.write(' ') entry.write('world') entry.end() // pipe the pack stream somewhere pack.pipe(process.stdout) ``` ## Extracting To extract a stream use `tar.extract()` and listen for `extract.on('entry', header, stream, callback)` ``` js var extract = tar.extract() extract.on('entry', function(header, stream, callback) { // header is the tar header // stream is the content body (might be an empty stream) // call next when you are done with this entry stream.on('end', function() { callback() // ready for next entry }) stream.resume() // just auto drain the stream }) extract.on('finish', function() { // all entries read }) pack.pipe(extract) ``` ## Headers The header object using in `entry` should contain the following properties. Most of these values can be found by stat'ing a file. ``` js { name: 'path/to/this/entry.txt', size: 1314, // entry size. defaults to 0 mode: 0644, // entry mode. defaults to to 0755 for dirs and 0644 otherwise mtime: new Date(), // last modified date for entry. defaults to now. type: 'file', // type of entry. defaults to file. can be: // file | link | symlink | directory | block-device // character-device | fifo | contiguous-file linkname: 'path', // linked file name uid: 0, // uid of entry owner. defaults to 0 gid: 0, // gid of entry owner. defaults to 0 uname: 'maf', // uname of entry owner. defaults to null gname: 'staff', // gname of entry owner. defaults to null devmajor: 0, // device major version. defaults to 0 devminor: 0 // device minor version. defaults to 0 } ``` ## Modifying existing tarballs Using tar-stream it is easy to rewrite paths / change modes etc in an existing tarball. ``` js var extract = tar.extract() var pack = tar.pack() var path = require('path') extract.on('entry', function(header, stream, callback) { // let's prefix all names with 'tmp' header.name = path.join('tmp', header.name) // write the new entry to the pack stream stream.pipe(pack.entry(header, callback)) }) extract.on('finish', function() { // all entries done - lets finalize it pack.finalize() }) // pipe the old tarball to the extractor oldTarballStream.pipe(extract) // pipe the new tarball the another stream pack.pipe(newTarballStream) ``` ## Performance [See tar-fs for a performance comparison with node-tar](https://github.com/mafintosh/tar-fs/blob/master/README.md#performance) # License MIT tar-stream-1.5.2/extract.js000066400000000000000000000125431270542720000156120ustar00rootroot00000000000000var util = require('util') var bl = require('bl') var xtend = require('xtend') var headers = require('./headers') var Writable = require('readable-stream').Writable var PassThrough = require('readable-stream').PassThrough var noop = function () {} var overflow = function (size) { size &= 511 return size && 512 - size } var emptyStream = function (self, offset) { var s = new Source(self, offset) s.end() return s } var mixinPax = function (header, pax) { if (pax.path) header.name = pax.path if (pax.linkpath) header.linkname = pax.linkpath header.pax = pax return header } var Source = function (self, offset) { this._parent = self this.offset = offset PassThrough.call(this) } util.inherits(Source, PassThrough) Source.prototype.destroy = function (err) { this._parent.destroy(err) } var Extract = function (opts) { if (!(this instanceof Extract)) return new Extract(opts) Writable.call(this, opts) this._offset = 0 this._buffer = bl() this._missing = 0 this._onparse = noop this._header = null this._stream = null this._overflow = null this._cb = null this._locked = false this._destroyed = false this._pax = null this._paxGlobal = null this._gnuLongPath = null this._gnuLongLinkPath = null var self = this var b = self._buffer var oncontinue = function () { self._continue() } var onunlock = function (err) { self._locked = false if (err) return self.destroy(err) if (!self._stream) oncontinue() } var onstreamend = function () { self._stream = null var drain = overflow(self._header.size) if (drain) self._parse(drain, ondrain) else self._parse(512, onheader) if (!self._locked) oncontinue() } var ondrain = function () { self._buffer.consume(overflow(self._header.size)) self._parse(512, onheader) oncontinue() } var onpaxglobalheader = function () { var size = self._header.size self._paxGlobal = headers.decodePax(b.slice(0, size)) b.consume(size) onstreamend() } var onpaxheader = function () { var size = self._header.size self._pax = headers.decodePax(b.slice(0, size)) if (self._paxGlobal) self._pax = xtend(self._paxGlobal, self._pax) b.consume(size) onstreamend() } var ongnulongpath = function () { var size = self._header.size this._gnuLongPath = headers.decodeLongPath(b.slice(0, size)) b.consume(size) onstreamend() } var ongnulonglinkpath = function () { var size = self._header.size this._gnuLongLinkPath = headers.decodeLongPath(b.slice(0, size)) b.consume(size) onstreamend() } var onheader = function () { var offset = self._offset var header try { header = self._header = headers.decode(b.slice(0, 512)) } catch (err) { self.emit('error', err) } b.consume(512) if (!header) { self._parse(512, onheader) oncontinue() return } if (header.type === 'gnu-long-path') { self._parse(header.size, ongnulongpath) oncontinue() return } if (header.type === 'gnu-long-link-path') { self._parse(header.size, ongnulonglinkpath) oncontinue() return } if (header.type === 'pax-global-header') { self._parse(header.size, onpaxglobalheader) oncontinue() return } if (header.type === 'pax-header') { self._parse(header.size, onpaxheader) oncontinue() return } if (self._gnuLongPath) { header.name = self._gnuLongPath self._gnuLongPath = null } if (self._gnuLongLinkPath) { header.linkname = self._gnuLongLinkPath self._gnuLongLinkPath = null } if (self._pax) { self._header = header = mixinPax(header, self._pax) self._pax = null } self._locked = true if (!header.size) { self._parse(512, onheader) self.emit('entry', header, emptyStream(self, offset), onunlock) return } self._stream = new Source(self, offset) self.emit('entry', header, self._stream, onunlock) self._parse(header.size, onstreamend) oncontinue() } this._parse(512, onheader) } util.inherits(Extract, Writable) Extract.prototype.destroy = function (err) { if (this._destroyed) return this._destroyed = true if (err) this.emit('error', err) this.emit('close') if (this._stream) this._stream.emit('close') } Extract.prototype._parse = function (size, onparse) { if (this._destroyed) return this._offset += size this._missing = size this._onparse = onparse } Extract.prototype._continue = function () { if (this._destroyed) return var cb = this._cb this._cb = noop if (this._overflow) this._write(this._overflow, undefined, cb) else cb() } Extract.prototype._write = function (data, enc, cb) { if (this._destroyed) return var s = this._stream var b = this._buffer var missing = this._missing // we do not reach end-of-chunk now. just forward it if (data.length < missing) { this._missing -= data.length this._overflow = null if (s) return s.write(data, cb) b.append(data) return cb() } // end-of-chunk. the parser should call cb. this._cb = cb this._missing = 0 var overflow = null if (data.length > missing) { overflow = data.slice(missing) data = data.slice(0, missing) } if (s) s.end(data) else b.append(data) this._overflow = overflow this._onparse() } module.exports = Extract tar-stream-1.5.2/headers.js000066400000000000000000000160001270542720000155430ustar00rootroot00000000000000var ZEROS = '0000000000000000000' var ZERO_OFFSET = '0'.charCodeAt(0) var USTAR = 'ustar\x0000' var MASK = parseInt('7777', 8) var clamp = function (index, len, defaultValue) { if (typeof index !== 'number') return defaultValue index = ~~index // Coerce to integer. if (index >= len) return len if (index >= 0) return index index += len if (index >= 0) return index return 0 } var toType = function (flag) { switch (flag) { case 0: return 'file' case 1: return 'link' case 2: return 'symlink' case 3: return 'character-device' case 4: return 'block-device' case 5: return 'directory' case 6: return 'fifo' case 7: return 'contiguous-file' case 72: return 'pax-header' case 55: return 'pax-global-header' case 27: return 'gnu-long-link-path' case 28: case 30: return 'gnu-long-path' } return null } var toTypeflag = function (flag) { switch (flag) { case 'file': return 0 case 'link': return 1 case 'symlink': return 2 case 'character-device': return 3 case 'block-device': return 4 case 'directory': return 5 case 'fifo': return 6 case 'contiguous-file': return 7 case 'pax-header': return 72 } return 0 } var alloc = function (size) { var buf = new Buffer(size) buf.fill(0) return buf } var indexOf = function (block, num, offset, end) { for (; offset < end; offset++) { if (block[offset] === num) return offset } return end } var cksum = function (block) { var sum = 8 * 32 for (var i = 0; i < 148; i++) sum += block[i] for (var j = 156; j < 512; j++) sum += block[j] return sum } var encodeOct = function (val, n) { val = val.toString(8) return ZEROS.slice(0, n - val.length) + val + ' ' } /* Copied from the node-tar repo and modified to meet * tar-stream coding standard. * * Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349 */ function parse256 (buf) { // first byte MUST be either 80 or FF // 80 for positive, FF for 2's comp var positive if (buf[0] === 0x80) positive = true else if (buf[0] === 0xFF) positive = false else return null // build up a base-256 tuple from the least sig to the highest var zero = false var tuple = [] for (var i = buf.length - 1; i > 0; i--) { var byte = buf[i] if (positive) tuple.push(byte) else if (zero && byte === 0) tuple.push(0) else if (zero) { zero = false tuple.push(0x100 - byte) } else tuple.push(0xFF - byte) } var sum = 0 var l = tuple.length for (i = 0; i < l; i++) { sum += tuple[i] * Math.pow(256, i) } return positive ? sum : -1 * sum } var decodeOct = function (val, offset) { // If prefixed with 0x80 then parse as a base-256 integer if (val[offset] & 0x80) { return parse256(val.slice(offset, offset + 8)) } else { // Older versions of tar can prefix with spaces while (offset < val.length && val[offset] === 32) offset++ var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length) while (offset < end && val[offset] === 0) offset++ if (end === offset) return 0 return parseInt(val.slice(offset, end).toString(), 8) } } var decodeStr = function (val, offset, length) { return val.slice(offset, indexOf(val, 0, offset, offset + length)).toString() } var addLength = function (str) { var len = Buffer.byteLength(str) var digits = Math.floor(Math.log(len) / Math.log(10)) + 1 if (len + digits > Math.pow(10, digits)) digits++ return (len + digits) + str } exports.decodeLongPath = function (buf) { return decodeStr(buf, 0, buf.length) } exports.encodePax = function (opts) { // TODO: encode more stuff in pax var result = '' if (opts.name) result += addLength(' path=' + opts.name + '\n') if (opts.linkname) result += addLength(' linkpath=' + opts.linkname + '\n') var pax = opts.pax if (pax) { for (var key in pax) { result += addLength(' ' + key + '=' + pax[key] + '\n') } } return new Buffer(result) } exports.decodePax = function (buf) { var result = {} while (buf.length) { var i = 0 while (i < buf.length && buf[i] !== 32) i++ var len = parseInt(buf.slice(0, i).toString(), 10) if (!len) return result var b = buf.slice(i + 1, len - 1).toString() var keyIndex = b.indexOf('=') if (keyIndex === -1) return result result[b.slice(0, keyIndex)] = b.slice(keyIndex + 1) buf = buf.slice(len) } return result } exports.encode = function (opts) { var buf = alloc(512) var name = opts.name var prefix = '' if (opts.typeflag === 5 && name[name.length - 1] !== '/') name += '/' if (Buffer.byteLength(name) !== name.length) return null // utf-8 while (Buffer.byteLength(name) > 100) { var i = name.indexOf('/') if (i === -1) return null prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i) name = name.slice(i + 1) } if (Buffer.byteLength(name) > 100 || Buffer.byteLength(prefix) > 155) return null if (opts.linkname && Buffer.byteLength(opts.linkname) > 100) return null buf.write(name) buf.write(encodeOct(opts.mode & MASK, 6), 100) buf.write(encodeOct(opts.uid, 6), 108) buf.write(encodeOct(opts.gid, 6), 116) buf.write(encodeOct(opts.size, 11), 124) buf.write(encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136) buf[156] = ZERO_OFFSET + toTypeflag(opts.type) if (opts.linkname) buf.write(opts.linkname, 157) buf.write(USTAR, 257) if (opts.uname) buf.write(opts.uname, 265) if (opts.gname) buf.write(opts.gname, 297) buf.write(encodeOct(opts.devmajor || 0, 6), 329) buf.write(encodeOct(opts.devminor || 0, 6), 337) if (prefix) buf.write(prefix, 345) buf.write(encodeOct(cksum(buf), 6), 148) return buf } exports.decode = function (buf) { var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET var name = decodeStr(buf, 0, 100) var mode = decodeOct(buf, 100) var uid = decodeOct(buf, 108) var gid = decodeOct(buf, 116) var size = decodeOct(buf, 124) var mtime = decodeOct(buf, 136) var type = toType(typeflag) var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100) var uname = decodeStr(buf, 265, 32) var gname = decodeStr(buf, 297, 32) var devmajor = decodeOct(buf, 329) var devminor = decodeOct(buf, 337) if (buf[345]) name = decodeStr(buf, 345, 155) + '/' + name // to support old tar versions that use trailing / to indicate dirs if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5 var c = cksum(buf) // checksum is still initial value if header was null. if (c === 8 * 32) return null // valid checksum if (c !== decodeOct(buf, 148)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?') return { name: name, mode: mode, uid: uid, gid: gid, size: size, mtime: new Date(1000 * mtime), type: type, linkname: linkname, uname: uname, gname: gname, devmajor: devmajor, devminor: devminor } } tar-stream-1.5.2/index.js000066400000000000000000000001101270542720000152320ustar00rootroot00000000000000exports.extract = require('./extract') exports.pack = require('./pack') tar-stream-1.5.2/pack.js000066400000000000000000000127201270542720000150530ustar00rootroot00000000000000var constants = require('constants') var eos = require('end-of-stream') var util = require('util') var Readable = require('readable-stream').Readable var Writable = require('readable-stream').Writable var StringDecoder = require('string_decoder').StringDecoder var headers = require('./headers') var DMODE = parseInt('755', 8) var FMODE = parseInt('644', 8) var END_OF_TAR = new Buffer(1024) END_OF_TAR.fill(0) var noop = function () {} var overflow = function (self, size) { size &= 511 if (size) self.push(END_OF_TAR.slice(0, 512 - size)) } function modeToType (mode) { switch (mode & constants.S_IFMT) { case constants.S_IFBLK: return 'block-device' case constants.S_IFCHR: return 'character-device' case constants.S_IFDIR: return 'directory' case constants.S_IFIFO: return 'fifo' case constants.S_IFLNK: return 'symlink' } return 'file' } var Sink = function (to) { Writable.call(this) this.written = 0 this._to = to this._destroyed = false } util.inherits(Sink, Writable) Sink.prototype._write = function (data, enc, cb) { this.written += data.length if (this._to.push(data)) return cb() this._to._drain = cb } Sink.prototype.destroy = function () { if (this._destroyed) return this._destroyed = true this.emit('close') } var LinkSink = function () { Writable.call(this) this.linkname = '' this._decoder = new StringDecoder('utf-8') this._destroyed = false } util.inherits(LinkSink, Writable) LinkSink.prototype._write = function (data, enc, cb) { this.linkname += this._decoder.write(data) cb() } LinkSink.prototype.destroy = function () { if (this._destroyed) return this._destroyed = true this.emit('close') } var Void = function () { Writable.call(this) this._destroyed = false } util.inherits(Void, Writable) Void.prototype._write = function (data, enc, cb) { cb(new Error('No body allowed for this entry')) } Void.prototype.destroy = function () { if (this._destroyed) return this._destroyed = true this.emit('close') } var Pack = function (opts) { if (!(this instanceof Pack)) return new Pack(opts) Readable.call(this, opts) this._drain = noop this._finalized = false this._finalizing = false this._destroyed = false this._stream = null } util.inherits(Pack, Readable) Pack.prototype.entry = function (header, buffer, callback) { if (this._stream) throw new Error('already piping an entry') if (this._finalized || this._destroyed) return if (typeof buffer === 'function') { callback = buffer buffer = null } if (!callback) callback = noop var self = this if (!header.size || header.type === 'symlink') header.size = 0 if (!header.type) header.type = modeToType(header.mode) if (!header.mode) header.mode = header.type === 'directory' ? DMODE : FMODE if (!header.uid) header.uid = 0 if (!header.gid) header.gid = 0 if (!header.mtime) header.mtime = new Date() if (typeof buffer === 'string') buffer = new Buffer(buffer) if (Buffer.isBuffer(buffer)) { header.size = buffer.length this._encode(header) this.push(buffer) overflow(self, header.size) process.nextTick(callback) return new Void() } if (header.type === 'symlink' && !header.linkname) { var linkSink = new LinkSink() eos(linkSink, function (err) { if (err) { // stream was closed self.destroy() return callback(err) } header.linkname = linkSink.linkname self._encode(header) callback() }) return linkSink } this._encode(header) if (header.type !== 'file' && header.type !== 'contiguous-file') { process.nextTick(callback) return new Void() } var sink = new Sink(this) this._stream = sink eos(sink, function (err) { self._stream = null if (err) { // stream was closed self.destroy() return callback(err) } if (sink.written !== header.size) { // corrupting tar self.destroy() return callback(new Error('size mismatch')) } overflow(self, header.size) if (self._finalizing) self.finalize() callback() }) return sink } Pack.prototype.finalize = function () { if (this._stream) { this._finalizing = true return } if (this._finalized) return this._finalized = true this.push(END_OF_TAR) this.push(null) } Pack.prototype.destroy = function (err) { if (this._destroyed) return this._destroyed = true if (err) this.emit('error', err) this.emit('close') if (this._stream && this._stream.destroy) this._stream.destroy() } Pack.prototype._encode = function (header) { if (!header.pax) { var buf = headers.encode(header) if (buf) { this.push(buf) return } } this._encodePax(header) } Pack.prototype._encodePax = function (header) { var paxHeader = headers.encodePax({ name: header.name, linkname: header.linkname, pax: header.pax }) var newHeader = { name: 'PaxHeader', mode: header.mode, uid: header.uid, gid: header.gid, size: paxHeader.length, mtime: header.mtime, type: 'pax-header', linkname: header.linkname && 'PaxHeader', uname: header.uname, gname: header.gname, devmajor: header.devmajor, devminor: header.devminor } this.push(headers.encode(newHeader)) this.push(paxHeader) overflow(this, paxHeader.length) newHeader.size = header.size newHeader.type = header.type this.push(headers.encode(newHeader)) } Pack.prototype._read = function (n) { var drain = this._drain this._drain = noop drain() } module.exports = Pack tar-stream-1.5.2/package.json000066400000000000000000000023521270542720000160650ustar00rootroot00000000000000{ "name": "tar-stream", "version": "1.5.2", "description": "tar-stream is a streaming tar parser and generator and nothing else. It is streams2 and operates purely using streams which means you can easily extract/parse tarballs without ever hitting the file system.", "author": "Mathias Buus ", "engines": { "node": ">= 0.8.0" }, "dependencies": { "bl": "^1.0.0", "end-of-stream": "^1.0.0", "readable-stream": "^2.0.0", "xtend": "^4.0.0" }, "devDependencies": { "concat-stream": "^1.4.6", "standard": "^5.3.1", "tape": "^3.0.3" }, "scripts": { "test": "standard && tape test/*.js" }, "keywords": [ "tar", "tarball", "parse", "parser", "generate", "generator", "stream", "stream2", "streams", "streams2", "streaming", "pack", "extract", "modify" ], "bugs": { "url": "https://github.com/mafintosh/tar-stream/issues" }, "homepage": "https://github.com/mafintosh/tar-stream", "main": "index.js", "files": [ "*.js", "LICENSE" ], "directories": { "test": "test" }, "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/mafintosh/tar-stream.git" } } tar-stream-1.5.2/test/000077500000000000000000000000001270542720000145545ustar00rootroot00000000000000tar-stream-1.5.2/test/extract.js000066400000000000000000000246541270542720000165770ustar00rootroot00000000000000var test = require('tape') var tar = require('../index') var fixtures = require('./fixtures') var concat = require('concat-stream') var fs = require('fs') var clamp = function (index, len, defaultValue) { if (typeof index !== 'number') return defaultValue index = ~~index // Coerce to integer. if (index >= len) return len if (index >= 0) return index index += len if (index >= 0) return index return 0 } test('one-file', function (t) { t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'test.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'hello world\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.ONE_FILE_TAR)) }) test('chunked-one-file', function (t) { t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'test.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'hello world\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) var b = fs.readFileSync(fixtures.ONE_FILE_TAR) for (var i = 0; i < b.length; i += 321) { extract.write(b.slice(i, clamp(i + 321, b.length, b.length))) } extract.end() }) test('multi-file', function (t) { t.plan(5) var extract = tar.extract() var noEntries = false var onfile1 = function (header, stream, callback) { t.deepEqual(header, { name: 'file-1.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) extract.on('entry', onfile2) stream.pipe(concat(function (data) { t.same(data.toString(), 'i am file-1\n') callback() })) } var onfile2 = function (header, stream, callback) { t.deepEqual(header, { name: 'file-2.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'i am file-2\n') callback() })) } extract.once('entry', onfile1) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.MULTI_FILE_TAR)) }) test('chunked-multi-file', function (t) { t.plan(5) var extract = tar.extract() var noEntries = false var onfile1 = function (header, stream, callback) { t.deepEqual(header, { name: 'file-1.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) extract.on('entry', onfile2) stream.pipe(concat(function (data) { t.same(data.toString(), 'i am file-1\n') callback() })) } var onfile2 = function (header, stream, callback) { t.deepEqual(header, { name: 'file-2.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'i am file-2\n') callback() })) } extract.once('entry', onfile1) extract.on('finish', function () { t.ok(noEntries) }) var b = fs.readFileSync(fixtures.MULTI_FILE_TAR) for (var i = 0; i < b.length; i += 321) { extract.write(b.slice(i, clamp(i + 321, b.length, b.length))) } extract.end() }) test('pax', function (t) { t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'pax.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 12, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0, pax: { path: 'pax.txt', special: 'sauce' } }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'hello world\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.PAX_TAR)) }) test('types', function (t) { t.plan(3) var extract = tar.extract() var noEntries = false var ondir = function (header, stream, callback) { t.deepEqual(header, { name: 'directory', mode: parseInt('755', 8), uid: 501, gid: 20, size: 0, mtime: new Date(1387580181000), type: 'directory', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.on('data', function () { t.ok(false) }) extract.once('entry', onlink) callback() } var onlink = function (header, stream, callback) { t.deepEqual(header, { name: 'directory-link', mode: parseInt('755', 8), uid: 501, gid: 20, size: 0, mtime: new Date(1387580181000), type: 'symlink', linkname: 'directory', uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.on('data', function () { t.ok(false) }) noEntries = true callback() } extract.once('entry', ondir) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.TYPES_TAR)) }) test('long-name', function (t) { t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'my/file/is/longer/than/100/characters/and/should/use/the/prefix/header/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/filename.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 16, mtime: new Date(1387580181000), type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'hello long name\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.LONG_NAME_TAR)) }) test('unicode-bsd', function (t) { // can unpack a bsdtar unicoded tarball t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'høllø.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 4, mtime: new Date(1387588646000), pax: {'SCHILY.dev': '16777217', 'SCHILY.ino': '3599143', 'SCHILY.nlink': '1', atime: '1387589077', ctime: '1387588646', path: 'høllø.txt'}, type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'hej\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.UNICODE_BSD_TAR)) }) test('unicode', function (t) { // can unpack a bsdtar unicoded tarball t.plan(3) var extract = tar.extract() var noEntries = false extract.on('entry', function (header, stream, callback) { t.deepEqual(header, { name: 'høstål.txt', mode: parseInt('644', 8), uid: 501, gid: 20, size: 8, mtime: new Date(1387580181000), pax: {path: 'høstål.txt'}, type: 'file', linkname: null, uname: 'maf', gname: 'staff', devmajor: 0, devminor: 0 }) stream.pipe(concat(function (data) { noEntries = true t.same(data.toString(), 'høllø\n') callback() })) }) extract.on('finish', function () { t.ok(noEntries) }) extract.end(fs.readFileSync(fixtures.UNICODE_TAR)) }) test('name-is-100', function (t) { t.plan(3) var extract = tar.extract() extract.on('entry', function (header, stream, callback) { t.same(header.name.length, 100) stream.pipe(concat(function (data) { t.same(data.toString(), 'hello\n') callback() })) }) extract.on('finish', function () { t.ok(true) }) extract.end(fs.readFileSync(fixtures.NAME_IS_100_TAR)) }) test('invalid-file', function (t) { t.plan(1) var extract = tar.extract() extract.on('error', function (err) { t.ok(!!err) extract.destroy() }) extract.end(fs.readFileSync(fixtures.INVALID_TGZ)) }) test('space prefixed', function (t) { t.plan(5) var extract = tar.extract() extract.on('entry', function (header, stream, callback) { t.ok(true) callback() }) extract.on('finish', function () { t.ok(true) }) extract.end(fs.readFileSync(fixtures.SPACE_TAR_GZ)) }) test('gnu long path', function (t) { t.plan(2) var extract = tar.extract() extract.on('entry', function (header, stream, callback) { t.ok(header.name.length > 100) callback() }) extract.on('finish', function () { t.ok(true) }) extract.end(fs.readFileSync(fixtures.GNU_LONG_PATH)) }) test('base 256 uid and gid', function (t) { t.plan(2) var extract = tar.extract() extract.on('entry', function (header, stream, callback) { t.ok(header.uid === 116435139) t.ok(header.gid === 1876110778) callback() }) extract.end(fs.readFileSync(fixtures.BASE_256_UID_GID)) }) tar-stream-1.5.2/test/fixtures/000077500000000000000000000000001270542720000164255ustar00rootroot00000000000000tar-stream-1.5.2/test/fixtures/base-256-uid-gid.tar000066400000000000000000000240001270542720000216750ustar00rootroot00000000000000package.json0000644Ào-0000000326612634176473011630 0ustar { "name": "immutable", "version": "3.7.6", "description": "Immutable Data Collections", "homepage": "https://github.com/facebook/immutable-js", "author": { "name": "Lee Byron", "url": "https://github.com/leebyron" }, "repository": { "type": "git", "url": "git://github.com/facebook/immutable-js.git" }, "bugs": { "url": "https://github.com/facebook/immutable-js/issues" }, "main": "dist/immutable.js", "typescript": { "definition": "dist/immutable.d.ts" }, "scripts": { "test": "./resources/node_test.sh", "perf": "node ./resources/bench.js" }, "jest": { "scriptPreprocessor": "resources/jestPreprocessor.js", "testFileExtensions": [ "js", "ts" ], "persistModuleRegistryBetweenSpecs": true }, "devDependencies": { "acorn": "^0.11.0", "benchmark": "^1.0.0", "bluebird": "^2.7.1", "colors": "^1.0.3", "es6-transpiler": "^0.7.18", "estraverse": "^1.9.1", "grunt": "^0.4.5", "grunt-contrib-clean": "^0.5.0", "grunt-contrib-copy": "^0.5.0", "grunt-contrib-jshint": "^0.10.0", "grunt-jest": "^0.1.0", "grunt-release": "^0.7.0", "jasmine-check": "^0.1.2", "magic-string": "^0.2.6", "microtime": "^1.2.0", "react-tools": "^0.11.1", "rollup": "^0.19.2", "typescript": "~1.4.1", "uglify-js": "^2.4.15" }, "engines": { "node": ">=0.8.0" }, "files": [ "dist", "contrib", "README.md", "LICENSE", "PATENTS" ], "keywords": [ "immutable", "persistent", "lazy", "data", "datastructure", "functional", "collection", "stateless", "sequence", "iteration" ], "license": "BSD-3-Clause" } tar-stream-1.5.2/test/fixtures/gnu-long-path.tar000066400000000000000000000166521270542720000216270ustar00rootroot00000000000000././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootnode-v0.11.14/deps/npm/node_modules/init-package-json/node_modules/promzard/example/npm-init/init-input.jsnode-v0.11.14/deps/npm/node_modules/init-package-json/node_modules/promzard/example/npm-init/init-in0000664000000000000000000001365212410635701032177 0ustar rootrootvar fs = require('fs') var path = require('path'); module.exports = { "name" : prompt('name', typeof name === 'undefined' ? basename.replace(/^node-|[.-]js$/g, ''): name), "version" : prompt('version', typeof version !== "undefined" ? version : '0.0.0'), "description" : (function () { if (typeof description !== 'undefined' && description) { return description } var value; try { var src = fs.readFileSync('README.md', 'utf8'); value = src.split('\n').filter(function (line) { return /\s+/.test(line) && line.trim() !== basename.replace(/^node-/, '') && !line.trim().match(/^#/) ; })[0] .trim() .replace(/^./, function (c) { return c.toLowerCase() }) .replace(/\.$/, '') ; } catch (e) { try { // Wouldn't it be nice if that file mattered? var d = fs.readFileSync('.git/description', 'utf8') } catch (e) {} if (d.trim() && !value) value = d } return prompt('description', value); })(), "main" : (function () { var f try { f = fs.readdirSync(dirname).filter(function (f) { return f.match(/\.js$/) }) if (f.indexOf('index.js') !== -1) f = 'index.js' else if (f.indexOf('main.js') !== -1) f = 'main.js' else if (f.indexOf(basename + '.js') !== -1) f = basename + '.js' else f = f[0] } catch (e) {} return prompt('entry point', f || 'index.js') })(), "bin" : function (cb) { fs.readdir(dirname + '/bin', function (er, d) { // no bins if (er) return cb() // just take the first js file we find there, or nada return cb(null, d.filter(function (f) { return f.match(/\.js$/) })[0]) }) }, "directories" : function (cb) { fs.readdir('.', function (er, dirs) { if (er) return cb(er) var res = {} dirs.forEach(function (d) { switch (d) { case 'example': case 'examples': return res.example = d case 'test': case 'tests': return res.test = d case 'doc': case 'docs': return res.doc = d case 'man': return res.man = d } }) if (Object.keys(res).length === 0) res = undefined return cb(null, res) }) }, "dependencies" : typeof dependencies !== 'undefined' ? dependencies : function (cb) { fs.readdir('node_modules', function (er, dir) { if (er) return cb() var deps = {} var n = dir.length dir.forEach(function (d) { if (d.match(/^\./)) return next() if (d.match(/^(expresso|mocha|tap|coffee-script|coco|streamline)$/)) return next() fs.readFile('node_modules/' + d + '/package.json', function (er, p) { if (er) return next() try { p = JSON.parse(p) } catch (e) { return next() } if (!p.version) return next() deps[d] = '~' + p.version return next() }) }) function next () { if (--n === 0) return cb(null, deps) } }) }, "devDependencies" : typeof devDependencies !== 'undefined' ? devDependencies : function (cb) { // same as dependencies but for dev deps fs.readdir('node_modules', function (er, dir) { if (er) return cb() var deps = {} var n = dir.length dir.forEach(function (d) { if (d.match(/^\./)) return next() if (!d.match(/^(expresso|mocha|tap|coffee-script|coco|streamline)$/)) return next() fs.readFile('node_modules/' + d + '/package.json', function (er, p) { if (er) return next() try { p = JSON.parse(p) } catch (e) { return next() } if (!p.version) return next() deps[d] = '~' + p.version return next() }) }) function next () { if (--n === 0) return cb(null, deps) } }) }, "scripts" : (function () { // check to see what framework is in use, if any try { var d = fs.readdirSync('node_modules') } catch (e) { d = [] } var s = typeof scripts === 'undefined' ? {} : scripts if (d.indexOf('coffee-script') !== -1) s.prepublish = prompt('build command', s.prepublish || 'coffee src/*.coffee -o lib') var notest = 'echo "Error: no test specified" && exit 1' function tx (test) { return test || notest } if (!s.test || s.test === notest) { if (d.indexOf('tap') !== -1) s.test = prompt('test command', 'tap test/*.js', tx) else if (d.indexOf('expresso') !== -1) s.test = prompt('test command', 'expresso test', tx) else if (d.indexOf('mocha') !== -1) s.test = prompt('test command', 'mocha', tx) else s.test = prompt('test command', tx) } return s })(), "repository" : (function () { try { var gconf = fs.readFileSync('.git/config') } catch (e) { gconf = null } if (gconf) { gconf = gconf.split(/\r?\n/) var i = gconf.indexOf('[remote "origin"]') if (i !== -1) { var u = gconf[i + 1] if (!u.match(/^\s*url =/)) u = gconf[i + 2] if (!u.match(/^\s*url =/)) u = null else u = u.replace(/^\s*url = /, '') } if (u && u.match(/^git@github.com:/)) u = u.replace(/^git@github.com:/, 'git://github.com/') } return prompt('git repository', u) })(), "keywords" : prompt(function (s) { if (!s) return undefined if (Array.isArray(s)) s = s.join(' ') if (typeof s !== 'string') return s return s.split(/[\s,]+/) }), "author" : config['init.author.name'] ? { "name" : config['init.author.name'], "email" : config['init.author.email'], "url" : config['init.author.url'] } : undefined, "license" : prompt('license', 'BSD') } tar-stream-1.5.2/test/fixtures/index.js000066400000000000000000000013711270542720000200740ustar00rootroot00000000000000var path = require('path') exports.ONE_FILE_TAR = path.join(__dirname, 'one-file.tar') exports.MULTI_FILE_TAR = path.join(__dirname, 'multi-file.tar') exports.PAX_TAR = path.join(__dirname, 'pax.tar') exports.TYPES_TAR = path.join(__dirname, 'types.tar') exports.LONG_NAME_TAR = path.join(__dirname, 'long-name.tar') exports.UNICODE_BSD_TAR = path.join(__dirname, 'unicode-bsd.tar') exports.UNICODE_TAR = path.join(__dirname, 'unicode.tar') exports.NAME_IS_100_TAR = path.join(__dirname, 'name-is-100.tar') exports.INVALID_TGZ = path.join(__dirname, 'invalid.tgz') exports.SPACE_TAR_GZ = path.join(__dirname, 'space.tar') exports.GNU_LONG_PATH = path.join(__dirname, 'gnu-long-path.tar') exports.BASE_256_UID_GID = path.join(__dirname, 'base-256-uid-gid.tar') tar-stream-1.5.2/test/fixtures/invalid.tgz000066400000000000000000001641661270542720000206170ustar00rootroot00000000000000}>0S{_90S(1dYe@жГv ag8}MB2;g9;T*JRW:MAn񿝵 Wյfӎ謮omIl~qgf^zPm4WڿWA%/ckcrV7֞nmItBZxC8KK<Mi䅩^4 oO?o8 "S0CSec{%|ʒ'm[8_&49|p&qVF5)al>Y 2axAD.cc#V:KF?NSO] ?i\0FtOrSy}dHA'^'Jx}'!qǞ1'KiLn&I'ȡ^AL2Tw8$M۴6NΪu0 y'M30Cs_r08aC?@fEC/qٕ(N_rr]ɇ7yF؏ 3ufo ~oOGqpʼnw:o>l>|ַkx?O%?(+Aھ_ymT#\ r]I_Қlˢ}iv |*Yb Z@,/ @2 ;ÿ]{86N"~%}^k[hm<_]{ m}5~h%$?g`ŶHNoSRo fje2&fA(ԏC~(-ċh'` þ7FȢȪlH=fP50QS(̮S&C:Q+T댖g5* HL0D'j/r<|jYQ=S@ѿw~ |fF,d`:?'P=5]@h>>NI5X3RL70@3V$n9kQtU7瑀,WL;S K[[N#5SV{}<~pbԑ*sK `>}o5A<*dݚb]@q\g"h YL^RtL\g|#g!>WF? G]֘;v)y ~1X Z? oEge@XU5SRٰIMOgM/J۶ 8CO5||j?pQV#jYAq:$9"/gt[ .xjcbqq>Dk0v!ڐH]p'"ssh&ٖBj,wYT+fOb5*eyly'n-7($&!ulVJ+@P|7BSC {/uHI|b02l^Ii~n> %Ii~W{5߂Kda?iCYbJ*cJڛ,i5=D;@jR#VၪzOId!2_W{݃cںN F:Rr+ni8JTa4ZSIK&2{- IKvG"z -N%Q QpG4a0`@$P34hŚ iz H0餶 )N4 L'X;A%:/hc^pr88Q8o 0 sH,I!Y-ɫ8>|yv+z{{=x~o{'OO898Y;?j9#{fk^'-zr(C =ݣW΋~x;9@/xst=9oNwA}=8iCЕǯvS=|QW'W{] rW0ySZ#޾'owx4=<89?[0ʣm;Gc@#9!v]Ό@1.{ݝ}u0ǁ?ɤ[|R "Bd)I3+^bL/Z[Ed `_ >x~P%H5kfc~_Z "?u[%K"h?E Qmԃ,`=bх&=)oC1ǐPaǏ[PL"F8?1.`ɼOdX T4jqK7_O|5UMg++Pr5x%5,(ΜFG|ƽiC{;.ѨTxʏ.6n]&ae&OPNgIO7 ֎-K: h{\vf=Jtc%̕^GEZ ,X.Kyt4iNS.S 8Dvy$~DM U4Ҏ8mR}Nrd?xC )ᣮ m{iaå%p1 pٔCZR&=h)\cRe;a &e| %1LS1%`z">X)?uuT?q%+5NP%?VE a#rKnaX^@!'LlNaK :>q'p ć/<|!7$|Ͷ82,h^U?b}KCvћNCyE Bb^\\GgYyN<~XrHpKϿurWaYY.se?++5CNĭ&/H؜2gNiU_Tq&:[ IEbġ4QIZIYX_u/0jG^+گl?Vi[xFf6j9ay4r `5f\ OIlc4c*6񕍆|Z}ɉ˴>i(ƌN /UD –ϒVq25)U$ڇ_,-̐R_JvS 5H&_ThX9C0r YJ5 aD",`ZNkZ>PQ.HAgt%D3nu|Bf<m,;hm4)OS-NzT:Asadt.IujIunNؐUbs.4H7Kxgbdxf.06)>9i @GEc "Ղl*90\1;S{`zDd3% FBjX]V,Ƴs#ABQ3KVS(VކJ4yuLQT%՘XFK Y;n`9Ax{p oNǺ1'N9EmqMS:Bqq,&c߿ "4Cmo08i!VW %DiBo^ |(Φ.7\)J=F(&.][\ULt8Z=jZMsT]Vs!]HDS*`@Y 953xڸ/ĽN/{v1LD#o1͵lGCgan׾t:FAv(T!p֬8< v%/&y=sut.y)I(,|($4É80BLc\HKԡ4 e/;z0E&6|elE䡉 Ba½$7DpI\N/9̽X y݋ *4ޛbBОUٲPn9\:KK,|h!{%HȜJP ɰȡ C"=kP1sEe5r㕚%NOar@Ne˜a# IB"|vH~[DjS*t[ÞIc;͆L29gm?M)0 .|_O+Dh<ZJۆBhc^)-y BLivwu6c?FGN/1 Nhx`E*,fZWؽۊPvtͶk{+-VequkTY\tN9-Reg5?^ښBcc(bX%E:([rB}Iy #}9K]mJU|8pF!yn--qYg!JGI ^Jͥ%VoJLd$d(0bQBW Z]P)L=NR7SSHWyĕ7{(i@bI`#S.nlay D#\\ ƠI%Q禟g$"S8!N,t~bgNmnM-W)վ`4l?/od~}8Zy&Zנ63vCGjJ$ZmVk |l;'ܰDjU1y r+V:M1ܕ1;5wFkuB+ZwsuBĴVZ͋p=PJy᭜&[hÇjVgAkU9 +ZkZ/6ݿ@4šƼH/XgiE2y9|Pp/] \[͵1#h5X5$U$'Bp-Z@L{D!9->4>5jًj)c)ڧ־E~٨TԈcRAHUPy8j4,R7@TF>jCY>} @5fCZh]&F}JCऴL `=ִVi [|EQby!1fMeվŖ~RliA)R/ڟTT cJ}#J G5c;6kqAcayA?G[W }i>'5BG`ڿch>kzMH[?$^3XŊRFj Ɖ&Z QS? =@LI?\R\s?76ן6V1ϯGӔ7p_ Uᯋ`sLZӶz GV.}9l)LU_(2n&,b):Tڀ(l>m V໒5,kIz:<9 @ޡ4*UMPUK5uW;_ *Y-)٤-*Y/)yJ%%%QfI_dY:4^CC7J%[Bh^٦je7K5&`+fvn -%uUn˄V+fMʂtUO卪s[*صaS2Mºƅ ~^.js'܂<扺%ߧrؕk~]bE(H%OGk:s:Zs֭PT'w/Mv> {Y|\[Wd5wI"—1n!f|N17_<|*Q6h&a?l>cCzgD)j/?4-eɍb䭸YeVߜg:'ԉ}=DNUҰo~A9*4z+f? ܊[b:H?kXiu+2R'rId(Nʾ 2GLb ͚M>cċm@m%t_nYM!y1TvAr+ԓ G'A*' 4*VloiELX9>_0FqS enTu3dJ?|Y{evoqԨ8)I?8wx*quOXt28a?5U^Ia"gM_#1Cowwz7 ShP ѣ%MSnk\Pӑ^w9-e^-^H"aokyU|g|Rny軀A!5 =w`uFuMN,K+mOLF /n-VH\Q^~cIv;)kOB/bZK9(;frF_li"$.>}ho/?}|;)jL` z*&9jRGhJ| qQ0:͖v`6t>HJ }Ҧ]j- h|wTQH3PZQUR᠇c-2nƪ"wؖ8<]|Λy㿩濳ko_罍iqm f÷E~;[<&ϼy~{eOcX\__Z*?`4˗\~eM;Tlm*'OTBV;K5lYd¿e,{s z_h;sk^\SMolF'GFSq7)M\dPS!`&Ho2̞5E[%uwc-.%뭿ыWP/oա+nݮM5L``w.”#x9C7n 1DHMTG@wwrR`#(%κlD{> *W3Sq"9_6v{ٜ1N;8[ K3^V|ɚbTb{X>KI#Ӓg"%DJ[=]]m7a5EۥH_|n#%im48iJR+ѓTjI?ʊ(]'&8xY)Sf$>軽't6+[)Yzז٠4%/b\ZW'J*,ExSG2HP*%YV-o*? GLoao^4hS0?BMVvmesq(`R_'hQS\h)Eo=W<iiLNO,%GDѮDkWD} .= P'۝7GucqK흼:<=PhgqR,w9##{fׅϽӽO4=8<׽{rH}Jh1֯G΋~x;9%ovNz;Gћ. z/I:F`w[ߧwNaGLjᛟz?:Ey`t;X{;w~RCtD5%o_uSݓg}q%vzHG[  4=2 ;APF`]^wgc{~9aY)"p8 .22Jr9Lqq`xqmq*iA0^8c8r(e9llO9:# "l*6ֿ{.V֖XZUJ/M5mv 58g$PNp(9*_ UmzHjsWmZ"U@*pMMbV׾cpk/ myӅ5mMtzGݝ\5f:8<9W|kwH:''yp[BMٮ{wx)?j'ϯaw<-TOvB%fz{TbUbzE}qUՏ{\ +m FnAV(WI|#Q{~D iR8|T,YEs&x{L- 4D{DbdI BfT͒$&j9kt#T7D,V8(26/z{ABML()D;k2mߕ>2NlT=3@0nN_gHD/øq`YY_U#E;`u-@D+J;-wлEY>o_&cKQ4hO?ڀ,|(C5o~}*>`@aUmLY"ɺN[C]n3H/С:XM/F4Bgl+{S &Q;@<$򪽰iCPz-ߞ&2Zz-*D^y%X]ӕ/)bO2y6dP\K忟"<~?@!nm7D~sj\MmRbm{/_4iꆀRyA$ӣ+T ZngpiV/xaϿы.lLߎ1A3{?9@9 ?>waPc, 1 k\jBWYX3# =IQ;%07u%JH93J~!0PX܁;)+Xd&s;%$ :ø N{ҶT.V%R2]#.KZi/z<ӿ#2,Vߡ+*2r|$RS!p㳆2]]ơ/PR\ Ruzuz a<X֟h\ y`ЈwԺHaa=4xΗS1hfy{T݆VmEKՐK-:.$Wq9mەG/V =e XC4>gN:oxߩKr@zD]״۱p gUXÚ_t?r9Ҍ+:-ЬZ| } uF{O2^ G)F=U5#T?lj xItYE 5݃㟏UK Y7sI04Խ'uv .OK*SI#P܂cռq}>q|Fh 9?. ~E(=&T$&,/1GzKU᝵A)iмLdd-DR'ng獷|s/<`-GD/.hZf_z[uHg>}=:b6mY.eSaOfB4^?vѪ,*j\z2ek6 9W>2ט:bbu+e2>`kx,Tb %oT~ᓫsHz1u:iN:%>/xBRpcVD|PCre;~%7˿R)ˏX OgSipzk)Yh %jh`ghwq8{࿁p|,Jp}>sbֲGZ"״w R,#RQ1E,ah F**E|rK X9"3~LƟ.Th=R.{׈)RkaXoJ), Y*-3rXvWT(/{,_*1rrZ~r䉈{JT~iG kʏ֠:S70E*'8 Y{< yт-ຢgGlS84Sk~PWJKE/յt-(@oqVR*sZʟ9N$E927WWɑӥE>˷4G|  GxiaN.>h^ytY`K9w1\(* KnYrnǶx7aWz8?@OV-$yrs95.Y?;BsWKB?ac]sO_zov",D^֮e Y"?i|lۆ-QY}%Rjʰ]8f*ed|.)b!ӁLLT-gqHx1 K" J Kl@I %b*O%|{-a&}{)U0~ ]{rp^VlAȄidOg2e~/^M0BZ1SqL-G%BI䴨jm:9Ojf%5E8o)SVV[ewE&+޵CD>4bI]/,'9Q R8X\P.VF#j7G(76`/ 1l4 ק+-^y&~5,4mV;t(C%~ Z1)y~_@(2a?_!TwB{㪊%Ufl2UY115'řF)7ko}Is%y9y4'W) 971w=Du׬3ܧ;5DW¥l"QU0WL!rZT].d[ (l%E:ݧreҥfy (ՙ|֥FYNPrjn.|[FUeSzݤ'?Jy ze[}_A?gcks)0)e VL) lP?yNTh^iX8CћR vAsb;ٹ^&FVdl)JlkmFKhEn(AgMBrKVk/SjA~ ̯W'u|~5Nkκa,__q-:WΪ6^ԋz#~CaLBzUd0MϏ'鏟KAn_øMtýCuC3 207u`q4s9&3`0\L X"Й\%UW*@k_i;r@UuNJ#%m"c{-TVd *_Eo/0~ mq%e#ӗHtxץͶJ ?/e)goMDr-F4˝oQ" `b Db M%2|QWY~7 \/bh|8WkzZL"+ ->}F^Z miuO!8-ucDC=9P6B bQڥ̣Rss?dZ 51;6!}h:E F]8V0Kn9f`z7%Me>(!/b I|yn %n,4䒩BH5NK!)餗]Y91[q({kV4T;}6M"oI.+ =#p G^R_ Om)(Op~F8p} 6@ZTohto_\d|u J?SW,%hs[Z * dfml|$kaWW^ :nʲ Zcp^IMkPqYkULNilU?%턡j.PXIyԧrBYV6fMS'G@on"6֚ b{6)PL\eJ^tg`W@, qr.)lW8-!rfkҟ ga Spvi@q"njXa&2a`(<2V=L?Q D+ޣn ѨNR ( C8D2 ygrhC7Abۤ#W! YKf1&9E '0#QLזr2fHr3+^˴*Dyx#x x 3rXӚuV-C)~♘MJj80ڪ5Zia^c;Q 60ILϸԜZHѾmWv̗d?ٖ0S>Q ٧ ;`M=q.yO&ErEm©i&_AWjes'\!VH[(.- "ln#`V'tj&'TᰆR\K2r[jn1Iux/>ԇ}%69^D|rCA-`?'zfiafPm$\?c&g;.N&ᅋnv woϴbL"c[1t 25D}=33Q2Yq'ѡ1h8k\y]vH]QMHd" JEľs8K,G#M+"ԹsDKJy|fw+ 9}:5CqV>o翛IX!1o?<|cIW~ZXP>K2f Fpa' t\KN[>{WW)̘47uv8Oҩ K.fnXs5e щjҲļZMV.|W3"l1 j=$Fɤ饔Ս3.=\sJm>aEF*URf:ak%pZiY:6 RJ*XhMy=,k YBfF8#ayƃ |5Vq8?`ztJx.L2hE{bT<7sά&W#7zTnQC|*N{=iwLf0`^sAu81^{ X(["Py|<[bIv6ظ 㛷5|&V«*ME4*_)V5Q=R<[U*F4zI\P<ͭY+xi(* X0v ףT(U܁- @epX)+׀AfJ5ԭUl|? MLƨPAY:&L$ j5.<*Z ȿF%֚q ٣d_6 BFcF$m$1ȶuIޅ<L=KyϿ fQ~R-ki5]E9_Ⱥn 'r :!Rw%qF/3GLK󰶺QJRo^5[, kl79̌0nfKIMX5Zj'$=v5/>"R &> O>!0 >g*-QnP$cخ2q] "HI䓵Jc.Wݛ?%^R{NU>--vgBwQN BWZT/DdU8[}`ozt7U#Y#Σ<*=2 /k10tw z!AS,J"Zr.,q_-=6|3DžI?[8F~g.FǘEI-Qqlme0|=ńmSoI }IjYi۵$=q^F+׷͓R)q.n9󄘻/"bS,F8!,\:nm$~] e= NU<75QWP/r>a?%ŦMڒih֐sų'aޏ:dYU9+bҍ{VXvCˊl)k5*ڲ`*1ˢwoom.i'xk3X&xö6 !Ȋ5*Pٮ9b?[xvl\sDlkf՜k>Wqf*wfS*H' {r ! 6"noʭ)z:-:;3J ~ZŘ~ʲ$1F1>hjO`j =Z``=㘲'ׁ-Xd ;'KN1/|I 20^Tf=H`–(uoqHs7Jk{D:~.zon6]}3OjUe+i(vL8GAow xdm{+1/ٝGL &@oz5b8GoA 6fAԦjo0N}uz'd(DVA<)0=@˟„^0joT0SHRy܋LE+pCڸDF=^v]0rr|2U#6/Ц +$ 9#tuSEղA>IAA2I=$eq+$Λg0٥4Wo^aΣ4 AOɔFv V/A83&)@yUCsOs RtY KK0wxP7g,- s4 R $XH[ӍU4t,SrOOyuu䣾Kn1 x#? >N:ivWJ"sx ɘvҰ7# jKK4ae,$hcĬ')_[Hr B'MSVN1LBd^5Hc t"GY$9&S:6Ľ-(F?EQ)G. 膽 `נ`uTHnȅez8D3 %c^wx8فOKA==4eRd@dͭ}iDPM+j- $8 86S1ە( sY.B*Fm$)V9 FMjEl=1 (MVqbEgQ`6F2D>/=Erf^  {hZ-z6_̭Pݡ 4iǓVjMbmzz/]O3-sn[=e8Q4GfE',YD.*8,y$UɔhBF>]2r3f6%1— jD)%66 #(Q7 9\ w_0iˢ1&R[O:лTDѠNGq0_Q$txB@qČA:f)QYqH78iՀmZh/"y[fVX .xwLO8P$JLf K?3! $]r%bNc@dceimҎc\F/'bF,So|+Y9,Ihu̜Bz|!QLj),hYVfֵhGhҏ|Nc DҲ RiGvNʗ"1@ hJ=⿎(kIG kkS'M;|\xxKUf}2'H1j\#i0)kZMh`kSұf-VfAH☂Իy$iXg|,Q=X,|[‘p-2Ӊ:'15-*񁞑RLlDJNEXGtvZDQt9aW0wfG"nW@5Փ tUX^g'ysII$m҄$ʷVPzi? cRY| ؗ 3y`A~# ܻJ-;tIJ{qE \z?kP6KF |Euн?PH)'`1%%ZTu..Ĭwg5=cO*e IUQ902WHP-=(3Z!y+݉Hy#9`3Mqo}ͧ%wa=7BrjO,񳂞6`>9Me,Q:tZz'Q> GJF@ z`3ۿf[W}MD+F%RWIYw|{d2q|UwkmJȔ;2JYnوֶ RbVep|.nGo֕nHEN"wf)31a|yl<ىb~dguBg+aK$NS qVÑШKtÇx xok*RSJ2=t훨_$3a4I _s}'=y03T9dg-i+ߙ/gJNS qW' Djx` щ1xS3[Ɂh,:퀆Af|}lئ'D=+lov{nuz{>HXC؇抟Vdy$]i6~Vг. ]_4;H *5{v ?rFT{gC|Wz.xw␼^X@(&tg \^ \)PvY]iđjiĵ#WU 63tq*dV}xa?*> RKEt9$$'+f-Oy@od )GX/Oӣ2wZz`1/bf(O:8xAߘagֳ&ڤvS+rBn9o;aJJ?tK/dxI3$wt10V C=KSk l*%S?)[4st@%^W[1nC7$b*$nL}Q)S` jPkÙŊt_ɰow*/o΢*5X6Ӊ%Cb9tJXrE48dyt ^ ϧPG}!THya(n2H:itUϢy$-e|łZY$O^pM>|OYNxQ>C7[^$6iwTrG;qHtD‰/fQԴ$<Vu.ԕ 6PLx4z!v8Cy 3"RL$XgZf-<- 7g| W*y!#eH.\VH+pg̈Fre|Oe`h8ѧKב'n-HzT7Rq9l4=4d]U#.ui?%=eM,?ifIuȥ|F`-ji鞃ˆVXa/p'uEyNN jWPLղ7?> ,AYk\4Κɹ""~UQ㓯unzE7;d#֠915sĔP|rrNp:82cO-0!/)eIhQkBk'3%U}].c米g,xE4-c)8TX͜'޻7qeda2҇Ӹ01t)Ke[mJ0糿/uJpHG:s:j׾/>ќɐ,RWoҮ 1U~EMN`fPi!t- n{i glF\m#",z1z`OJV4T h|]EAyi(~"wA _'0=mR]ǻe;'*Dpn+LDЙWT'EF pvx3j8/ѧ m/UgxZDx~Qr `P0Cva!{c)6r:a?9]kD^1GڐU:#~R!(f^)Sl? 62S'AL)ƛJD~!Y! )Gr9DFf_ "E='88An6&8d^ɱde[\wD@p2qU9}KJ/2y|" 0hQ2bl|Q`h'2)(:s?6vGWC\4k!)Nc!8+{i%Ezi|䑝9YǶҮ>G^x( eګ$參Yo(,q2zOvHEtEz ɰRNXݖxG忦stӦ[57I36]egI_I5ͯE/I<=G>lؐIC=\+cuD)AR{:\I`̈́Di~M+#qߒ6s!8rnsb҅b2D/.pk3Ԩ Č(ßvKTo\8Y҈=zfCFƻjoQAsDd+MZ$؆Ucja'5\a[㩌utY$1 ~}tRvuV"sCx*F"O( M&\V^z?L0 XH>琒؅48|E!EݳvISUf[`o)|bgO>e{Sxfx*zw=q_tA+q>Ob$|??l+)̅>.=yr}ǓSoAXDl;PTg0atU cW]0W$p&L}:\1߬oBnssnƯ 8h> I#X++5~NRp>:r Y#WB^~ihcog͍M[;;jkl % Kk k ꢵʼj 5ԊӹqZôb{7Fiŏ,Ҋ,KAh jg HPΊq4k02k(0k05Ge e ̓zAGd XyX` `2Xe@7Eb b Jk8kBscon,,b7^ŭ\x@uqW6jx r5ڍV*V P93GA)`) A9*ʣ#a^>L{u c/s`EH)4` `R=&FQ 1Tc󂲔@8S#.elU^;5`3~)tjTXR s6]35yL0M Jx#T~B #%_I @IUb>2\J%xSJ`!x`9_5 ?UnJ. _,5X5X5&*A "j j_9]- 5X\n, 5X j `qT٘VjE@n-,TrO@#|Zr[4X4X4!L`9pA5کv`۽"iPtJ-r TTvA))vnSMovL7]d"_رI.jL5u0M+ M%i hfZ˴eT `Y8AP4XKSnWTD+SJTvR[o+C3KoK=|AMҠfT4+( vW0Tiuc<,+0iwo Rh0S4pa@Ħ4V%?%N|=^&]]4ܩ-32!G#㔨+V~A.,0@d:uOdn%C+ /Wӣ˦u1lVeL,38T#ae޺|~~sQg+GݵrG"z:Us԰BcǺGq8z`Ѡ.hph`F0\e-{ Ȩ-@µ~2EtQp1h0 W4+̃*u0EjHA pxL|_J A`(@DAQ{[@4u7F 5U:4Xrh(蔷dQ 5ԯEPERE8z)\h, ,4X+ivaP蜟Z -Z냄1B,+ &.7 ,4(%Ia|0h\` jqPts7 .WcH0 c X2@ @-s% ׮A`9?eN*fgȟ(zg~AEϻ% I@~&wʊkOI`*. As3lʙeʠ؞F<.{(冀A :p]ɳEw.]tQ< .%7qٝ X;wNbݹ\/V9`_½3XB`ˆB4`)E³XA-Ϊk< olu bz]3X3X3ȓr9y9WnaRsqRD؅|gPZqPR8+43X p\??gf@pNٙ_ 7+T;'CDlqO_֘ar~LZ.,n 8?ted4jalirƽ~ƳEǨI26O)s%D n>)y.`e{:8 _~_=}??e;GP)a{OÓ'??k+q> _?9<œoϠW~<^:jCäG9<5- Qų=x/5O_a={ɟJJ=ߣGӣW8?O^Ÿ-|JEkOxxGT|j+™ߔ͞ѳ'/7[^k;cB5rXlo}}OvzN}=n, ρOc;gO $Qwօ1;!Kt/_}|{7Яoovs}l'o_f1d0Yl<{ywqqEEPD(?߲΋pV:OF==mQBIQ=Oo_t}w;?x}`@lZfms7&o_pgYo BSԗ%9xI #,Fr""/<֤f^=Pjt޾@uͦ?`{<$wDr F,BrVt:;=}stǽWܷ)zGn!:pÃòv9|I}ʥC.eC.aewW֛:+|. 'o_+rJe_!<8'<<ʷq]fBK\a rŖk`#pRްMįŽuJR o;efE\EEJSUjNTTvo$pc w6u|ě#Ā&eJ"yh^1UG=C65bPin]wv ] ^ٵVj $\{7YgVc\y䴟%P+$KugɈo`D1ç T&xI>|6xs'J<yd9i]dLeyh-Ʈ }bw-3 6}+|!i]3`YY9j_L LBC& 5)i+{(ǒyKSBLwQ3GspSʤ\Yz ty2'G{M2=0H9dz{ww.d+PrU8*LO]B~g;͕ɳڥbOkiiq*z4EKTQ+':EKIjUBdc8'^ov5tPFKq$)L¾DhQ(@P|t#BwRFXЁcsjZ0of ;CĜ \7K y ]W~$WدjmՀȥ0v4@p|lu;U"xQy}QQ`ȏB1a08>* A_'>zךثYe?oD_k̦V̦e,yyG~&7|b%\v=1FhАׯ†Ϣuz5I'h- KRc#]81.JQMLwu'Ͽ_^sH߾qʠs.  뾠d*D,iw=Qaڨ/ҳra凱UOJAMltSN-1%NdMzrt7 'vQ߅J K}hkk5BNɏ6ȕurÃ5OӀ`G6T]nh^ *՛lr7yR놽;H e_QO8F5Kʮ8mtU@f;fgr )XI'NY#GR{D|#Cagxam8-(56S7Dbwon;Db$CA4f tf HHj#}oL zH뒇 Sya?%[NbWR;6E%izW~mb6T&u셚k6pΘ5Y9}C*B'qX8;4h&QMUmX ŌVh8W{j' TT #Jº(Ԇœҏa?uz0gY!&$`v! ƯF N^$1+Yy4uG)mǦZg?CptS`26 uO ɉ;С|cvRȭlfapn;5?iÏ4+H-v$iL/džWqE#әsT !hO9?E)Blݯ,Z/j /#`G|aJ w5G(_p[ƺ^;G9b>I lYCyFhBcn6;2`FPɑ3OpyR7e60IA'Pt^Rb]mMzPu/r٪yHb=my }l>Gr)-'xaΩa`$p!Ph[Z)akpaf@ck~G׽>we&p|yH\3ϕ̹niuKW.>p(S\zYeh>TWds-$͚+*`"abPkJoU-UȄX7[]W6o|ir0?[ݎ}6wV?[V?ۋF!8g}v?J@ZiOS&s='kZy% kMKgϠk\p nmX!FaPvV7~_0O?A&ֱƣ:({a6BB4P4-?ڨL1F_JRhW,[GOPWr1QYu)?~/?~g\VoGddEc;u有b>8Wcal_C*]d46ms /68h>crXfT`y(~Ak}X5Mn ĵ|J*lchBa.z3h ^|zinob53=ѥM05}N z+=c5|M >ff9FKo ~7\QY}]gZ~߸meS"/Ѽ>8R0f c\]? ѹ]OR)cѡh+#Ǖ:Υs%NEN*UPbs~UE6{,(:fHejeg *_0U"?# YJ<'w֙3kct>yRGG?;Ï >xfi=ޛZ<)|͘oj5jȉUaZ<=ԓzmpwG{&w~O޾:NrVկ_tLYv(fx$oh]xZ^-,_At1{KBs+U̮fViTBY؍aRI3JҼlu‡ |d^+~z`?s~`nWmO.$CZjA6dD?dp 5}]=G)0^0 tk̔sMz؈r8+quGAYyiUa4R[\:mtQP?oឦmfNnm o%}szJ=oSj5L;ݔI.ztf)GfFo.*Է)a,*ByWeR[Up73qy hǔ7Bj< ItBCjx' ahe<ax䣙]E:ɾǼL:y(N8JOigߡ ^F#Եf2);Avn(*8`SQ`/*N.v0p8@ͧ_-o^ߍ]Ưs?jo7yg8z&6}@;[U[+ގ7zyHMm?E4r<+/ޞ6Zs#a-[͡skqBʼ_mnlBap ds$v//M 'zԜ~Jړuʭq  %5ƌ9N/n (nRuF_d4g@o!D76d ^Z'h~A%bʬ*ӜWy^I$Zcρa8T?TO{-!g4Il80;럌 ׸/05_˜7lx )S7LDm3OO ~H'Z^1QKmzo±-kuu0a)|(x۵J9elB'BkC!P5EV!?k"slb'RR62t1]sڑ9F;vE IXB8K ΍U+WћY/_jg~}̬׿!{*lFقcʔ-%9G2&(S%jIC?tpc|433$wFOxǎ۲7¥3G|jF~YFxP ?I#tE Nkim燢 \Dz!2$0H{LIj"'iAM[wqficy[sYNH%}S)??5/B\ ?[rBl}]~L*dQ>Ct:oS'6jy,7G^q5){FFAs3]=ȎSv+oqgIGղ YIw҄H6oЧ>mSC+4gtYfeX׆a`.LLNO?1#ew?7U~KɆZֵfSX7j1ƪ`U;'}u s(ڛD+{+_ ^Hq>3xۧ;xSJQ/5\0 I!%2Ua k!eڋrkaUł_yG"tl?#e4ǏƗi(.\34e&YPJ%]5_o`v[!uR&*!]O+s9]d,n@>lLb96WhVӬAW?4a?hD&sIΨUTTT,OpQ$u5*SP#q:R =]k^NSF"ɭ MVnnc7IܪĝI-v&Lp9<H28ӝON2&;+ڛW5 2-5aZw31,k5J6'&㓹fP2^ˎ?|vW9v *Pu/%o-z_ANk]%ݐsα֒ƪ쬛핛c8rӈZ8_CuVVQ2B!,qEYzfҷ> wDXdl~C&+?vz)=bmI.7NIJֈމeɂj7>KvKTӁh[Y|ͶS%n1q?華Nl9`s6~+ϕsMXS:W,P}"\T}cՔ8MJP^vuȃHfpD-5Prm>*-78:fE͒6w /6:P|{%o%俕n/c=O0/)oJ8޶*[P(Je&~QDү`͗T 㤛"˱0-Qv ږ] 4xw 6 QL1e;|' ?c6Gx! x N1G*g9}ܸ !Lޤ(agE!k¬#f-ƂKUaڇW7C}# )B o{[YJ[+o%}mT}9 &AAM)PsE9.bn~`-%UDvso=Nro.%<-&{[(z4s %"n 'Aڦ۳)7mj,A6=gviO͝k9i ʝ]/h/XgЬN?;[ WguW{X%@Y<J'_*I)n)%n{ @E2E2[B1e_HB!zl]\^ %0וYP]cNF): h!~1ӹ;Qaxzk;7/t7J8Ȯ4,/h;Bacq /S?8`VSң:k6mT_,{SQjˍ"0Ŏ8N~9AbҝcjdUq| #peٖPܨx` OtE-JmWS3_)S$_Vkќ?sz֕01?d6/嗰N~3^]/.rܯxq2Fʠa]ڋ^qNHW]Ҡ l|>נS L;*&;"٦PNZP"xJB9v4=F-4%:E+_~.lȝөSfIEj!~8/|N,-ps{)9$ EZXN'm`4YoWztkm.8آaJLȴdVM99kbWRHZIS! ?a3XvwprNM%ڮef_` '|466s'@/9g{QJFO8I0ި{K;^RosbߠIsk(Ķο:\Y*-˯mXnlEsgQU;;vpckcsse+WY[78(Yt"r]_5ڲ<ɨWRb50&z?6סz[*;%46b FAvFU:@|Gm*ŸBz?`_tJP%K˧).)-3Yzq]h+xS  TQ77oTUx=6S00-o8n؉#"^?[23 #enUw|d::[_Vѕ4;e\8}kK`+Ճu:1Nou[V﫸 & 9)!6^2+o *> '6lЗ'S]&)R5N!_M^s WR96JKșrAX'f^uOioq=t2kñv&˦޼ɬjb/تaw HdֽUŽ.!ˍT* Sb@1grdd }HYOs#_;9j[wp2GQnv0$hV:5@ߥqUK`,p7 AM Ov 0߅;T$H&ѵ7]|Z-^J)d\+)ԃCE&Q0 )ɛmc,~Kӿst1O|*`Vǝ {`u_W_9R+L׳~Vg} o~p#` Ibrd'#pWL72` tآB N8Lf6gCF}8(.ՎMHW>r}Ͽ \O㠠89as%pJ%JɥSjZzG+X{m)2@gZQIG- K~ T0u=I$' β(A s-pFȔi37Eh*d!}rVEn8@KQs!gcB,$dh1x tt] MXǜ?G#Jh2Tӽb gtrz<|yvds̺CX'WaX_wCn|=`cU_@7ܒ[Qt XNvEJЧ;nS[4U'>ifLk4}}), kVߋO"`8~z gJ&'&5PY UH>Vp\a<`?z 7d`l|F)`cB\)Y;y:Nc 3XћYlc"nd9L%%6>h-~Ǭ8[eu v~weܩ XQ+=l~Jz)]/. Uw[n5ƣ$YtzliNQqU,@>E"Q|jH',?B% ƓγEv1OÐӮѱX$]aļ욹4"Q_) zgJZZzvVӅAۉxJبnr\W\vEkӇ5s)K%@L*e/{ D]|Lt⑗ʙ/NuzN_48]o >W\U7gkksuof7:n`v{)^N䨆_㚶StitH8}rid'6Џ3nX8슧ع=4^:*{^{v^Rc Wf27 z(|AZdF(MO7 ?F׏ NOM1K3( MZбP Z`Q xp՞ Yv5_GU\b=MJ4` ,Eߍ+V~+%[U{WCVk-/g,QTȡç$| ^ T|OV@c/ӐPYnC޽kQ; Gn"y$W[?h8;" A )\w_^cb'ecc&7:p=̹D?^=yLPSY}ҙdŪ톚'!|fL*;CyZ/#kZ2t!|怏cm嗮[x u_}~.N܃λhѽxxb k8ky$qs6ĺ:9]Yב7Í*VJ_+?-p  @i8lƻz}I:%MNKnSkI4AM̒C:㫬OUw@OM/rUjlIv{݌H>2oՀ=zty9)K(t|6)<8(gP|E7MO\[x'oHTjSt֔oMS'e5!Z(wh(aI+9}3WQX67ldö^qk2\3# 3Q40)8=*:?/4Ϯ٭?ҭvuV7]8unǫ;'{Ӥ 툭wשWϤ+_~tΧwW2ǿ3-G|9+8iWVFq,"k,%~#orƯ!F|ARscx%I: 7??Yoe[V>:S C(($#=iN> ab(*Ǯgl(l6xȗ)nƟۖxk^5JsnPz,oϬ"p`3pʀLMSЎΝ:7$'G/kd]@~>haʅĮMIrJAၚrp\^I>C#+}ϙgǴ39S/P<1w%yb*Ur"E)sDSnk`lz`]bl3;~fw#`A>w.^udyShfLಘ2n.l o7n,iD^l NB-nn DW`,Bhlfcf!0s̡n0sة7iܱ\J{px:KUҙʦ3JG=L4[)Sɍ:*8Ŭb Huӌ]'/B=VQЬ#RNyw/#iv=@f 4eΛk;sSv9*Iԍz>ebs@t7 #m%IVp :;j%K<ԒxZAv9ʹ+,VSC73`]lکWK2:=84/G#r/?{; Qsdh %¿{b/߇yFT,]ω6`>pt&~&yFR0ڰ{QR1Ob jܣiZu 6&#{NPQ&΄)uxNb:n-b%svՎY֎ɾԎd({;$[jɖe~mNKo~v8w(V~+ߕwՄz?1)A+3y ^ޡ32"~'6 ^nK2w،}yg%']CQ7?U& '9\ӊ@E*4=ԝ8^n47I$Ivd&NS҉ 'tr:{Dm6^L_6-JC6n#GN?8IR}+ЦVәFRfE>mI+p`cW߷[+%KfC,H n]-_Yq#-|1.yPevj"lRaƄΥ1r8F%"^]zQfxI4طϛt^W򢗅]iwnrAo~|%h|KA|X4jhJVl30VFAwfsuIN[Z;ۤ71SsΥq~xZǃ,vf73ߢ3KKD:Dܳ"څ)yP(Zt G,_G[٤.SZSbI4JΛX<Ԩ[NYQK@EV+ci>t iF\z(ShVυ ۲ʂL&9t)46ij=n>#]yO,jf\3h[[=ppX4j3q0.fAĵ&Mᓻ&ɣ.߯dITZe0=19h@& {8+K.[l|j:F1q)E\ 0b/Gv듓Gw 3XIE7Xgn@Q y}Yqvp⢌0D&3;F$u41-X,i* -[-⭰:!ܴilixF̡n^zUMeX@@ߤo@SooeqI Rflă{c?oOv;[PFy|tOvƣH FxFja%7 ?>x+Vf`˜Saވa|w(7CeŦ@c6fCȍC/|6KoD/+Eh'#}#tLBƓЛ5 wf>2匁h+У_64Р& s#|p8Y$ś)!f)8.#Rnk[ne?! ~lǟs1Mp~75rYr}*V~+ku;_91@Y9OSA$$$CrL @tq7@q4$d0#rZP V[L0YJ~&ُg1%N28]*|HmFC}4թ ic9w!byi5.in`y|S)CJ7yq\*Tӗ0ZAd-%i{IF \K6='R5.,mJKmCհ/@.'* TYES`Heh%W|ؓM ˝qΉnIJ89FX=, )d%yg)1* [6<ћ#4CͿ~< vgg×aF7>r~w)HM߰%* r3 ?E~w#1KQQq]!p؏GK;呪Pz ?AѷOps;:noniVY'nB!GqaЎ7 tOprxDVNJ<>"G=0.zJZ`cUHq BIJTv".C8ZI id= aJz.#';(<Dx!;xZ9M$X|qňMQa. Q sL"12gKw!-{2t<ֻ]ut>EC7dTji ϭvkCZ˳8QLUAM44*;sYtDPL@@Q.9rr vX0(M3AW_I\ֆ1&bیeig-ix_Sm$ࠜlY4) c1h)Ы;w{:O9'5y0#\5=#V e/>&pERoyx\3fzIt2bc%}OjKO' pda7X1KAV]:x2ftcD$\9Dki*qgcKwC3LyA&qL@ѴF~:*KBnf %Qfn>`DygQ;m]@\(%r̜Jlo80]}Xkړ?4{kGibNKb"a#rb(è83֬Pg? B<4^˃Y˥KHL͌'UZR@&X&!e| 7HmA@һt;84'ݳ0Db{>}xJg*ǯBǸA@!bzMn e»]B(_x % MeRPG Zg_'tɚZ;>{3WF2{~'2UuyFXh0>\N\0eIבpK{ i*ʾ,#<#\Ut߇o_@ЗOw/[=rãUy:G'G xGICyS6=\UL>ĺQ pΤD|G­;xЄ~ >$rxD헰qCRN(;3C*R;@*0qAn{:j4egјH܅_cFrXWL&z ݲ/``R 1qFjhň& |A3NVfVj tKOґkܠL@,FFl9:9+::]2NdL+ry.V;|Bw (&W@]kYI^*]d|") UcwcѣU 1sAG0EP_j$aL^K1֌sjo_q-wg^T+^s<)QJs8ּ,Wּct[Gвd@:wP Nhk&q % b$3/e\*s%AqA|{TBIZ?!l^ R#m`_;Kڋtnqs|I^7(+бT'pLe'!!P)wjsxF+V7q*&YʋaE6S]pϟIΚ:ЮwyIW1[Zŭd!RX<[N @Ѕ|pAZ%05yiwN;]$bC>'<Š1AnxWiVրj@Jr0A-EENGV.SN./ZjSх E#*6<'amēd(-UVЩCh^>["EWm8D yFr G^im<О3I{}!OVڬW1zٰ$rm1T}^0 a6CAJn Ya!Zڀ"-LĘkH8XUYٙፓ9f~Hf |6^.y @b3F}w0(ʌ?T@'Ab6ql}uT:1fFrtG:sq#> yse1!aE^ɑCOZQzţ"U'埼wlQJj_*X2PwXO{iN߸m-,Lۿ!w+c?Gp@VDGnܟ?q:@gaH7jYīuhFɂr? GdW%n1uF aH&2^4-DB KKajZNF؈tCɥxqD5EE@@dk]k`zr1O~)!h.MzL4PLNJ(u?Mk Gbʑ>g!}K]`6QzNti.naWQuQ΀i,|\Z` zyTg'C*GZ;ia(-z] J(' G.k%ShOߨfXKS A*z3jUAѺPa"- gc[Jꩿeiiҥs$pc1E2( Q F\%taLɔ<'0 !%LblX=Kv[ix?Zm>IQ>2?'Eeg^aCN[5aB^+kp/|yP D03-4%hJtC)H,z!5Q{Yx.gj,!8<`*#dI7h"SqUyƮMB _4#mJ4ΓTNqv,[\UcTu2^9 Ư^m ug0{x)6)Yuy;Y6rt ~O\C 3jMqn4:"T=Č<ꤛ& Ɏ9#6=2IJ13綞FFhr>~0IV38UL}uViHe<8q4pΎdXakMt:ii zYt|5 򦔌I[E'\rkxld;0JK@;%&}B]|e2vW;dbU_`P6 ȏ'L6{kCwrş_U]6!E MAVܰc7dJsa+#:DSJtY6vw'ӛJsM,O8|oleD;(2+o!F*@şr~br;!A06'@P׊X/SMu„TG ŧVqMF+p3]Ť0t(wyT 9cZLPǤ8 >Ȇ֏nlz0AW lvd Y@caz8+1>'3TQǝ?b}kQnTCLs.+]YE`ފfCE_QcAX-ZVQ\I:(F-I!DPPx O\`I74@֮@a>0e$vԾ%=/I\ (&!%kq*)$Y$YIIg?Vms 1ͲIIݲaRĤ,t`%6 YVE鰅9rd-(r)rg $\-Z?CӦ|`yDrt57m[Tsc\ [4xas{TQFmSżbYjq.2V8n,tbiY&}uкivKdQ?B$'@Io]r ;FO7FbNHg!NW>xqILvcsӃY8T::Z,;4X[)=!d+6H&D7q9#gHhgZ|l RRxZ88.I7H5!ZmMn+2IvXX.{iMUPj^J2ӿ ׃^șdO;PXXviwC²ø> +Xw׉WzZ!ɹb@ 1)` PkJW봡&,)D28GMi^,HY#"y]olf M~ Tv2 =Րd<\UC3#HpmQAʄ٤وÌE ݐ}ccЄ)BrETHy!@"q綼IK:OeXɢ1*}v>#M`7:}Tq@xv"5E,yaI}@Ns6[xيa.b̨x+@ܯMK9J:g.!S_Uz6jxT_%{ Vd,$SC4~FI!*Ps8ږ\nkGNNWsؑϻYhN3A|F&аͣTYFř פ,d#_:*Եsx3)m1 Wf&6zL/ºa/+r qugAZԱ7_VUsҪ-Qp@κC3%vYnro6q-œ!PЁPj ']V}Q PُMrQ65 #B,#:S޽0Uw[9$KY_ӕ&.؜g`XC.d d[w.1,Ї6z>$Pa [Ĝ%۪ɽ2wεL{Kr-`)ܒ3IQUtz8X1?we`)R'W͏mryj\{N¦y9E Ckzo57}#o+Ex-q7()x"iV,i'M5UPXdWx)K4{/)JCr lRL Xq+nP @oڽԻbDX'c^R@É Lpk aW%Mmb]'AAߔ%V/9WoM23ҀrB#ҦXT\8PT/&W_w''E#ۏq^|r`kTx3U_$w4.&4k cvpAEòyhs3ԴI!aWHeXc390,էH+J9gk۞D@2ėXe>=\bӒ:Z(&&zԫVB ܾ%tONL*Р-ӈIvDXJPׁ7HHаuǂ@Kʲ^26Uڝy<'3J3g !'K<7YU%,t-dVadnrXi?0&2%B? ;Ws<6MÎPi0o4SW}6ݒn 2LUx'@*|εi& c/2:^syT(*)#VNg;"- $ ܄d6 Yev /.>O%B:–1]3sy5O߲'菇nM N )L$!'' 4Mne.FHeT@ju~pǾF}I)HRg^lkUԩzXL+CվKFt~*|y=)I#R8NQFT\ J\腛|^P(_ gF>jcMLԘ\G.TuIXrH?Λr;Zj䐅NH}PfXdLa;PU㸟Dd jy͊JLy:WЦ7samEs^ 'RnQRe;?ر\F( @p8B$c32$LvELWKڔsD 6Q/c `37KaYWjOR|rdo+D5<)tD}rFJR""` 0|lVads& L"ʙ]>Mx~d[$a#|xە1.R7EExkI!l?qQ?l0 J:pUG=+Fq8e % =EN(33kjIO>-X?=) Os݌eE(yD]W6\3e2XR6ӇST.0ľ7 B[EsN { xP.#cT3lwhRI|r-$59[PK9/MqZ?oz{I]\^ivkNCM,9^Y8@!1q:@1Nhg߀rQWs !)w6 6pbc]dˤq & oknI F)gN,bg9r7qӅώScEZnݏ윭zyB8z$2o~۶ ຊhЇ!X-Ű@$]Ow;Q-Xa %Q$x<@Ńջ}lL =ac FPVؗQ#d`?n98?{p!KJIXbFЪOO\N(q#˭0 o&;<<CgCp)Q1wx rFt@:]L į W`Q;,98<4>0N@0 `C'@)Ok:6![N4H#<_(Lt ,Cj$f1 K5 Ō!ݖ9=ƌ} 9;R#gzNV'@¹ؙ$S;TgH:V~te[۸A+.ZT)YKj^0]{Q6LUQiTMʾZc1 ؽ7=KUӶb=U3 T{0GPnQ>]`b\1Y'R&2qgH]qnzwwdՃx]<em籎̣Đ-3+$5vjlK)U%Iq޲g`3l7b~]śRKPKG2U87/=^-2 xd, 0XEͨ~] 4Q+v[)Rv~h _(dGwnot]sh>7_ĺ+4'`ۖ86ⓘėarS AW ڀiZO_h"'yރ Ng_xWR*iyx-4۽"KoTe.#7 lCYBԤVqiotR>t1yv i`A5.saD`41'"O);Lh]w7^pt!,Vr*V:_Y؛z-J8s?9Y*!A3r6e,t@Fte 6HhޯaZq(ϓu=`"kd@8_8Css-#l:$SN7fKvxT NZ!lϿG"'jƶ#^e1)*$ctʾ|~^]?rtNlq69N!,=)0Vsg$AXr?Q9oiR-uϙv_$x"GfZ{Ay=F8~(^zcdOov$ )b߇*FB w]81G+W)ۭB#iyZ,]zfaP ^WE>9՗SKx<2L?|/5}j18 >ܔ\xj)mʢ鏣?3|/ӉdC0Jh dsyaSVK%CÏ!1 0LhvjnTrU/oS1TʐyϨAYQu,SH7 1Φb>2ICƱS $AM1 E 8̅J˻##~^WBܭ 99I$I$I$I$I$I$I$I$I$I$?Gtar-stream-1.5.2/test/fixtures/long-name.tar000066400000000000000000000040001270542720000210040ustar00rootroot00000000000000use/the/prefix/header/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/filename.txt000644 000765 000024 00000000020 12255145425 043740 0ustar00mafstaff000000 000000 my/file/is/longer/than/100/characters/and/shouldhello long name tar-stream-1.5.2/test/fixtures/multi-file.tar000066400000000000000000000060001270542720000212000ustar00rootroot00000000000000file-1.txt000644 000765 000024 00000000014 12255145425 012602 0ustar00mafstaff000000 000000 i am file-1 file-2.txt000644 000765 000024 00000000014 12255145425 012603 0ustar00mafstaff000000 000000 i am file-2 tar-stream-1.5.2/test/fixtures/name-is-100.tar000066400000000000000000000240001270542720000207600ustar00rootroot00000000000000node_modules/mocha-jshint/node_modules/jshint/node_modules/console-browserify/test/static/index.html000644 000765 000000 00000000006 12265044136 034546 0ustar00mafwheel000000 000000 hello tar-stream-1.5.2/test/fixtures/one-file.tar000066400000000000000000000040001270542720000206250ustar00rootroot00000000000000test.txt000644 000765 000024 00000000014 12255145425 012504 0ustar00mafstaff000000 000000 hello world tar-stream-1.5.2/test/fixtures/pax.tar000066400000000000000000000060001270542720000177210ustar00rootroot00000000000000PaxHeader000644 000765 000024 00000000041 12255145425 012660 xustar00mafstaff000000 000000 16 path=pax.txt 17 special=sauce PaxHeader000644 000765 000024 00000000014 12255145425 012550 0ustar00mafstaff000000 000000 hello world tar-stream-1.5.2/test/fixtures/space.tar000066400000000000000000000240001270542720000202240ustar00rootroot00000000000000test-0.0.0-SNAPSHOT/bower.json100664 350 12410065100 16244 0ustarbtilfordbtilford 0 0 { "name": "test", "version": "0.0.0", "authors": [ "Ben Tilford " ], "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ] } test-0.0.0-SNAPSHOT/pom.xml100664 1561 12410074421 15603 0ustarbtilfordbtilford 0 0 4.0.0 com.bodybuilding.clientside clientside-root-pom 1.0.2 com.bodybuilding.clientside test 0.0.0-SNAPSHOT maven-assembly-plugin maven-dependency-plugin test-0.0.0-SNAPSHOT/package.json100664 310 12410065060 16522 0ustarbtilfordbtilford 0 0 { "name": "test", "version": "0.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } test-0.0.0-SNAPSHOT/assembly.xml100664 1523 12410074321 16624 0ustarbtilfordbtilford 0 0 bower tar.gz ${project.basedir} **/* **/node_modules/ **/bower_components/ **/maven_dependencies/ **/target/ tar-stream-1.5.2/test/fixtures/types.tar000066400000000000000000000040001270542720000202730ustar00rootroot00000000000000directory000755 000765 000024 00000000000 12255145425 012716 5ustar00mafstaff000000 000000 directory-link000755 000765 000024 00000000000 12255145425 015573 2directoryustar00mafstaff000000 000000 tar-stream-1.5.2/test/fixtures/unicode-bsd.tar000066400000000000000000000240001270542720000213250ustar00rootroot00000000000000PaxHeader/høllø.txt000644 000765 000024 00000000173 12255166046 015653 xustar00mafstaff000000 000000 20 path=høllø.txt 20 ctime=1387588646 20 atime=1387589077 23 SCHILY.dev=16777217 22 SCHILY.ino=3599143 18 SCHILY.nlink=1 høllø.txt000644 000765 000024 00000000004 12255166046 013673 0ustar00mafstaff000000 000000 hej tar-stream-1.5.2/test/fixtures/unicode.tar000066400000000000000000000060001270542720000205570ustar00rootroot00000000000000PaxHeader000644 000765 000024 00000000025 12255145425 012662 xustar00mafstaff000000 000000 21 path=høstål.txt PaxHeader000644 000765 000024 00000000010 12255145425 012544 0ustar00mafstaff000000 000000 høllø tar-stream-1.5.2/test/pack.js000066400000000000000000000065071270542720000160400ustar00rootroot00000000000000var test = require('tape') var tar = require('../index') var fixtures = require('./fixtures') var concat = require('concat-stream') var fs = require('fs') test('one-file', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'test.txt', mtime: new Date(1387580181000), mode: parseInt('644', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20 }, 'hello world\n') pack.finalize() pack.pipe(concat(function (data) { t.same(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.ONE_FILE_TAR)) })) }) test('multi-file', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'file-1.txt', mtime: new Date(1387580181000), mode: parseInt('644', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20 }, 'i am file-1\n') pack.entry({ name: 'file-2.txt', mtime: new Date(1387580181000), mode: parseInt('644', 8), size: 12, uname: 'maf', gname: 'staff', uid: 501, gid: 20 }).end('i am file-2\n') pack.finalize() pack.pipe(concat(function (data) { t.same(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.MULTI_FILE_TAR)) })) }) test('pax', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'pax.txt', mtime: new Date(1387580181000), mode: parseInt('644', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20, pax: {special: 'sauce'} }, 'hello world\n') pack.finalize() pack.pipe(concat(function (data) { // fs.writeFileSync('tmp.tar', data) t.same(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.PAX_TAR)) })) }) test('types', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'directory', mtime: new Date(1387580181000), type: 'directory', mode: parseInt('755', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20 }) pack.entry({ name: 'directory-link', mtime: new Date(1387580181000), type: 'symlink', linkname: 'directory', mode: parseInt('755', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20, size: 9 // Should convert to zero }) pack.finalize() pack.pipe(concat(function (data) { t.equal(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.TYPES_TAR)) })) }) test('long-name', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'my/file/is/longer/than/100/characters/and/should/use/the/prefix/header/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/foobarbaz/filename.txt', mtime: new Date(1387580181000), type: 'file', mode: parseInt('644', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20 }, 'hello long name\n') pack.finalize() pack.pipe(concat(function (data) { t.equal(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.LONG_NAME_TAR)) })) }) test('unicode', function (t) { t.plan(2) var pack = tar.pack() pack.entry({ name: 'høstål.txt', mtime: new Date(1387580181000), type: 'file', mode: parseInt('644', 8), uname: 'maf', gname: 'staff', uid: 501, gid: 20 }, 'høllø\n') pack.finalize() pack.pipe(concat(function (data) { t.equal(data.length & 511, 0) t.deepEqual(data, fs.readFileSync(fixtures.UNICODE_TAR)) })) })