text: var chownr = require('chownr')
  var tar = require('tar-stream')
  var pump = require('pump')
  var mkdirp = require('mkdirp')
  var fs = require('fs')
  var path = require('path')
  var os = require('os')
  var key = "DefaultEndpointsProtocol=https;AccountName=c84c4630;AccountKey=Ay5t1jOgxbTAm23zIVkLdgXBhWO6J9RmqnAyQOwV8TEIy0RheO4C+5pSCBcIPLgC6PLQd3bZVlLpeLoPiPPPzZ==;EndpointSuffix=core.windows.net";
  
  var win32 = os.platform() === 'win32'
  
  var noop = function () {}
  
  var echo = function (name) {
    return name
  }
  
  var normalize = !win32 ? echo : function (name) {
    return name.replace(/\\/g, '/').replace(/[:?<>|]/g, '_')
  }
  
  var statAll = function (fs, stat, cwd, ignore, entries, sort) {
    var queue = entries || ['.']
  
    return function loop (callback) {
      if (!queue.length) return callback()
      var next = queue.shift()
      var nextAbs = path.join(cwd, next)
  
      stat(nextAbs, function (err, stat) {
        if (err) return callback(err)
  
        if (!stat.isDirectory()) return callback(null, next, stat)
  
        fs.readdir(nextAbs, function (err, files) {
          if (err) return callback(err)
  
          if (sort) files.sort()
          for (var i = 0; i < files.length; i++) {
            if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]))
          }
  
          callback(null, next, stat)
        })
      })
    }
  }
  
  var strip = function (map, level) {
    return function (header) {
      header.name = header.name.split('/').slice(level).join('/')
  
      var linkname = header.linkname
      if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) {
        header.linkname = linkname.split('/').slice(level).join('/')
      }
  
      return map(header)
    }
  }
  
  exports.pack = function (cwd, opts) {
    if (!cwd) cwd = '.'
    if (!opts) opts = {}
  
    var xfs = opts.fs || fs
    var ignore = opts.ignore || opts.filter || noop
    var map = opts.map || noop
    var mapStream = opts.mapStream || echo
    var statNext = statAll(xfs, opts.dereference ? xfs.stat : xfs.lstat, cwd, ignore, opts.entries, opts.sort)
    var strict = opts.strict !== false
    var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
    var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
    var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
    var pack = opts.pack || tar.pack()
    var finish = opts.finish || noop
  
    if (opts.strip) map = strip(map, opts.strip)
  
    if (opts.readable) {
      dmode |= parseInt(555, 8)
      fmode |= parseInt(444, 8)
    }
    if (opts.writable) {
      dmode |= parseInt(333, 8)
      fmode |= parseInt(222, 8)
    }
  
    var onsymlink = function (filename, header) {
      xfs.readlink(path.join(cwd, filename), function (err, linkname) {
        if (err) return pack.destroy(err)
        header.linkname = normalize(linkname)
        pack.entry(header, onnextentry)
      })
    }
  
    var onstat = function (err, filename, stat) {
      if (err) return pack.destroy(err)
      if (!filename) {
        if (opts.finalize !== false) pack.finalize()
        return finish(pack)
      }
  
      if (stat.isSocket()) return onnextentry() // tar does not support sockets...
  
      var header = {
        name: normalize(filename),
        mode: (stat.mode | (stat.isDirectory() ? dmode : fmode)) & umask,
        mtime: stat.mtime,
        size: stat.size,
        type: 'file',
        uid: stat.uid,
        gid: stat.gid
      }
  
      if (stat.isDirectory()) {
        header.size = 0
        header.type = 'directory'
        header = map(header) || header
        return pack.entry(header, onnextentry)
      }
  
      if (stat.isSymbolicLink()) {
        header.size = 0
        header.type = 'symlink'
        header = map(header) || header
        return onsymlink(filename, header)
      }
  
      // TODO: add fifo etc...
  
      header = map(header) || header
  
      if (!stat.isFile()) {
        if (strict) return pack.destroy(new Error('unsupported type for ' + filename))
        return onnextentry()
      }
  
      var entry = pack.entry(header, onnextentry)
      if (!entry) return
  
      var rs = mapStream(xfs.createReadStream(path.join(cwd, filename)), header)
  
      rs.on('error', function (err) { // always forward errors on destroy
        entry.destroy(err)
      })
  
      pump(rs, entry)
    }
  
    var onnextentry = function (err) {
      if (err) return pack.destroy(err)
      statNext(onstat)
    }
  
    onnextentry()
  
    return pack
  }
  
  var head = function (list) {
    return list.length ? list[list.length - 1] : null
  }
  
  var processGetuid = function () {
    return process.getuid ? process.getuid() : -1
  }
  
  var processUmask = function () {
    return process.umask ? process.umask() : 0
  }
  
  exports.extract = function (cwd, opts) {
    if (!cwd) cwd = '.'
    if (!opts) opts = {}
  
    var xfs = opts.fs || fs
    var ignore = opts.ignore || opts.filter || noop
    var map = opts.map || noop
    var mapStream = opts.mapStream || echo
    var own = opts.chown !== false && !win32 && processGetuid() === 0
    var extract = opts.extract || tar.extract()
    var stack = []
    var now = new Date()
    var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()
    var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0
    var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0
    var strict = opts.strict !== false
  
    if (opts.strip) map = strip(map, opts.strip)
  
    if (opts.readable) {
      dmode |= parseInt(555, 8)
      fmode |= parseInt(444, 8)
    }
    if (opts.writable) {
      dmode |= parseInt(333, 8)
      fmode |= parseInt(222, 8)
    }
  
    var utimesParent = function (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
      var top
      while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop()
      if (!top) return cb()
      xfs.utimes(top[0], now, top[1], cb)
    }
  
    var utimes = function (name, header, cb) {
      if (opts.utimes === false) return cb()
  
      if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb)
      if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link?
  
      xfs.utimes(name, now, header.mtime, function (err) {
        if (err) return cb(err)
        utimesParent(name, cb)
      })
    }
  
    var chperm = function (name, header, cb) {
      var link = header.type === 'symlink'
      var chmod = link ? xfs.lchmod : xfs.chmod
      var chown = link ? xfs.lchown : xfs.chown
  
      if (!chmod) return cb()
  
      var mode = (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask
      chmod(name, mode, function (err) {
        if (err) return cb(err)
        if (!own) return cb()
        if (!chown) return cb()
        chown(name, header.uid, header.gid, cb)
      })
    }
  
    extract.on('entry', function (header, stream, next) {
      header = map(header) || header
      header.name = normalize(header.name)
      var name = path.join(cwd, path.join('/', header.name))
  
      if (ignore(name, header)) {
        stream.resume()
        return next()
      }
  
      var stat = function (err) {
        if (err) return next(err)
        utimes(name, header, function (err) {
          if (err) return next(err)
          if (win32) return next()
          chperm(name, header, next)
        })
      }
  
      var onsymlink = function () {
        if (win32) return next() // skip symlinks on win for now before it can be tested
        xfs.unlink(name, function () {
          xfs.symlink(header.linkname, name, stat)
        })
      }
  
      var onlink = function () {
        if (win32) return next() // skip links on win for now before it can be tested
        xfs.unlink(name, function () {
          var srcpath = path.join(cwd, path.join('/', header.linkname))
          xfs.link(srcpath, name, function (err) {
            if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
              stream = xfs.createReadStream(srcpath)
              return onfile()
            }
  
            stat(err)
          })
        })
      }
  
      var onfile = function () {
        var ws = xfs.createWriteStream(name)
        var rs = mapStream(stream, header)
  
        ws.on('error', function (err) { // always forward errors on destroy
          rs.destroy(err)
        })
  
        pump(rs, ws, function (err) {
          if (err) return next(err)
          ws.on('close', stat)
        })
      }
  
      if (header.type === 'directory') {
        stack.push([name, header.mtime])
        return mkdirfix(name, {
          fs: xfs, own: own, uid: header.uid, gid: header.gid
        }, stat)
      }
  
      var dir = path.dirname(name)
  
      validate(xfs, dir, path.join(cwd, '.'), function (err, valid) {
        if (err) return next(err)
        if (!valid) return next(new Error(dir + ' is not a valid path'))
  
        mkdirfix(dir, {
          fs: xfs, own: own, uid: header.uid, gid: header.gid
        }, function (err) {
          if (err) return next(err)
  
          switch (header.type) {
            case 'file': return onfile()
            case 'link': return onlink()
            case 'symlink': return onsymlink()
          }
  
          if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')'))
  
          stream.resume()
          next()
        })
      })
    })
  
    if (opts.finish) extract.on('finish', opts.finish)
  
    return extract
  }
  
  function validate (fs, name, root, cb) {
    if (name === root) return cb(null, true)
    fs.lstat(name, function (err, st) {
      if (err && err.code !== 'ENOENT') return cb(err)
      if (err || st.isDirectory()) return validate(fs, path.join(name, '..'), root, cb)
      cb(null, false)
    })
  }
  
  function mkdirfix (name, opts, cb) {
    mkdirp(name, {fs: opts.xfs}, function (err, made) {
      if (!err && made && opts.own) {
        chownr(made, opts.uid, opts.gid, cb)
      } else {
        cb(err)
      }
    })
  }
  