code:
### 1.0.1

 * use `setImmediate` instead of `nextTick`

### 1.0.0

 * `new FdSlicer(fd, options)` must now be `fdSlicer.createFromFd(fd, options)`
 * fix behavior when `end` is 0.
 * fix `createWriteStream` when using `createFromBuffer`

### 0.4.0

 * add ability to create an FdSlicer instance from a Buffer

### 0.3.2

 * fix write stream and read stream destroy behavior

### 0.3.1

 * write stream: fix end option behavior

### 0.3.0

 * write stream emits 'progress' events
 * write stream supports 'end' option which causes the stream to emit an error
   if a maximum size is exceeded
 * improve documentation

### 0.2.1

 * Update pend dependency to latest bugfix version.

### 0.2.0

 * Add read and write functions

### 0.1.0

 * Add `autoClose` option and `ref()` and `unref()`.

### 0.0.2

 * Add API documentation
 * read stream: create buffer at last possible moment

### 0.0.1

 * Initial release


code:
# fd-slicer2

[![Build Status](https://travis-ci.com/nalhabash/node-fd-slicer.svg?branch=master)](https://travis-ci.com/nalhabash/node-fd-slicer)
[![node](https://img.shields.io/node/v/fd-slicer2.svg)](https://github.com/nalhabash/fd-slicer2)

### *This is a fork of the original fd-slicer package, without the DEP0005 deprecation error*

Safe `fs.ReadStream` and `fs.WriteStream` using the same fd.

Let's say that you want to perform a parallel upload of a file to a remote
server. To do this, we want to create multiple read streams. The first thing
you might think of is to use the `{start: 0, end: 0}` API of
`fs.createReadStream`. This gives you two choices:

 0. Use the same file descriptor for all `fs.ReadStream` objects.
 0. Open the file multiple times, resulting in a separate file descriptor
    for each read stream.

Neither of these are acceptable options. The first one is a severe bug,
because the API docs for `fs.write` state:

> Note that it is unsafe to use `fs.write` multiple times on the same file
> without waiting for the callback. For this scenario, `fs.createWriteStream`
> is strongly recommended.

`fs.createWriteStream` will solve the problem if you only create one of them
for the file descriptor, but it will exhibit this unsafety if you create
multiple write streams per file descriptor.

The second option suffers from a race condition. For each additional time the
file is opened after the first, it is possible that the file is modified. So
in our parallel uploading example, we might upload a corrupt file that never
existed on the client's computer.

This module solves this problem by providing `createReadStream` and
`createWriteStream` that operate on a shared file descriptor and provides
the convenient stream API while still allowing slicing and dicing.

This module also gives you some additional power that the builtin
`fs.createWriteStream` do not give you. These features are:

 * Emitting a 'progress' event on write.
 * Ability to set a maximum size and emit an error if this size is exceeded.
 * Ability to create an `FdSlicer` instance from a `Buffer`. This enables you
   to provide API for handling files as well as buffers using the same API.

## Usage

```js
var fdSlicer = require('fd-slicer');
var fs = require('fs');

fs.open("file.txt", 'r', function(err, fd) {
  if (err) throw err;
  var slicer = fdSlicer.createFromFd(fd);
  var firstPart = slicer.createReadStream({start: 0, end: 100});
  var secondPart = slicer.createReadStream({start: 100});
  var firstOut = fs.createWriteStream("first.txt");
  var secondOut = fs.createWriteStream("second.txt");
  firstPart.pipe(firstOut);
  secondPart.pipe(secondOut);
});
```

You can also create from a buffer:

```js
var fdSlicer = require('fd-slicer');
var slicer = FdSlicer.createFromBuffer(someBuffer);
var firstPart = slicer.createReadStream({start: 0, end: 100});
var secondPart = slicer.createReadStream({start: 100});
var firstOut = fs.createWriteStream("first.txt");
var secondOut = fs.createWriteStream("second.txt");
firstPart.pipe(firstOut);
secondPart.pipe(secondOut);
```

## API Documentation

### fdSlicer.createFromFd(fd, [options])

```js
var fdSlicer = require('fd-slicer');
fs.open("file.txt", 'r', function(err, fd) {
  if (err) throw err;
  var slicer = fdSlicer.createFromFd(fd);
  // ...
});
```

Make sure `fd` is a properly initialized file descriptor. If you want to
use `createReadStream` make sure you open it for reading and if you want
to use `createWriteStream` make sure you open it for writing.

`options` is an optional object which can contain:

 * `autoClose` - if set to `true`, the file descriptor will be automatically
   closed once the last stream that references it is closed. Defaults to
   `false`. `ref()` and `unref()` can be used to increase or decrease the
   reference count, respectively.

### fdSlicer.createFromBuffer(buffer, [options])

```js
var fdSlicer = require('fd-slicer');
var slicer = fdSlicer.createFromBuffer(someBuffer);
// ...
```

`options` is an optional object which can contain:

 * `maxChunkSize` - A `Number` of bytes. see `createReadStream()`.
   If falsey, defaults to unlimited.

#### Properties

##### fd

The file descriptor passed in. `undefined` if created from a buffer.

#### Methods

##### createReadStream(options)

Available `options`:

 * `start` - Number. The offset into the file to start reading from. Defaults
   to 0.
 * `end` - Number. Exclusive upper bound offset into the file to stop reading
   from.
 * `highWaterMark` - Number. The maximum number of bytes to store in the
   internal buffer before ceasing to read from the underlying resource.
   Defaults to 16 KB.
 * `encoding` - String. If specified, then buffers will be decoded to strings
   using the specified encoding. Defaults to `null`.

The ReadableStream that this returns has these additional methods:

 * `destroy(err)` - stop streaming. `err` is optional and is the error that
   will be emitted in order to cause the streaming to stop. Defaults to
   `new Error("stream destroyed")`.

If `maxChunkSize` was specified (see `createFromBuffer()`), the read stream
will provide chunks of at most that size. Normally, the read stream provides
the entire range requested in a single chunk, but this can cause performance
problems in some circumstances.
See [thejoshwolfe/yauzl#87](https://github.com/thejoshwolfe/yauzl/issues/87).

##### createWriteStream(options)

Available `options`:

 * `start` - Number. The offset into the file to start writing to. Defaults to
   0.
 * `end` - Number. Exclusive upper bound offset into the file. If this offset
   is reached, the write stream will emit an 'error' event and stop functioning.
   In this situation, `err.code === 'ETOOBIG'`. Defaults to `Infinity`.
 * `highWaterMark` - Number. Buffer level when `write()` starts returning
   false. Defaults to 16KB.
 * `decodeStrings` - Boolean. Whether or not to decode strings into Buffers
   before passing them to` _write()`. Defaults to `true`.

The WritableStream that this returns has these additional methods:

 * `destroy()` - stop streaming

And these additional properties:

 * `bytesWritten` - number of bytes written to the stream

And these additional events:

 * 'progress' - emitted when `bytesWritten` changes.

##### read(buffer, offset, length, position, callback)

Equivalent to `fs.read`, but with concurrency protection.
`callback` must be defined.

##### write(buffer, offset, length, position, callback)

Equivalent to `fs.write`, but with concurrency protection.
`callback` must be defined.

##### ref()

Increase the `autoClose` reference count by 1.

##### unref()

Decrease the `autoClose` reference count by 1.

#### Events

##### 'error'

Emitted if `fs.close` returns an error when auto closing.

##### 'close'

Emitted when fd-slicer closes the file descriptor due to `autoClose`. Never
emitted if created from a buffer.

license: mit


code:
const fs = require('fs');
const { Readable, Writable, PassThrough } = require('stream');
const Pend = require('pend');
const { EventEmitter } = require('events');

class FdSlicer extends EventEmitter {
  constructor(fd, options = {}) {
    super();

    this.fd = fd;
    this.pend = new Pend();
    this.pend.max = 1;
    this.refCount = 0;
    this.autoClose = !!options.autoClose;
  }

  read(buffer, offset, length, position, callback) {
    this.pend.go(cb => {
      fs.read(this.fd, buffer, offset, length, position, (err, bytesRead, buffer) => {
        cb();
        callback(err, bytesRead, buffer);
      });
    });
  }

  write(buffer, offset, length, position, callback) {
    this.pend.go(cb => {
      fs.write(this.fd, buffer, offset, length, position, (err, written, buffer) => {
        cb();
        callback(err, written, buffer);
      });
    });
  }

  createReadStream(options) {
    return new ReadStream(this, options);
  }

  createWriteStream(options) {
    return new WriteStream(this, options);
  }

  ref() {
    this.refCount += 1;
  }

  unref() {
    this.refCount -= 1;

    if (this.refCount > 0) return;
    if (this.refCount < 0) throw new Error("invalid unref");

    if (this.autoClose) {
      fs.close(this.fd, err => {
        if (err) {
          this.emit('error', err);
        } else {
          this.emit('close');
        }
      });
    }
  }
}

class ReadStream extends Readable {
  constructor(context, options = {}) {
    super(options);

    this.context = context;
    this.context.ref();

    this.start = options.start || 0;
    this.endOffset = options.end;
    this.pos = this.start;
    this.destroyed = false;
  }

  _read(n) {
    if (this.destroyed) return;

    let toRead = Math.min(this._readableState.highWaterMark, n);
    if (this.endOffset != null) {
      toRead = Math.min(toRead, this.endOffset - this.pos);
    }
    if (toRead <= 0) {
      this.destroyed = true;
      this.push(null);
      this.context.unref();
      return;
    }
    this.context.pend.go(cb => {
      if (this.destroyed) return cb();
      const buffer = Buffer.alloc(toRead);
      fs.read(this.context.fd, buffer, 0, toRead, this.pos, (err, bytesRead) => {
        if (err) {
          this.destroy(err);
        } else if (bytesRead === 0) {
          this.destroyed = true;
          this.push(null);
          this.context.unref();
        } else {
          this.pos += bytesRead;
          this.push(buffer.slice(0, bytesRead));
        }
        cb();
      });
    });
  }

  destroy(err) {
    if (this.destroyed) return;
    err = err || new Error("stream destroyed");
    this.destroyed = true;
    this.emit('error', err);
    this.context.unref();
  }
}

class WriteStream extends Writable {
  constructor(context, options = {}) {
    super(options);

    this.context = context;
    this.context.ref();

    this.start = options.start || 0;
    this.endOffset = (options.end == null) ? Infinity : +options.end;
    this.bytesWritten = 0;
    this.pos = this.start;
    this.destroyed = false;

    this.on('finish', this.destroy.bind(this));
  }

  _write(buffer, _encoding, callback) {
    if (this.destroyed) return;

    if (this.pos + buffer.length > this.endOffset) {
      const err = new Error("maximum file length exceeded");
      err.code = 'ETOOBIG';
      this.destroy();
      callback(err);
      return;
    }
    this.context.pend.go(cb => {
      if (this.destroyed) return cb();
      fs.write(this.context.fd, buffer, 0, buffer.length, this.pos, (err, bytes) => {
        if (err) {
          this.destroy();
          cb();
          callback(err);
        } else {
          this.bytesWritten += bytes;
          this.pos += bytes;
          this.emit('progress');
          cb();
          callback();
        }
      });
    });
  }

  destroy() {
    if (this.destroyed) return;
    this.destroyed = true;
    this.context.unref();
  }
}

const { MAX_SAFE_INTEGER } = Number;

class BufferSlicer extends EventEmitter {
  constructor(buffer, options) {
    super();

    options = options || {};
    this.refCount = 0;
    this.buffer = buffer;
    this.maxChunkSize = options.maxChunkSize || MAX_SAFE_INTEGER;
  }

  read(buffer, offset, length, position, callback) {
    const end = position + length;
    const delta = end - this.buffer.length;
    const written = (delta > 0) ? delta : length;
    this.buffer.copy(buffer, offset, position, end);
    setImmediate(() => {
      callback(null, written);
    });
  }

  write(buffer, offset, length, position, callback) {
    buffer.copy(this.buffer, position, offset, offset + length);
    setImmediate(() => {
      callback(null, length, buffer);
    });
  }

  createReadStream(options = {}) {
    const readStream = new PassThrough(options);
    readStream.destroyed = false;
    readStream.start = options.start || 0;
    readStream.endOffset = options.end;
    // by the time this function returns, we'll be done.
    readStream.pos = readStream.endOffset || this.buffer.length;

    // respect the maxChunkSize option to slice up the chunk into smaller pieces.
    const entireSlice = this.buffer.slice(readStream.start, readStream.pos);
    let offset = 0;
    while (true) {
      const nextOffset = offset + this.maxChunkSize;
      if (nextOffset >= entireSlice.length) {
        // last chunk
        if (offset < entireSlice.length) {
          readStream.write(entireSlice.slice(offset, entireSlice.length));
        }
        break;
      }
      readStream.write(entireSlice.slice(offset, nextOffset));
      offset = nextOffset;
    }

    readStream.end();
    readStream.destroy = () => {
      readStream.destroyed = true;
    };
    return readStream;
  }

  createWriteStream(options) {
    const bufferSlicer = this;
    options = options || {};
    const writeStream = new Writable(options);
    writeStream.start = options.start || 0;
    writeStream.endOffset = (options.end == null) ? this.buffer.length : +options.end;
    writeStream.bytesWritten = 0;
    writeStream.pos = writeStream.start;
    writeStream.destroyed = false;
    writeStream._write = (buffer, encoding, callback) => {
      if (writeStream.destroyed) return;

      const end = writeStream.pos + buffer.length;
      if (end > writeStream.endOffset) {
        const err = new Error("maximum file length exceeded");
        err.code = 'ETOOBIG';
        writeStream.destroyed = true;
        callback(err);
        return;
      }
      buffer.copy(bufferSlicer.buffer, writeStream.pos, 0, buffer.length);

      writeStream.bytesWritten += buffer.length;
      writeStream.pos = end;
      writeStream.emit('progress');
      callback();
    };
    writeStream.destroy = () => {
      writeStream.destroyed = true;
    };
    return writeStream;
  }

  ref() {
    this.refCount += 1;
  }

  unref() {
    this.refCount -= 1;

    if (this.refCount < 0) {
      throw new Error("invalid unref");
    }
  }
}

function createFromBuffer(buffer, options) {
  return new BufferSlicer(buffer, options);
}

function createFromFd(fd, options) {
  return new FdSlicer(fd, options);
}

exports.createFromBuffer = createFromBuffer;
exports.createFromFd = createFromFd;
exports.BufferSlicer = BufferSlicer;
exports.FdSlicer = FdSlicer;


description: Fork of fd-slicer that fixes the DEP00005 deprecation error

test: mocha --check-leaks

test:coverage: nyc mocha -- --reporter dot --check-leaks test/test.js

author: Nour Al-Habash <nour35000@gmail.com>

license: MIT

test: test

type: git

keywords: createReadStream createWriteStream


code:
'use strict';
const escapeStringRegexp = require('escape-string-regexp');

const platform = process.platform;

const main = {
	tick: '✔',
	cross: '✖',
	star: '★',
	square: '▇',
	squareSmall: '◻',
	squareSmallFilled: '◼',
	play: '▶',
	circle: '◯',
	circleFilled: '◉',
	circleDotted: '◌',
	circleDouble: '◎',
	circleCircle: 'ⓞ',
	circleCross: 'ⓧ',
	circlePipe: 'Ⓘ',
	circleQuestionMark: '?⃝',
	bullet: '●',
	dot: '․',
	line: '─',
	ellipsis: '…',
	pointer: '❯',
	pointerSmall: '›',
	info: 'ℹ',
	warning: '⚠',
	hamburger: '☰',
	smiley: '㋡',
	mustache: '෴',
	heart: '♥',
	arrowUp: '↑',
	arrowDown: '↓',
	arrowLeft: '←',
	arrowRight: '→',
	radioOn: '◉',
	radioOff: '◯',
	checkboxOn: '☒',
	checkboxOff: '☐',
	checkboxCircleOn: 'ⓧ',
	checkboxCircleOff: 'Ⓘ',
	questionMarkPrefix: '?⃝',
	oneHalf: '½',
	oneThird: '⅓',
	oneQuarter: '¼',
	oneFifth: '⅕',
	oneSixth: '⅙',
	oneSeventh: '⅐',
	oneEighth: '⅛',
	oneNinth: '⅑',
	oneTenth: '⅒',
	twoThirds: '⅔',
	twoFifths: '⅖',
	threeQuarters: '¾',
	threeFifths: '⅗',
	threeEighths: '⅜',
	fourFifths: '⅘',
	fiveSixths: '⅚',
	fiveEighths: '⅝',
	sevenEighths: '⅞'
};

const win = {
	tick: '√',
	cross: '×',
	star: '*',
	square: '█',
	squareSmall: '[ ]',
	squareSmallFilled: '[█]',
	play: '►',
	circle: '( )',
	circleFilled: '(*)',
	circleDotted: '( )',
	circleDouble: '( )',
	circleCircle: '(○)',
	circleCross: '(×)',
	circlePipe: '(│)',
	circleQuestionMark: '(?)',
	bullet: '*',
	dot: '.',
	line: '─',
	ellipsis: '...',
	pointer: '>',
	pointerSmall: '»',
	info: 'i',
	warning: '‼',
	hamburger: '≡',
	smiley: '☺',
	mustache: '┌─┐',
	heart: main.heart,
	arrowUp: main.arrowUp,
	arrowDown: main.arrowDown,
	arrowLeft: main.arrowLeft,
	arrowRight: main.arrowRight,
	radioOn: '(*)',
	radioOff: '( )',
	checkboxOn: '[×]',
	checkboxOff: '[ ]',
	checkboxCircleOn: '(×)',
	checkboxCircleOff: '( )',
	questionMarkPrefix: '？',
	oneHalf: '1/2',
	oneThird: '1/3',
	oneQuarter: '1/4',
	oneFifth: '1/5',
	oneSixth: '1/6',
	oneSeventh: '1/7',
	oneEighth: '1/8',
	oneNinth: '1/9',
	oneTenth: '1/10',
	twoThirds: '2/3',
	twoFifths: '2/5',
	threeQuarters: '3/4',
	threeFifths: '3/5',
	threeEighths: '3/8',
	fourFifths: '4/5',
	fiveSixths: '5/6',
	fiveEighths: '5/8',
	sevenEighths: '7/8'
};

if (platform === 'linux') {
	// the main one doesn't look that good on Ubuntu
	main.questionMarkPrefix = '?';
}

const figures = platform === 'win32' ? win : main;

const fn = str => {
	if (figures === main) {
		return str;
	}

	Object.keys(main).forEach(key => {
		if (main[key] === figures[key]) {
			return;
		}

		str = str.replace(new RegExp(escapeStringRegexp(main[key]), 'g'), figures[key]);
	});

	return str;
};

module.exports = Object.assign(fn, figures);


figures

description: Unicode symbols with Windows CMD fallbacks

repository: sindresorhus/figures

test: xo && ava

keywords: unicode cli cmd command-line characters char symbol symbols figure figures fallback


code:
# figures [![Build Status: Linux](https://travis-ci.org/sindresorhus/figures.svg?branch=master)](https://travis-ci.org/sindresorhus/figures) [![Build status: Windows](https://ci.appveyor.com/api/projects/status/mb743hl70269be3r/branch/master?svg=true)](https://ci.appveyor.com/project/sindresorhus/figures/branch/master)

> Unicode symbols with Windows CMD fallbacks

[![](screenshot.png)](index.js)

[*and more...*](index.js)

Windows CMD only supports a [limited character set](http://en.wikipedia.org/wiki/Code_page_437).

## Install

```
$ npm install --save figures
```

## Usage

See the [source](index.js) for supported symbols.

```js
const figures = require('figures');

console.log(figures('✔ check'));
// On real OSes:  ✔ check
// On Windows:    √ check

console.log(figures.tick);
// On real OSes:  ✔
// On Windows:    √
```

## API

### figures(input)

Returns the input with replaced fallback unicode symbols on Windows.

All the below [figures](#figures) are attached to the main export as shown in the example above.

#### input

Type: `string`

String where the unicode symbols will be replaced with fallback symbols depending on the OS.

## Figures

| Name               | Real OSes | Windows |
| ------------------ | :-------: | :-----: |
| tick               |     ✔     |    √    |
| cross              |     ✖     |    ×    |
| star               |     ★     |    *    |
| square             |     ▇     |    █    |
| squareSmall        |     ◻     |   [ ]   |
| squareSmallFilled  |     ◼     |   [█]   |
| play               |     ▶     |    ►    |
| circle             |     ◯     |   ( )   |
| circleFilled       |     ◉     |   (*)   |
| circleDotted       |     ◌     |   ( )   |
| circleDouble       |     ◎     |   ( )   |
| circleCircle       |     ⓞ     |   (○)   |
| circleCross        |     ⓧ     |   (×)   |
| circlePipe         |     Ⓘ     |   (│)   |
| circleQuestionMark |     ?⃝    |   (?)   |
| bullet             |     ●     |    *    |
| dot                |     ․     |    .    |
| line               |     ─     |    ─    |
| ellipsis           |     …     |   ...   |
| pointer            |     ❯     |    >    |
| pointerSmall       |     ›     |    »    |
| info               |     ℹ     |    i    |
| warning            |     ⚠     |    ‼    |
| hamburger          |     ☰     |    ≡    |
| smiley             |     ㋡     |    ☺    |
| mustache           |     ෴     |   ┌─┐   |
| heart              |     ♥     |    ♥    |
| arrowUp            |     ↑     |    ↑    |
| arrowDown          |     ↓     |    ↓    |
| arrowLeft          |     ←     |    ←    |
| arrowRight         |     →     |    →    |
| radioOn            |     ◉     |   (*)   |
| radioOff           |     ◯     |   ( )   |
| checkboxOn         |     ☒     |   [×]   |
| checkboxOff        |     ☐     |   [ ]   |
| checkboxCircleOn   |     ⓧ     |   (×)   |
| checkboxCircleOff  |     Ⓘ     |   ( )   |
| questionMarkPrefix |     ?⃝    |    ？    |
| oneHalf            |     ½     |   1/2   |
| oneThird           |     ⅓     |   1/3   |
| oneQuarter         |     ¼     |   1/4   |
| oneFifth           |     ⅕     |   1/5   |
| oneSixth           |     ⅙     |   1/6   |
| oneSeventh         |     ⅐     |   1/7   |
| oneEighth          |     ⅛     |   1/8   |
| oneNinth           |     ⅑     |   1/9   |
| oneTenth           |     ⅒     |   1/10  |
| twoThirds          |     ⅔     |   2/3   |
| twoFifths          |     ⅖     |   2/5   |
| threeQuarters      |     ¾     |   3/4   |
| threeFifths        |     ⅗     |   3/5   |
| threeEighths       |     ⅜     |   3/8   |
| fourFifths         |     ⅘     |   4/5   |
| fiveSixths         |     ⅚     |   5/6   |
| fiveEighths        |     ⅝     |   5/8   |
| sevenEighths       |     ⅞     |   7/8   |

## Related

- [log-symbols](https://github.com/sindresorhus/log-symbols) - Colored symbols for various log levels

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


code:
# file-entry-cache
> Super simple cache for file metadata, useful for process that work o a given series of files
> and that only need to repeat the job on the changed ones since the previous run of the process — Edit

[![NPM Version](http://img.shields.io/npm/v/file-entry-cache.svg?style=flat)](https://npmjs.org/package/file-entry-cache)
[![Build Status](http://img.shields.io/travis/royriojas/file-entry-cache.svg?style=flat)](https://travis-ci.org/royriojas/file-entry-cache)

## install

```bash
npm i --save file-entry-cache
```

## Usage

The module exposes two functions `create` and `createFromFile`.

## `create(cacheName, [directory, useCheckSum])`
- **cacheName**: the name of the cache to be created
- **directory**: Optional the directory to load the cache from
- **usecheckSum**: Whether to use md5 checksum to verify if file changed. If false the default will be to use the mtime and size of the file.

## `createFromFile(pathToCache, [useCheckSum])`
- **pathToCache**: the path to the cache file (this combines the cache name and directory)
- **useCheckSum**: Whether to use md5 checksum to verify if file changed. If false the default will be to use the mtime and size of the file.

```js
// loads the cache, if one does not exists for the given
// Id a new one will be prepared to be created
var fileEntryCache = require('file-entry-cache');

var cache = fileEntryCache.create('testCache');

var files = expand('../fixtures/*.txt');

// the first time this method is called, will return all the files
var oFiles = cache.getUpdatedFiles(files);

// this will persist this to disk checking each file stats and
// updating the meta attributes `size` and `mtime`.
// custom fields could also be added to the meta object and will be persisted
// in order to retrieve them later
cache.reconcile();

// use this if you want the non visited file entries to be kept in the cache
// for more than one execution
//
// cache.reconcile( true /* noPrune */)

// on a second run
var cache2 = fileEntryCache.create('testCache');

// will return now only the files that were modified or none
// if no files were modified previous to the execution of this function
var oFiles = cache.getUpdatedFiles(files);

// if you want to prevent a file from being considered non modified
// something useful if a file failed some sort of validation
// you can then remove the entry from the cache doing
cache.removeEntry('path/to/file'); // path to file should be the same path of the file received on `getUpdatedFiles`
// that will effectively make the file to appear again as modified until the validation is passed. In that
// case you should not remove it from the cache

// if you need all the files, so you can determine what to do with the changed ones
// you can call
var oFiles = cache.normalizeEntries(files);

// oFiles will be an array of objects like the following
entry = {
  key: 'some/name/file', the path to the file
  changed: true, // if the file was changed since previous run
  meta: {
    size: 3242, // the size of the file
    mtime: 231231231, // the modification time of the file
    data: {} // some extra field stored for this file (useful to save the result of a transformation on the file
  }
}

```

## Motivation for this module

I needed a super simple and dumb **in-memory cache** with optional disk persistence (write-back cache) in order to make
a script that will beautify files with `esformatter` to execute only on the files that were changed since the last run.

In doing so the process of beautifying files was reduced from several seconds to a small fraction of a second.

This module uses [flat-cache](https://www.npmjs.com/package/flat-cache) a super simple `key/value` cache storage with
optional file persistance.

The main idea is to read the files when the task begins, apply the transforms required, and if the process succeed,
then store the new state of the files. The next time this module request for `getChangedFiles` will return only
the files that were modified. Making the process to end faster.

This module could also be used by processes that modify the files applying a transform, in that case the result of the
transform could be stored in the `meta` field, of the entries. Anything added to the meta field will be persisted.
Those processes won't need to call `getChangedFiles` they will instead call `normalizeEntries` that will return the
entries with a `changed` field that can be used to determine if the file was changed or not. If it was not changed
the transformed stored data could be used instead of actually applying the transformation, saving time in case of only
a few files changed.

In the worst case scenario all the files will be processed. In the best case scenario only a few of them will be processed.

## Important notes
- The values set on the meta attribute of the entries should be `stringify-able` ones if possible, flat-cache uses `circular-json` to try to persist circular structures, but this should be considered experimental. The best results are always obtained with non circular values
- All the changes to the cache state are done to memory first and only persisted after reconcile.

## License

MIT


code:
var path = require('path');
var crypto = require('crypto');

module.exports = {
  createFromFile: function (filePath, useChecksum) {
    var fname = path.basename(filePath);
    var dir = path.dirname(filePath);
    return this.create(fname, dir, useChecksum);
  },

  create: function (cacheId, _path, useChecksum) {
    var fs = require('fs');
    var flatCache = require('flat-cache');
    var cache = flatCache.load(cacheId, _path);
    var normalizedEntries = {};

    var removeNotFoundFiles = function removeNotFoundFiles() {
      const cachedEntries = cache.keys();
      // remove not found entries
      cachedEntries.forEach(function remover(fPath) {
        try {
          fs.statSync(fPath);
        } catch (err) {
          if (err.code === 'ENOENT') {
            cache.removeKey(fPath);
          }
        }
      });
    };

    removeNotFoundFiles();

    return {
      /**
       * the flat cache storage used to persist the metadata of the `files
       * @type {Object}
       */
      cache: cache,

      /**
       * Given a buffer, calculate md5 hash of its content.
       * @method getHash
       * @param  {Buffer} buffer   buffer to calculate hash on
       * @return {String}          content hash digest
       */
      getHash: function (buffer) {
        return crypto.createHash('md5').update(buffer).digest('hex');
      },

      /**
       * Return whether or not a file has changed since last time reconcile was called.
       * @method hasFileChanged
       * @param  {String}  file  the filepath to check
       * @return {Boolean}       wheter or not the file has changed
       */
      hasFileChanged: function (file) {
        return this.getFileDescriptor(file).changed;
      },

      /**
       * given an array of file paths it return and object with three arrays:
       *  - changedFiles: Files that changed since previous run
       *  - notChangedFiles: Files that haven't change
       *  - notFoundFiles: Files that were not found, probably deleted
       *
       * @param  {Array} files the files to analyze and compare to the previous seen files
       * @return {[type]}       [description]
       */
      analyzeFiles: function (files) {
        var me = this;
        files = files || [];

        var res = {
          changedFiles: [],
          notFoundFiles: [],
          notChangedFiles: [],
        };

        me.normalizeEntries(files).forEach(function (entry) {
          if (entry.changed) {
            res.changedFiles.push(entry.key);
            return;
          }
          if (entry.notFound) {
            res.notFoundFiles.push(entry.key);
            return;
          }
          res.notChangedFiles.push(entry.key);
        });
        return res;
      },

      getFileDescriptor: function (file) {
        var fstat;

        try {
          fstat = fs.statSync(file);
        } catch (ex) {
          this.removeEntry(file);
          return { key: file, notFound: true, err: ex };
        }

        if (useChecksum) {
          return this._getFileDescriptorUsingChecksum(file);
        }

        return this._getFileDescriptorUsingMtimeAndSize(file, fstat);
      },

      _getFileDescriptorUsingMtimeAndSize: function (file, fstat) {
        var meta = cache.getKey(file);
        var cacheExists = !!meta;

        var cSize = fstat.size;
        var cTime = fstat.mtime.getTime();

        var isDifferentDate;
        var isDifferentSize;

        if (!meta) {
          meta = { size: cSize, mtime: cTime };
        } else {
          isDifferentDate = cTime !== meta.mtime;
          isDifferentSize = cSize !== meta.size;
        }

        var nEntry = (normalizedEntries[file] = {
          key: file,
          changed: !cacheExists || isDifferentDate || isDifferentSize,
          meta: meta,
        });

        return nEntry;
      },

      _getFileDescriptorUsingChecksum: function (file) {
        var meta = cache.getKey(file);
        var cacheExists = !!meta;

        var contentBuffer;
        try {
          contentBuffer = fs.readFileSync(file);
        } catch (ex) {
          contentBuffer = '';
        }

        var isDifferent = true;
        var hash = this.getHash(contentBuffer);

        if (!meta) {
          meta = { hash: hash };
        } else {
          isDifferent = hash !== meta.hash;
        }

        var nEntry = (normalizedEntries[file] = {
          key: file,
          changed: !cacheExists || isDifferent,
          meta: meta,
        });

        return nEntry;
      },

      /**
       * Return the list o the files that changed compared
       * against the ones stored in the cache
       *
       * @method getUpdated
       * @param files {Array} the array of files to compare against the ones in the cache
       * @returns {Array}
       */
      getUpdatedFiles: function (files) {
        var me = this;
        files = files || [];

        return me
          .normalizeEntries(files)
          .filter(function (entry) {
            return entry.changed;
          })
          .map(function (entry) {
            return entry.key;
          });
      },

      /**
       * return the list of files
       * @method normalizeEntries
       * @param files
       * @returns {*}
       */
      normalizeEntries: function (files) {
        files = files || [];

        var me = this;
        var nEntries = files.map(function (file) {
          return me.getFileDescriptor(file);
        });

        //normalizeEntries = nEntries;
        return nEntries;
      },

      /**
       * Remove an entry from the file-entry-cache. Useful to force the file to still be considered
       * modified the next time the process is run
       *
       * @method removeEntry
       * @param entryName
       */
      removeEntry: function (entryName) {
        delete normalizedEntries[entryName];
        cache.removeKey(entryName);
      },

      /**
       * Delete the cache file from the disk
       * @method deleteCacheFile
       */
      deleteCacheFile: function () {
        cache.removeCacheFile();
      },

      /**
       * remove the cache from the file and clear the memory cache
       */
      destroy: function () {
        normalizedEntries = {};
        cache.destroy();
      },

      _getMetaForFileUsingCheckSum: function (cacheEntry) {
        var contentBuffer = fs.readFileSync(cacheEntry.key);
        var hash = this.getHash(contentBuffer);
        var meta = Object.assign(cacheEntry.meta, { hash: hash });
        delete meta.size;
        delete meta.mtime;
        return meta;
      },

      _getMetaForFileUsingMtimeAndSize: function (cacheEntry) {
        var stat = fs.statSync(cacheEntry.key);
        var meta = Object.assign(cacheEntry.meta, {
          size: stat.size,
          mtime: stat.mtime.getTime(),
        });
        delete meta.hash;
        return meta;
      },

      /**
       * Sync the files and persist them to the cache
       * @method reconcile
       */
      reconcile: function (noPrune) {
        removeNotFoundFiles();

        noPrune = typeof noPrune === 'undefined' ? true : noPrune;

        var entries = normalizedEntries;
        var keys = Object.keys(entries);

        if (keys.length === 0) {
          return;
        }

        var me = this;

        keys.forEach(function (entryName) {
          var cacheEntry = entries[entryName];

          try {
            var meta = useChecksum
              ? me._getMetaForFileUsingCheckSum(cacheEntry)
              : me._getMetaForFileUsingMtimeAndSize(cacheEntry);
            cache.setKey(entryName, meta);
          } catch (err) {
            // if the file does not exists we don't save it
            // other errors are just thrown
            if (err.code !== 'ENOENT') {
              throw err;
            }
          }
        });

        cache.save(noPrune);
      },
    };
  },
};


code:
# file-entry-cache - Changelog
## v6.0.1
- **Other changes**
  - Delete previous mtime when checksum is used and vice versa - [abcf0f9]( https://github.com/royriojas/file-entry-cache/commit/abcf0f9 ), [Milos Djermanovic](https://github.com/Milos Djermanovic), 19/02/2021 18:19:43

  - Adds travis jobs on ppc64le - [92e4d4a]( https://github.com/royriojas/file-entry-cache/commit/92e4d4a ), [dineshks1](https://github.com/dineshks1), 25/11/2020 04:52:11

## v6.0.0
- **Refactoring**
  - Align file-entry-cache with latest eslint - [4c6f1fb]( https://github.com/royriojas/file-entry-cache/commit/4c6f1fb ), [Roy Riojas](https://github.com/Roy Riojas), 08/11/2020 02:43:09

  - Upgrade deps - [8ab3257]( https://github.com/royriojas/file-entry-cache/commit/8ab3257 ), [Roy Riojas](https://github.com/Roy Riojas), 08/11/2020 02:41:53

  - updated packages - [3dd4231]( https://github.com/royriojas/file-entry-cache/commit/3dd4231 ), [Roy Riojas](https://github.com/Roy Riojas), 08/11/2020 02:29:37

  - Upgrade flat-cache to version 3 - [d7c60ef]( https://github.com/royriojas/file-entry-cache/commit/d7c60ef ), [Roy Riojas](https://github.com/Roy Riojas), 08/11/2020 01:18:04

## v5.0.1
- **Bug Fixes**
  - Fix missing checksum comparison from reconcile since now we use mtime and size by default. - [e858aa9]( https://github.com/royriojas/file-entry-cache/commit/e858aa9 ), [Roy Riojas](https://github.com/Roy Riojas), 04/02/2019 09:30:22

    Old mode using checkSum can still be used by passing the `useCheckSum` parameter to the `create` or `createFromFile` methods.

## v5.0.0
- **Refactoring**
  - Make checksum comparison optional - [b0f9ae0]( https://github.com/royriojas/file-entry-cache/commit/b0f9ae0 ), [Roy Riojas](https://github.com/Roy Riojas), 03/02/2019 18:17:39

    To determine if a file has changed we were using the checksum in the newer versions, but eslint was relying on the old behavior where we use the mtime and file size to determine if a file changed. That's why we decided to make the checksum check optional.

    To use it:

    ```js
    // to make the cache use the checkSum check do the following:
    var fCache = fileEntryCache.create(cacheName, dir, useCheckSum); // pass the third parameter as true
    var otherCache = fileEntryCache.createFromFile(cacheName, useCheckSum); // pass the second parameter as true
    ```

## v4.0.0
- **Build Scripts Changes**
  - use the same node versions eslint use - [563cfee]( https://github.com/royriojas/file-entry-cache/commit/563cfee ), [Roy Riojas](https://github.com/Roy Riojas), 08/01/2019 20:29:34

- **Other changes**
  - Remove object-assign dependency. - [d0f598e]( https://github.com/royriojas/file-entry-cache/commit/d0f598e ), [Corey Farrell](https://github.com/Corey Farrell), 08/01/2019 20:09:51

    node.js >=4 is required so object-assign is no longer needed, the native
    Object.assign can be used instead.

## v3.0.0
- **Build Scripts Changes**
  - Upgrade flat-cache dep to latest - [078b0df]( https://github.com/royriojas/file-entry-cache/commit/078b0df ), [Roy Riojas](https://github.com/Roy Riojas), 08/01/2019 18:54:40

  - Commit new package-lock.json file - [245fe62]( https://github.com/royriojas/file-entry-cache/commit/245fe62 ), [Roy Riojas](https://github.com/Roy Riojas), 08/01/2019 17:56:21

- **Refactoring**
  - add eslintrc file - [6dd32d8]( https://github.com/royriojas/file-entry-cache/commit/6dd32d8 ), [Roy Riojas](https://github.com/Roy Riojas), 22/08/2018 09:58:17

- **Other changes**
  - Move variable definition out of else block - [ea05441]( https://github.com/royriojas/file-entry-cache/commit/ea05441 ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 25/04/2017 11:19:00

  - Add script and cmd to test hash/checksum performance - [7f60e0a]( https://github.com/royriojas/file-entry-cache/commit/7f60e0a ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 24/04/2017 14:43:12

  - Calculate md5 hexdigest instead of Adler-32 checksum - [f9e5c69]( https://github.com/royriojas/file-entry-cache/commit/f9e5c69 ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 24/04/2017 14:43:12

  - How to reproduce - [4edc2dc]( https://github.com/royriojas/file-entry-cache/commit/4edc2dc ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 24/04/2017 13:49:32

  - Test handling of removed files - [09d9ec5]( https://github.com/royriojas/file-entry-cache/commit/09d9ec5 ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 19/04/2017 19:51:50

  - Use content checksum instead of mtime and fsize - [343b340]( https://github.com/royriojas/file-entry-cache/commit/343b340 ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 19/04/2017 19:51:47

- **Revert**
  - Revert "How to reproduce" - [4b4e54a]( https://github.com/royriojas/file-entry-cache/commit/4b4e54a ), [Zakhar Shapurau](https://github.com/Zakhar Shapurau), 25/04/2017 11:15:36

    This reverts commit 4edc2dcec01574247bfc2e0a2fe26527332b7df3.

## v2.0.0
- **Features**
  - do not persist and prune removed files from cache. Relates to [#2](https://github.com/royriojas/file-entry-cache/issues/2) - [408374d]( https://github.com/royriojas/file-entry-cache/commit/408374d ), [Roy Riojas](https://github.com/Roy Riojas), 16/08/2016 13:47:58

## v1.3.1
- **Build Scripts Changes**
  - remove older node version - [0a26ac4]( https://github.com/royriojas/file-entry-cache/commit/0a26ac4 ), [Roy Riojas](https://github.com/Roy Riojas), 01/08/2016 04:09:17

## v1.3.0
- **Features**
  - Add an option to not prune non visited keys. Closes [#2](https://github.com/royriojas/file-entry-cache/issues/2) - [b1a64db]( https://github.com/royriojas/file-entry-cache/commit/b1a64db ), [Roy Riojas](https://github.com/Roy Riojas), 01/08/2016 03:52:12

## v1.2.4
- **Enhancements**
  - Expose the flat-cache instance - [f34c557]( https://github.com/royriojas/file-entry-cache/commit/f34c557 ), [royriojas](https://github.com/royriojas), 23/09/2015 18:26:33

## v1.2.3
- **Build Scripts Changes**
  - update flat-cache dep - [cc7b9ce]( https://github.com/royriojas/file-entry-cache/commit/cc7b9ce ), [royriojas](https://github.com/royriojas), 11/09/2015 16:04:44

## v1.2.2
- **Build Scripts Changes**
  - Add changelogx section to package.json - [a3916ff]( https://github.com/royriojas/file-entry-cache/commit/a3916ff ), [royriojas](https://github.com/royriojas), 11/09/2015 16:00:26

## v1.2.1
- **Build Scripts Changes**
  - update flat-cache dep - [e49b0d4]( https://github.com/royriojas/file-entry-cache/commit/e49b0d4 ), [royriojas](https://github.com/royriojas), 11/09/2015 15:55:25

- **Other changes**
  - Update dependencies Replaced lodash.assign with smaller object-assign Fixed tests for windows - [0ad3000]( https://github.com/royriojas/file-entry-cache/commit/0ad3000 ), [Bogdan Chadkin](https://github.com/Bogdan Chadkin), 11/09/2015 15:44:18

## v1.2.0
- **Features**
  - analyzeFiles now returns also the files that were removed - [6ac2431]( https://github.com/royriojas/file-entry-cache/commit/6ac2431 ), [royriojas](https://github.com/royriojas), 04/09/2015 12:40:53

## v1.1.1
- **Features**
  - Add method to check if a file hasChanged - [3640e2b]( https://github.com/royriojas/file-entry-cache/commit/3640e2b ), [Roy Riojas](https://github.com/Roy Riojas), 30/08/2015 05:33:32

## v1.1.0
- **Features**
  - Create the cache directly from a file path - [a23de61]( https://github.com/royriojas/file-entry-cache/commit/a23de61 ), [Roy Riojas](https://github.com/Roy Riojas), 30/08/2015 04:41:33

  - Add a method to remove an entry from the filecache - [7af29fc]( https://github.com/royriojas/file-entry-cache/commit/7af29fc ), [Roy Riojas](https://github.com/Roy Riojas), 02/03/2015 23:25:32

  - cache module finished - [1f95544]( https://github.com/royriojas/file-entry-cache/commit/1f95544 ), [Roy Riojas](https://github.com/Roy Riojas), 02/03/2015 01:08:08

- **Build Scripts Changes**
  - set the version for the first release - [7472eaa]( https://github.com/royriojas/file-entry-cache/commit/7472eaa ), [Roy Riojas](https://github.com/Roy Riojas), 02/03/2015 01:29:54

- **Documentation**
  - Updated documentation - [557358f]( https://github.com/royriojas/file-entry-cache/commit/557358f ), [Roy Riojas](https://github.com/Roy Riojas), 02/03/2015 01:29:29

- **Other changes**
  - Initial commit - [3d5f42b]( https://github.com/royriojas/file-entry-cache/commit/3d5f42b ), [Roy Riojas](https://github.com/Roy Riojas), 01/03/2015 21:58:29


file-entry-cache

description: Super simple cache for file metadata, useful for process that work o a given series of files and that only need to repeat the job on the changed ones since the previous run of the process

repository: royriojas/file-entry-cache

eslint: eslint --cache --cache-location=node_modules/.cache/ 'cache.js' 'test/**/*.js' 'perf.js'

autofix: npm run eslint -- --fix

install-hooks: prepush install && changelogx install-hook && precommit install

changelog: changelogx -f markdown -o ./changelog.md

do-changelog: npm run changelog && git add ./changelog.md && git commit -m 'DOC: Generate changelog' --no-verify

pre-v: npm run test

post-v: npm run do-changelog && git push --no-verify && git push --tags --no-verify

bump-major: npm run pre-v && npm version major -m 'BLD: Release v%s' && npm run post-v

bump-minor: npm run pre-v && npm version minor -m 'BLD: Release v%s' && npm run post-v

bump-patch: npm run pre-v && npm version patch -m 'BLD: Release v%s' && npm run post-v

test: npm run eslint --silent && mocha -R spec test/specs

perf: node perf.js

watch: watch-run -i -p 'test/specs/**/*.js' istanbul cover test/runner.js html text-summary

keywords:
file cache
task cache files
file cache
key par
key value
cache

ignoreRegExp:
BLD: Release
DOC: Generate Changelog
Generated Changelog

projectName: file-entry-cache


code:
# fill-range [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/fill-range.svg?style=flat)](https://www.npmjs.com/package/fill-range) [![NPM monthly downloads](https://img.shields.io/npm/dm/fill-range.svg?style=flat)](https://npmjs.org/package/fill-range) [![NPM total downloads](https://img.shields.io/npm/dt/fill-range.svg?style=flat)](https://npmjs.org/package/fill-range) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/fill-range.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/fill-range)

> Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`

Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.

## Install

Install with [npm](https://www.npmjs.com/):

```sh
$ npm install --save fill-range
```

## Usage

Expands numbers and letters, optionally using a `step` as the last argument. _(Numbers may be defined as JavaScript numbers or strings)_.

```js
const fill = require('fill-range');
// fill(from, to[, step, options]);

console.log(fill('1', '10')); //=> ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
console.log(fill('1', '10', { toRegex: true })); //=> [1-9]|10
```

**Params**

* `from`: **{String|Number}** the number or letter to start with
* `to`: **{String|Number}** the number or letter to end with
* `step`: **{String|Number|Object|Function}** Optionally pass a [step](#optionsstep) to use.
* `options`: **{Object|Function}**: See all available [options](#options)

## Examples

By default, an array of values is returned.

**Alphabetical ranges**

```js
console.log(fill('a', 'e')); //=> ['a', 'b', 'c', 'd', 'e']
console.log(fill('A', 'E')); //=> [ 'A', 'B', 'C', 'D', 'E' ]
```

**Numerical ranges**

Numbers can be defined as actual numbers or strings.

```js
console.log(fill(1, 5));     //=> [ 1, 2, 3, 4, 5 ]
console.log(fill('1', '5')); //=> [ 1, 2, 3, 4, 5 ]
```

**Negative ranges**

Numbers can be defined as actual numbers or strings.

```js
console.log(fill('-5', '-1')); //=> [ '-5', '-4', '-3', '-2', '-1' ]
console.log(fill('-5', '5')); //=> [ '-5', '-4', '-3', '-2', '-1', '0', '1', '2', '3', '4', '5' ]
```

**Steps (increments)**

```js
// numerical ranges with increments
console.log(fill('0', '25', 4)); //=> [ '0', '4', '8', '12', '16', '20', '24' ]
console.log(fill('0', '25', 5)); //=> [ '0', '5', '10', '15', '20', '25' ]
console.log(fill('0', '25', 6)); //=> [ '0', '6', '12', '18', '24' ]

// alphabetical ranges with increments
console.log(fill('a', 'z', 4)); //=> [ 'a', 'e', 'i', 'm', 'q', 'u', 'y' ]
console.log(fill('a', 'z', 5)); //=> [ 'a', 'f', 'k', 'p', 'u', 'z' ]
console.log(fill('a', 'z', 6)); //=> [ 'a', 'g', 'm', 's', 'y' ]
```

## Options

### options.step

**Type**: `number` (formatted as a string or number)

**Default**: `undefined`

**Description**: The increment to use for the range. Can be used with letters or numbers.

**Example(s)**

```js
// numbers
console.log(fill('1', '10', 2)); //=> [ '1', '3', '5', '7', '9' ]
console.log(fill('1', '10', 3)); //=> [ '1', '4', '7', '10' ]
console.log(fill('1', '10', 4)); //=> [ '1', '5', '9' ]

// letters
console.log(fill('a', 'z', 5)); //=> [ 'a', 'f', 'k', 'p', 'u', 'z' ]
console.log(fill('a', 'z', 7)); //=> [ 'a', 'h', 'o', 'v' ]
console.log(fill('a', 'z', 9)); //=> [ 'a', 'j', 's' ]
```

### options.strictRanges

**Type**: `boolean`

**Default**: `false`

**Description**: By default, `null` is returned when an invalid range is passed. Enable this option to throw a `RangeError` on invalid ranges.

**Example(s)**

The following are all invalid:

```js
fill('1.1', '2');   // decimals not supported in ranges
fill('a', '2');     // incompatible range values
fill(1, 10, 'foo'); // invalid "step" argument
```

### options.stringify

**Type**: `boolean`

**Default**: `undefined`

**Description**: Cast all returned values to strings. By default, integers are returned as numbers.

**Example(s)**

```js
console.log(fill(1, 5));                    //=> [ 1, 2, 3, 4, 5 ]
console.log(fill(1, 5, { stringify: true })); //=> [ '1', '2', '3', '4', '5' ]
```

### options.toRegex

**Type**: `boolean`

**Default**: `undefined`

**Description**: Create a regex-compatible source string, instead of expanding values to an array.

**Example(s)**

```js
// alphabetical range
console.log(fill('a', 'e', { toRegex: true })); //=> '[a-e]'
// alphabetical with step
console.log(fill('a', 'z', 3, { toRegex: true })); //=> 'a|d|g|j|m|p|s|v|y'
// numerical range
console.log(fill('1', '100', { toRegex: true })); //=> '[1-9]|[1-9][0-9]|100'
// numerical range with zero padding
console.log(fill('000001', '100000', { toRegex: true }));
//=> '0{5}[1-9]|0{4}[1-9][0-9]|0{3}[1-9][0-9]{2}|0{2}[1-9][0-9]{3}|0[1-9][0-9]{4}|100000'
```

### options.transform

**Type**: `function`

**Default**: `undefined`

**Description**: Customize each value in the returned array (or [string](#optionstoRegex)). _(you can also pass this function as the last argument to `fill()`)_.

**Example(s)**

```js
// add zero padding
console.log(fill(1, 5, value => String(value).padStart(4, '0')));
//=> ['0001', '0002', '0003', '0004', '0005']
```

## About

Contributing

Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).

Running Tests

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

```sh
$ npm install && npm test
```

Building docs

_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_

To generate the readme, run the following command:

```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```

### Contributors

| **Commits** | **Contributor** |
| --- | --- |
| 116 | [jonschlinkert](https://github.com/jonschlinkert) |
| 4   | [paulmillr](https://github.com/paulmillr) |
| 2   | [realityking](https://github.com/realityking) |
| 2   | [bluelovers](https://github.com/bluelovers) |
| 1   | [edorivai](https://github.com/edorivai) |
| 1   | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) |

### Author

**Jon Schlinkert**

* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)

Please consider supporting me on Patreon, or [start your own Patreon page](https://patreon.com/invite/bxpbvm)!

### License

Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).

***

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 08, 2019._


code:
/*!
 * fill-range <https://github.com/jonschlinkert/fill-range>
 *
 * Copyright (c) 2014-present, Jon Schlinkert.
 * Licensed under the MIT License.
 */

'use strict';

const util = require('util');
const toRegexRange = require('to-regex-range');

const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);

const transform = toNumber => {
  return value => toNumber === true ? Number(value) : String(value);
};

const isValidValue = value => {
  return typeof value === 'number' || (typeof value === 'string' && value !== '');
};

const isNumber = num => Number.isInteger(+num);

const zeros = input => {
  let value = `${input}`;
  let index = -1;
  if (value[0] === '-') value = value.slice(1);
  if (value === '0') return false;
  while (value[++index] === '0');
  return index > 0;
};

const stringify = (start, end, options) => {
  if (typeof start === 'string' || typeof end === 'string') {
    return true;
  }
  return options.stringify === true;
};

const pad = (input, maxLength, toNumber) => {
  if (maxLength > 0) {
    let dash = input[0] === '-' ? '-' : '';
    if (dash) input = input.slice(1);
    input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0'));
  }
  if (toNumber === false) {
    return String(input);
  }
  return input;
};

const toMaxLen = (input, maxLength) => {
  let negative = input[0] === '-' ? '-' : '';
  if (negative) {
    input = input.slice(1);
    maxLength--;
  }
  while (input.length < maxLength) input = '0' + input;
  return negative ? ('-' + input) : input;
};

const toSequence = (parts, options, maxLen) => {
  parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
  parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);

  let prefix = options.capture ? '' : '?:';
  let positives = '';
  let negatives = '';
  let result;

  if (parts.positives.length) {
    positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|');
  }

  if (parts.negatives.length) {
    negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`;
  }

  if (positives && negatives) {
    result = `${positives}|${negatives}`;
  } else {
    result = positives || negatives;
  }

  if (options.wrap) {
    return `(${prefix}${result})`;
  }

  return result;
};

const toRange = (a, b, isNumbers, options) => {
  if (isNumbers) {
    return toRegexRange(a, b, { wrap: false, ...options });
  }

  let start = String.fromCharCode(a);
  if (a === b) return start;

  let stop = String.fromCharCode(b);
  return `[${start}-${stop}]`;
};

const toRegex = (start, end, options) => {
  if (Array.isArray(start)) {
    let wrap = options.wrap === true;
    let prefix = options.capture ? '' : '?:';
    return wrap ? `(${prefix}${start.join('|')})` : start.join('|');
  }
  return toRegexRange(start, end, options);
};

const rangeError = (...args) => {
  return new RangeError('Invalid range arguments: ' + util.inspect(...args));
};

const invalidRange = (start, end, options) => {
  if (options.strictRanges === true) throw rangeError([start, end]);
  return [];
};

const invalidStep = (step, options) => {
  if (options.strictRanges === true) {
    throw new TypeError(`Expected step "${step}" to be a number`);
  }
  return [];
};

const fillNumbers = (start, end, step = 1, options = {}) => {
  let a = Number(start);
  let b = Number(end);

  if (!Number.isInteger(a) || !Number.isInteger(b)) {
    if (options.strictRanges === true) throw rangeError([start, end]);
    return [];
  }

  // fix negative zero
  if (a === 0) a = 0;
  if (b === 0) b = 0;

  let descending = a > b;
  let startString = String(start);
  let endString = String(end);
  let stepString = String(step);
  step = Math.max(Math.abs(step), 1);

  let padded = zeros(startString) || zeros(endString) || zeros(stepString);
  let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0;
  let toNumber = padded === false && stringify(start, end, options) === false;
  let format = options.transform || transform(toNumber);

  if (options.toRegex && step === 1) {
    return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options);
  }

  let parts = { negatives: [], positives: [] };
  let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num));
  let range = [];
  let index = 0;

  while (descending ? a >= b : a <= b) {
    if (options.toRegex === true && step > 1) {
      push(a);
    } else {
      range.push(pad(format(a, index), maxLen, toNumber));
    }
    a = descending ? a - step : a + step;
    index++;
  }

  if (options.toRegex === true) {
    return step > 1
      ? toSequence(parts, options, maxLen)
      : toRegex(range, null, { wrap: false, ...options });
  }

  return range;
};

const fillLetters = (start, end, step = 1, options = {}) => {
  if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) {
    return invalidRange(start, end, options);
  }

  let format = options.transform || (val => String.fromCharCode(val));
  let a = `${start}`.charCodeAt(0);
  let b = `${end}`.charCodeAt(0);

  let descending = a > b;
  let min = Math.min(a, b);
  let max = Math.max(a, b);

  if (options.toRegex && step === 1) {
    return toRange(min, max, false, options);
  }

  let range = [];
  let index = 0;

  while (descending ? a >= b : a <= b) {
    range.push(format(a, index));
    a = descending ? a - step : a + step;
    index++;
  }

  if (options.toRegex === true) {
    return toRegex(range, null, { wrap: false, options });
  }

  return range;
};

const fill = (start, end, step, options = {}) => {
  if (end == null && isValidValue(start)) {
    return [start];
  }

  if (!isValidValue(start) || !isValidValue(end)) {
    return invalidRange(start, end, options);
  }

  if (typeof step === 'function') {
    return fill(start, end, 1, { transform: step });
  }

  if (isObject(step)) {
    return fill(start, end, 0, step);
  }

  let opts = { ...options };
  if (opts.capture === true) opts.wrap = true;
  step = step || opts.step || 1;

  if (!isNumber(step)) {
    if (step != null && !isObject(step)) return invalidStep(step, opts);
    return fill(start, end, 1, step);
  }

  if (isNumber(start) && isNumber(end)) {
    return fillNumbers(start, end, step, opts);
  }

  return fillLetters(start, end, Math.max(Math.abs(step), 1), opts);
};

module.exports = fill;


fill-range

description: Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`

repository: jonschlinkert/fill-range

lint: eslint --cache --cache-location node_modules/.cache/.eslintcache --report-unused-disable-directives --ignore-path .gitignore .

mocha: mocha --reporter dot

test: npm run lint && npm run mocha

test:ci: npm run test:cover

test:cover: nyc npm run mocha

keywords: alpha alphabetical array bash brace expand expansion fill glob match matches matching number numerical range ranges regex sh

layout: default


code:
1.2.0 / 2022-03-22
==================

  * Remove set content headers that break response
  * deps: on-finished@2.4.1
  * deps: statuses@2.0.1
    - Rename `425 Unordered Collection` to standard `425 Too Early`

1.1.2 / 2019-05-09
==================

  * Set stricter `Content-Security-Policy` header
  * deps: parseurl@~1.3.3
  * deps: statuses@~1.5.0

1.1.1 / 2018-03-06
==================

  * Fix 404 output for bad / missing pathnames
  * deps: encodeurl@~1.0.2
    - Fix encoding `%` as last character
  * deps: statuses@~1.4.0

1.1.0 / 2017-09-24
==================

  * Use `res.headersSent` when available

1.0.6 / 2017-09-22
==================

  * deps: debug@2.6.9

1.0.5 / 2017-09-15
==================

  * deps: parseurl@~1.3.2
    - perf: reduce overhead for full URLs
    - perf: unroll the "fast-path" `RegExp`

1.0.4 / 2017-08-03
==================

  * deps: debug@2.6.8

1.0.3 / 2017-05-16
==================

  * deps: debug@2.6.7
    - deps: ms@2.0.0

1.0.2 / 2017-04-22
==================

  * deps: debug@2.6.4
    - deps: ms@0.7.3

1.0.1 / 2017-03-21
==================

  * Fix missing `</html>` in HTML document
  * deps: debug@2.6.3
    - Fix: `DEBUG_MAX_ARRAY_LENGTH`

1.0.0 / 2017-02-15
==================

  * Fix exception when `err` cannot be converted to a string
  * Fully URL-encode the pathname in the 404 message
  * Only include the pathname in the 404 message
  * Send complete HTML document
  * Set `Content-Security-Policy: default-src 'self'` header
  * deps: debug@2.6.1
    - Allow colors in workers
    - Deprecated `DEBUG_FD` environment variable set to `3` or higher
    - Fix error when running under React Native
    - Use same color for same namespace
    - deps: ms@0.7.2

0.5.1 / 2016-11-12
==================

  * Fix exception when `err.headers` is not an object
  * deps: statuses@~1.3.1
  * perf: hoist regular expressions
  * perf: remove duplicate validation path

0.5.0 / 2016-06-15
==================

  * Change invalid or non-numeric status code to 500
  * Overwrite status message to match set status code
  * Prefer `err.statusCode` if `err.status` is invalid
  * Set response headers from `err.headers` object
  * Use `statuses` instead of `http` module for status messages
    - Includes all defined status messages

0.4.1 / 2015-12-02
==================

  * deps: escape-html@~1.0.3
    - perf: enable strict mode
    - perf: optimize string replacement
    - perf: use faster string coercion

0.4.0 / 2015-06-14
==================

  * Fix a false-positive when unpiping in Node.js 0.8
  * Support `statusCode` property on `Error` objects
  * Use `unpipe` module for unpiping requests
  * deps: escape-html@1.0.2
  * deps: on-finished@~2.3.0
    - Add defined behavior for HTTP `CONNECT` requests
    - Add defined behavior for HTTP `Upgrade` requests
    - deps: ee-first@1.1.1
  * perf: enable strict mode
  * perf: remove argument reassignment

0.3.6 / 2015-05-11
==================

  * deps: debug@~2.2.0
    - deps: ms@0.7.1

0.3.5 / 2015-04-22
==================

  * deps: on-finished@~2.2.1
    - Fix `isFinished(req)` when data buffered

0.3.4 / 2015-03-15
==================

  * deps: debug@~2.1.3
    - Fix high intensity foreground color for bold
    - deps: ms@0.7.0

0.3.3 / 2015-01-01
==================

  * deps: debug@~2.1.1
  * deps: on-finished@~2.2.0

0.3.2 / 2014-10-22
==================

  * deps: on-finished@~2.1.1
    - Fix handling of pipelined requests

0.3.1 / 2014-10-16
==================

  * deps: debug@~2.1.0
    - Implement `DEBUG_FD` env variable support

0.3.0 / 2014-09-17
==================

  * Terminate in progress response only on error
  * Use `on-finished` to determine request status

0.2.0 / 2014-09-03
==================

  * Set `X-Content-Type-Options: nosniff` header
  * deps: debug@~2.0.0

0.1.0 / 2014-07-16
==================

  * Respond after request fully read
    - prevents hung responses and socket hang ups
  * deps: debug@1.0.4

0.0.3 / 2014-07-11
==================

  * deps: debug@1.0.3
    - Add support for multiple wildcards in namespaces

0.0.2 / 2014-06-19
==================

  * Handle invalid status codes

0.0.1 / 2014-06-05
==================

  * deps: debug@1.0.2

0.0.0 / 2014-06-05
==================

  * Extracted from connect/express


code:
# finalhandler

[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-image]][node-url]
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
[![Test Coverage][coveralls-image]][coveralls-url]

Node.js function to invoke as the final step to respond to HTTP request.

## Installation

This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/). Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):

```sh
$ npm install finalhandler
```

## API

```js
var finalhandler = require('finalhandler')
```

### finalhandler(req, res, [options])

Returns function to be invoked as the final step for the given `req` and `res`.
This function is to be invoked as `fn(err)`. If `err` is falsy, the handler will
write out a 404 response to the `res`. If it is truthy, an error response will
be written out to the `res` or `res` will be terminated if a response has already
started.

When an error is written, the following information is added to the response:

  * The `res.statusCode` is set from `err.status` (or `err.statusCode`). If
    this value is outside the 4xx or 5xx range, it will be set to 500.
  * The `res.statusMessage` is set according to the status code.
  * The body will be the HTML of the status code message if `env` is
    `'production'`, otherwise will be `err.stack`.
  * Any headers specified in an `err.headers` object.

The final handler will also unpipe anything from `req` when it is invoked.

#### options.env

By default, the environment is determined by `NODE_ENV` variable, but it can be
overridden by this option.

#### options.onerror

Provide a function to be called with the `err` when it exists. Can be used for
writing errors to a central location without excessive function generation. Called
as `onerror(err, req, res)`.

## Examples

### always 404

```js
var finalhandler = require('finalhandler')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)
  done()
})

server.listen(3000)
```

### perform simple action

```js
var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)

  fs.readFile('index.html', function (err, buf) {
    if (err) return done(err)
    res.setHeader('Content-Type', 'text/html')
    res.end(buf)
  })
})

server.listen(3000)
```

### use with middleware-style functions

```js
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')

var serve = serveStatic('public')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res)
  serve(req, res, done)
})

server.listen(3000)
```

### keep log of all errors

```js
var finalhandler = require('finalhandler')
var fs = require('fs')
var http = require('http')

var server = http.createServer(function (req, res) {
  var done = finalhandler(req, res, { onerror: logerror })

  fs.readFile('index.html', function (err, buf) {
    if (err) return done(err)
    res.setHeader('Content-Type', 'text/html')
    res.end(buf)
  })
})

server.listen(3000)

function logerror (err) {
  console.error(err.stack || err.toString())
}
```

## License

[MIT](LICENSE)

[npm-image]: https://img.shields.io/npm/v/finalhandler.svg
[npm-url]: https://npmjs.org/package/finalhandler
[node-image]: https://img.shields.io/node/v/finalhandler.svg
[node-url]: https://nodejs.org/en/download
[coveralls-image]: https://img.shields.io/coveralls/pillarjs/finalhandler.svg
[coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master
[downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg
[downloads-url]: https://npmjs.org/package/finalhandler
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/pillarjs/finalhandler/ci/master?label=ci
[github-actions-ci-url]: https://github.com/jshttp/pillarjs/finalhandler?query=workflow%3Aci


code:
# Security Policies and Procedures

## Reporting a Bug

The `finalhandler` team and community take all security bugs seriously. Thank
you for improving the security of Express. We appreciate your efforts and
responsible disclosure and will make every effort to acknowledge your
contributions.

Report security bugs by emailing the current owner(s) of `finalhandler`. This
information can be found in the npm registry using the command
`npm owner ls finalhandler`.
If unsure or unable to get the information from the above, open an issue
in the [project issue tracker](https://github.com/pillarjs/finalhandler/issues)
asking for the current contact information.

To ensure the timely response to your report, please ensure that the entirety
of the report is contained within the email body and not solely behind a web
link or an attachment.

At least one owner will acknowledge your email within 48 hours, and will send a
more detailed response within 48 hours indicating the next steps in handling
your report. After the initial reply to your report, the owners will
endeavor to keep you informed of the progress towards a fix and full
announcement, and may ask for additional information or guidance.


code:
/*!
 * finalhandler
 * Copyright(c) 2014-2022 Douglas Christopher Wilson
 * MIT Licensed
 */

'use strict'

/**
 * Module dependencies.
 * @private
 */

var debug = require('debug')('finalhandler')
var encodeUrl = require('encodeurl')
var escapeHtml = require('escape-html')
var onFinished = require('on-finished')
var parseUrl = require('parseurl')
var statuses = require('statuses')
var unpipe = require('unpipe')

/**
 * Module variables.
 * @private
 */

var DOUBLE_SPACE_REGEXP = /\x20{2}/g
var NEWLINE_REGEXP = /\n/g

/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
  ? setImmediate
  : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }
var isFinished = onFinished.isFinished

/**
 * Create a minimal HTML document.
 *
 * @param {string} message
 * @private
 */

function createHtmlDocument (message) {
  var body = escapeHtml(message)
    .replace(NEWLINE_REGEXP, '
')
    .replace(DOUBLE_SPACE_REGEXP, '  ')

  return '<!DOCTYPE html>\n' +
    '\n' +
    '\n' +
    '<meta charset="utf-8">\n' +
    '<title>Error</title>\n' +
    '\n' +
    '\n' +
    '
' + body + '
\n' +
    '\n' +
    '\n'
}

/**
 * Module exports.
 * @public
 */

module.exports = finalhandler

/**
 * Create a function to handle the final response.
 *
 * @param {Request} req
 * @param {Response} res
 * @param {Object} [options]
 * @return {Function}
 * @public
 */

function finalhandler (req, res, options) {
  var opts = options || {}

  // get environment
  var env = opts.env || process.env.NODE_ENV || 'development'

  // get error callback
  var onerror = opts.onerror

  return function (err) {
    var headers
    var msg
    var status

    // ignore 404 on in-flight response
    if (!err && headersSent(res)) {
      debug('cannot 404 after headers sent')
      return
    }

    // unhandled error
    if (err) {
      // respect status code from error
      status = getErrorStatusCode(err)

      if (status === undefined) {
        // fallback to status code on response
        status = getResponseStatusCode(res)
      } else {
        // respect headers from error
        headers = getErrorHeaders(err)
      }

      // get error message
      msg = getErrorMessage(err, status, env)
    } else {
      // not found
      status = 404
      msg = 'Cannot ' + req.method + ' ' + encodeUrl(getResourceName(req))
    }

    debug('default %s', status)

    // schedule onerror callback
    if (err && onerror) {
      defer(onerror, err, req, res)
    }

    // cannot actually respond
    if (headersSent(res)) {
      debug('cannot %d after headers sent', status)
      req.socket.destroy()
      return
    }

    // send response
    send(req, res, status, headers, msg)
  }
}

/**
 * Get headers from Error object.
 *
 * @param {Error} err
 * @return {object}
 * @private
 */

function getErrorHeaders (err) {
  if (!err.headers || typeof err.headers !== 'object') {
    return undefined
  }

  var headers = Object.create(null)
  var keys = Object.keys(err.headers)

  for (var i = 0; i < keys.length; i++) {
    var key = keys[i]
    headers[key] = err.headers[key]
  }

  return headers
}

/**
 * Get message from Error object, fallback to status message.
 *
 * @param {Error} err
 * @param {number} status
 * @param {string} env
 * @return {string}
 * @private
 */

function getErrorMessage (err, status, env) {
  var msg

  if (env !== 'production') {
    // use err.stack, which typically includes err.message
    msg = err.stack

    // fallback to err.toString() when possible
    if (!msg && typeof err.toString === 'function') {
      msg = err.toString()
    }
  }

  return msg || statuses.message[status]
}

/**
 * Get status code from Error object.
 *
 * @param {Error} err
 * @return {number}
 * @private
 */

function getErrorStatusCode (err) {
  // check err.status
  if (typeof err.status === 'number' && err.status >= 400 && err.status < 600) {
    return err.status
  }

  // check err.statusCode
  if (typeof err.statusCode === 'number' && err.statusCode >= 400 && err.statusCode < 600) {
    return err.statusCode
  }

  return undefined
}

/**
 * Get resource name for the request.
 *
 * This is typically just the original pathname of the request
 * but will fallback to "resource" is that cannot be determined.
 *
 * @param {IncomingMessage} req
 * @return {string}
 * @private
 */

function getResourceName (req) {
  try {
    return parseUrl.original(req).pathname
  } catch (e) {
    return 'resource'
  }
}

/**
 * Get status code from response.
 *
 * @param {OutgoingMessage} res
 * @return {number}
 * @private
 */

function getResponseStatusCode (res) {
  var status = res.statusCode

  // default status code to 500 if outside valid range
  if (typeof status !== 'number' || status < 400 || status > 599) {
    status = 500
  }

  return status
}

/**
 * Determine if the response headers have been sent.
 *
 * @param {object} res
 * @returns {boolean}
 * @private
 */

function headersSent (res) {
  return typeof res.headersSent !== 'boolean'
    ? Boolean(res._header)
    : res.headersSent
}

/**
 * Send response.
 *
 * @param {IncomingMessage} req
 * @param {OutgoingMessage} res
 * @param {number} status
 * @param {object} headers
 * @param {string} message
 * @private
 */

function send (req, res, status, headers, message) {
  function write () {
    // response body
    var body = createHtmlDocument(message)

    // response status
    res.statusCode = status
    res.statusMessage = statuses.message[status]

    // remove any content headers
    res.removeHeader('Content-Encoding')
    res.removeHeader('Content-Language')
    res.removeHeader('Content-Range')

    // response headers
    setHeaders(res, headers)

    // security headers
    res.setHeader('Content-Security-Policy', "default-src 'none'")
    res.setHeader('X-Content-Type-Options', 'nosniff')

    // standard headers
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'))

    if (req.method === 'HEAD') {
      res.end()
      return
    }

    res.end(body, 'utf8')
  }

  if (isFinished(req)) {
    write()
    return
  }

  // unpipe everything from the request
  unpipe(req)

  // flush the request
  onFinished(req, write)
  req.resume()
}

/**
 * Set response headers from an object.
 *
 * @param {OutgoingMessage} res
 * @param {object} headers
 * @private
 */

function setHeaders (res, headers) {
  if (!headers) {
    return
  }

  var keys = Object.keys(headers)
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i]
    res.setHeader(key, headers[key])
  }
}


code:
support
test
examples
example
*.sock
dist
yarn.lock
coverage
bower.json


code:
language: node_js
node_js:
  - "6"
  - "5"
  - "4"

install:
  - make node_modules

script:
  - make lint
  - make test
  - make coveralls


code:
2.6.9 / 2017-09-22
==================

  * remove ReDoS regexp in %o formatter (#504)

2.6.8 / 2017-05-18
==================

  * Fix: Check for undefined on browser globals (#462, @marbemac)

2.6.7 / 2017-05-16
==================

  * Fix: Update ms to 2.0.0 to fix regular expression denial of service vulnerability (#458, @hubdotcom)
  * Fix: Inline extend function in node implementation (#452, @dougwilson)
  * Docs: Fix typo (#455, @msasad)

2.6.5 / 2017-04-27
==================

  * Fix: null reference check on window.documentElement.style.WebkitAppearance (#447, @thebigredgeek)
  * Misc: clean up browser reference checks (#447, @thebigredgeek)
  * Misc: add npm-debug.log to .gitignore (@thebigredgeek)

2.6.4 / 2017-04-20
==================

  * Fix: bug that would occure if process.env.DEBUG is a non-string value. (#444, @LucianBuzzo)
  * Chore: ignore bower.json in npm installations. (#437, @joaovieira)
  * Misc: update "ms" to v0.7.3 (@tootallnate)

2.6.3 / 2017-03-13
==================

  * Fix: Electron reference to `process.env.DEBUG` (#431, @paulcbetts)
  * Docs: Changelog fix (@thebigredgeek)

2.6.2 / 2017-03-10
==================

  * Fix: DEBUG_MAX_ARRAY_LENGTH (#420, @slavaGanzin)
  * Docs: Add backers and sponsors from Open Collective (#422, @piamancini)
  * Docs: Add Slackin invite badge (@tootallnate)

2.6.1 / 2017-02-10
==================

  * Fix: Module's `export default` syntax fix for IE8 `Expected identifier` error
  * Fix: Whitelist DEBUG_FD for values 1 and 2 only (#415, @pi0)
  * Fix: IE8 "Expected identifier" error (#414, @vgoma)
  * Fix: Namespaces would not disable once enabled (#409, @musikov)

2.6.0 / 2016-12-28
==================

  * Fix: added better null pointer checks for browser useColors (@thebigredgeek)
  * Improvement: removed explicit `window.debug` export (#404, @tootallnate)
  * Improvement: deprecated `DEBUG_FD` environment variable (#405, @tootallnate)

2.5.2 / 2016-12-25
==================

  * Fix: reference error on window within webworkers (#393, @KlausTrainer)
  * Docs: fixed README typo (#391, @lurch)
  * Docs: added notice about v3 api discussion (@thebigredgeek)

2.5.1 / 2016-12-20
==================

  * Fix: babel-core compatibility

2.5.0 / 2016-12-20
==================

  * Fix: wrong reference in bower file (@thebigredgeek)
  * Fix: webworker compatibility (@thebigredgeek)
  * Fix: output formatting issue (#388, @kribblo)
  * Fix: babel-loader compatibility (#383, @escwald)
  * Misc: removed built asset from repo and publications (@thebigredgeek)
  * Misc: moved source files to /src (#378, @yamikuronue)
  * Test: added karma integration and replaced babel with browserify for browser tests (#378, @yamikuronue)
  * Test: coveralls integration (#378, @yamikuronue)
  * Docs: simplified language in the opening paragraph (#373, @yamikuronue)

2.4.5 / 2016-12-17
==================

  * Fix: `navigator` undefined in Rhino (#376, @jochenberger)
  * Fix: custom log function (#379, @hsiliev)
  * Improvement: bit of cleanup + linting fixes (@thebigredgeek)
  * Improvement: rm non-maintainted `dist/` dir (#375, @freewil)
  * Docs: simplified language in the opening paragraph. (#373, @yamikuronue)

2.4.4 / 2016-12-14
==================

  * Fix: work around debug being loaded in preload scripts for electron (#368, @paulcbetts)

2.4.3 / 2016-12-14
==================

  * Fix: navigation.userAgent error for react native (#364, @escwald)

2.4.2 / 2016-12-14
==================

  * Fix: browser colors (#367, @tootallnate)
  * Misc: travis ci integration (@thebigredgeek)
  * Misc: added linting and testing boilerplate with sanity check (@thebigredgeek)

2.4.1 / 2016-12-13
==================

  * Fix: typo that broke the package (#356)

2.4.0 / 2016-12-13
==================

  * Fix: bower.json references unbuilt src entry point (#342, @justmatt)
  * Fix: revert "handle regex special characters" (@tootallnate)
  * Feature: configurable util.inspect()`options for NodeJS (#327, @tootallnate)
  * Feature: %O`(big O) pretty-prints objects (#322, @tootallnate)
  * Improvement: allow colors in workers (#335, @botverse)
  * Improvement: use same color for same namespace. (#338, @lchenay)

2.3.3 / 2016-11-09
==================

  * Fix: Catch `JSON.stringify()` errors (#195, Jovan Alleyne)
  * Fix: Returning `localStorage` saved values (#331, Levi Thomason)
  * Improvement: Don't create an empty object when no `process` (Nathan Rajlich)

2.3.2 / 2016-11-09
==================

  * Fix: be super-safe in index.js as well (@TooTallNate)
  * Fix: should check whether process exists (Tom Newby)

2.3.1 / 2016-11-09
==================

  * Fix: Added electron compatibility (#324, @paulcbetts)
  * Improvement: Added performance optimizations (@tootallnate)
  * Readme: Corrected PowerShell environment variable example (#252, @gimre)
  * Misc: Removed yarn lock file from source control (#321, @fengmk2)

2.3.0 / 2016-11-07
==================

  * Fix: Consistent placement of ms diff at end of output (#215, @gorangajic)
  * Fix: Escaping of regex special characters in namespace strings (#250, @zacronos)
  * Fix: Fixed bug causing crash on react-native (#282, @vkarpov15)
  * Feature: Enabled ES6+ compatible import via default export (#212 @bucaran)
  * Feature: Added %O formatter to reflect Chrome's console.log capability (#279, @oncletom)
  * Package: Update "ms" to 0.7.2 (#315, @DevSide)
  * Package: removed superfluous version property from bower.json (#207 @kkirsche)
  * Readme: fix USE_COLORS to DEBUG_COLORS
  * Readme: Doc fixes for format string sugar (#269, @mlucool)
  * Readme: Updated docs for DEBUG_FD and DEBUG_COLORS environment variables (#232, @mattlyons0)
  * Readme: doc fixes for PowerShell (#271 #243, @exoticknight @unreadable)
  * Readme: better docs for browser support (#224, @matthewmueller)
  * Tooling: Added yarn integration for development (#317, @thebigredgeek)
  * Misc: Renamed History.md to CHANGELOG.md (@thebigredgeek)
  * Misc: Added license file (#226 #274, @CantemoInternal @sdaitzman)
  * Misc: Updated contributors (@thebigredgeek)

2.2.0 / 2015-05-09
==================

  * package: update "ms" to v0.7.1 (#202, @dougwilson)
  * README: add logging to file example (#193, @DanielOchoa)
  * README: fixed a typo (#191, @amir-s)
  * browser: expose `storage` (#190, @stephenmathieson)
  * Makefile: add a `distclean` target (#189, @stephenmathieson)

2.1.3 / 2015-03-13
==================

  * Updated stdout/stderr example (#186)
  * Updated example/stdout.js to match debug current behaviour
  * Renamed example/stderr.js to stdout.js
  * Update Readme.md (#184)
  * replace high intensity foreground color for bold (#182, #183)

2.1.2 / 2015-03-01
==================

  * dist: recompile
  * update "ms" to v0.7.0
  * package: update "browserify" to v9.0.3
  * component: fix "ms.js" repo location
  * changed bower package name
  * updated documentation about using debug in a browser
  * fix: security error on safari (#167, #168, @yields)

2.1.1 / 2014-12-29
==================

  * browser: use `typeof` to check for `console` existence
  * browser: check for `console.log` truthiness (fix IE 8/9)
  * browser: add support for Chrome apps
  * Readme: added Windows usage remarks
  * Add `bower.json` to properly support bower install

2.1.0 / 2014-10-15
==================

  * node: implement `DEBUG_FD` env variable support
  * package: update "browserify" to v6.1.0
  * package: add "license" field to package.json (#135, @panuhorsmalahti)

2.0.0 / 2014-09-01
==================

  * package: update "browserify" to v5.11.0
  * node: use stderr rather than stdout for logging (#29, @stephenmathieson)

1.0.4 / 2014-07-15
==================

  * dist: recompile
  * example: remove `console.info()` log usage
  * example: add "Content-Type" UTF-8 header to browser example
  * browser: place %c marker after the space character
  * browser: reset the "content" color via `color: inherit`
  * browser: add colors support for Firefox >= v31
  * debug: prefer an instance `log()` function over the global one (#119)
  * Readme: update documentation about styled console logs for FF v31 (#116, @wryk)

1.0.3 / 2014-07-09
==================

  * Add support for multiple wildcards in namespaces (#122, @seegno)
  * browser: fix lint

1.0.2 / 2014-06-10
==================

  * browser: update color palette (#113, @gscottolson)
  * common: make console logging function configurable (#108, @timoxley)
  * node: fix %o colors on old node <= 0.8.x
  * Makefile: find node path using shell/which (#109, @timoxley)

1.0.1 / 2014-06-06
==================

  * browser: use `removeItem()` to clear localStorage
  * browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777)
  * package: add "contributors" section
  * node: fix comment typo
  * README: list authors

1.0.0 / 2014-06-04
==================

  * make ms diff be global, not be scope
  * debug: ignore empty strings in enable()
  * node: make DEBUG_COLORS able to disable coloring
  * *: export the `colors` array
  * npmignore: don't publish the `dist` dir
  * Makefile: refactor to use browserify
  * package: add "browserify" as a dev dependency
  * Readme: add Web Inspector Colors section
  * node: reset terminal color for the debug content
  * node: map "%o" to `util.inspect()`
  * browser: map "%j" to `JSON.stringify()`
  * debug: add custom "formatters"
  * debug: use "ms" module for humanizing the diff
  * Readme: add "bash" syntax highlighting
  * browser: add Firebug color support
  * browser: add colors for WebKit browsers
  * node: apply log to `console`
  * rewrite: abstract common logic for Node & browsers
  * add .jshintrc file

0.8.1 / 2014-04-14
==================

  * package: re-add the "component" section

0.8.0 / 2014-03-30
==================

  * add `enable()` method for nodejs. Closes #27
  * change from stderr to stdout
  * remove unnecessary index.js file

0.7.4 / 2013-11-13
==================

  * remove "browserify" key from package.json (fixes something in browserify)

0.7.3 / 2013-10-30
==================

  * fix: catch localStorage security error when cookies are blocked (Chrome)
  * add debug(err) support. Closes #46
  * add .browser prop to package.json. Closes #42

0.7.2 / 2013-02-06
==================

  * fix package.json
  * fix: Mobile Safari (private mode) is broken with debug
  * fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript

0.7.1 / 2013-02-05
==================

  * add repository URL to package.json
  * add DEBUG_COLORED to force colored output
  * add browserify support
  * fix component. Closes #24

0.7.0 / 2012-05-04
==================

  * Added .component to package.json
  * Added debug.component.js build

0.6.0 / 2012-03-16
==================

  * Added support for "-" prefix in DEBUG [Vinay Pulim]
  * Added `.enabled` flag to the node version [TooTallNate]

0.5.0 / 2012-02-02
==================

  * Added: humanize diffs. Closes #8
  * Added `debug.disable()` to the CS variant
  * Removed padding. Closes #10
  * Fixed: persist client-side variant again. Closes #9

0.4.0 / 2012-02-01
==================

  * Added browser variant support for older browsers [TooTallNate]
  * Added `debug.enable('project:*')` to browser variant [TooTallNate]
  * Added padding to diff (moved it to the right)

0.3.0 / 2012-01-26
==================

  * Added millisecond diff when isatty, otherwise UTC string

0.2.0 / 2012-01-22
==================

  * Added wildcard support

0.1.0 / 2011-12-02
==================

  * Added: remove colors unless stderr isatty [TooTallNate]

0.0.1 / 2010-01-03
==================

  * Initial release


code:
# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)

# BIN directory
BIN := $(THIS_DIR)/node_modules/.bin

# Path
PATH := node_modules/.bin:$(PATH)
SHELL := /bin/bash

# applications
NODE ?= $(shell which node)
YARN ?= $(shell which yarn)
PKG ?= $(if $(YARN),$(YARN),$(NODE) $(shell which npm))
BROWSERIFY ?= $(NODE) $(BIN)/browserify

.FORCE:

install: node_modules

node_modules: package.json
	@NODE_ENV= $(PKG) install
	@touch node_modules

lint: .FORCE
	eslint browser.js debug.js index.js node.js

test-node: .FORCE
	istanbul cover node_modules/mocha/bin/_mocha -- test/**.js

test-browser: .FORCE
	mkdir -p dist

	@$(BROWSERIFY) \
		--standalone debug \
		. > dist/debug.js

	karma start --single-run
	rimraf dist

test: .FORCE
	concurrently \
		"make test-node" \
		"make test-browser"

coveralls:
	cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

.PHONY: all install clean distclean


code:
# debug
[![Build Status](https://travis-ci.org/visionmedia/debug.svg?branch=master)](https://travis-ci.org/visionmedia/debug)  [![Coverage Status](https://coveralls.io/repos/github/visionmedia/debug/badge.svg?branch=master)](https://coveralls.io/github/visionmedia/debug?branch=master)  [![Slack](https://visionmedia-community-slackin.now.sh/badge.svg)](https://visionmedia-community-slackin.now.sh/) [![OpenCollective](https://opencollective.com/debug/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/debug/sponsors/badge.svg)](#sponsors)

A tiny node.js debugging utility modelled after node core's debugging technique.

**Discussion around the V3 API is under way [here](https://github.com/visionmedia/debug/issues/370)**

## Installation

```bash
$ npm install debug
```

## Usage

`debug` exposes a function; simply pass this function the name of your module, and it will return a decorated version of `console.error` for you to pass debug statements to. This will allow you to toggle the debug output for different parts of your module as well as the module as a whole.

Example _app.js_:

```js
var debug = require('debug')('http')
  , http = require('http')
  , name = 'My App';

// fake app

debug('booting %s', name);

http.createServer(function(req, res){
  debug(req.method + ' ' + req.url);
  res.end('hello\n');
}).listen(3000, function(){
  debug('listening');
});

// fake worker of some kind

require('./worker');
```

Example _worker.js_:

```js
var debug = require('debug')('worker');

setInterval(function(){
  debug('doing some work');
}, 1000);
```

 The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:

  ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)

  ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)

#### Windows note

 On Windows the environment variable is set using the `set` command.

 ```cmd
 set DEBUG=*,-not_this
 ```

 Note that PowerShell uses different syntax to set environment variables.

 ```cmd
 $env:DEBUG = "*,-not_this"
  ```

Then, run the program to be debugged as usual.

## Millisecond diff

  When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.

  ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)

  When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:

  ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)

## Conventions

  If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".

## Wildcards

  The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.

  You can also exclude specific debuggers by prefixing them with a "-" character.  For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".

## Environment Variables

  When running through Node.js, you can set a few environment variables that will
  change the behavior of the debug logging:

| Name      | Purpose                                         |
|-----------|-------------------------------------------------|
| `DEBUG`   | Enables/disables specific debugging namespaces. |
| `DEBUG_COLORS`| Whether or not to use colors in the debug output. |
| `DEBUG_DEPTH` | Object inspection depth. |
| `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. |

  __Note:__ The environment variables beginning with `DEBUG_` end up being
  converted into an Options object that gets used with `%o`/`%O` formatters.
  See the Node.js documentation for
  [`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
  for the complete list.

## Formatters

  Debug uses [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting. Below are the officially supported formatters:

| Formatter | Representation |
|-----------|----------------|
| `%O`      | Pretty-print an Object on multiple lines. |
| `%o`      | Pretty-print an Object all on a single line. |
| `%s`      | String. |
| `%d`      | Number (both integer and float). |
| `%j`      | JSON. Replaced with the string '[Circular]' if the argument contains circular references. |
| `%%`      | Single percent sign ('%'). This does not consume an argument. |

### Custom formatters

  You can add custom formatters by extending the `debug.formatters` object. For example, if you wanted to add support for rendering a Buffer as hex with `%h`, you could do something like:

```js
const createDebug = require('debug')
createDebug.formatters.h = (v) => {
  return v.toString('hex')
}

// …elsewhere
const debug = createDebug('foo')
debug('this is hex: %h', new Buffer('hello world'))
//   foo this is hex: 68656c6c6f20776f726c6421 +0ms
```

## Browser support
  You can build a browser-ready script using [browserify](https://github.com/substack/node-browserify),
  or just use the [browserify-as-a-service](https://wzrd.in/) [build](https://wzrd.in/standalone/debug@latest),
  if you don't want to build it yourself.

  Debug's enable state is currently persisted by `localStorage`.
  Consider the situation shown below where you have `worker:a` and `worker:b`,
  and wish to debug both. You can enable this using `localStorage.debug`:

```js
localStorage.debug = 'worker:*'
```

And then refresh the page.

```js
a = debug('worker:a');
b = debug('worker:b');

setInterval(function(){
  a('doing some work');
}, 1000);

setInterval(function(){
  b('doing some work');
}, 1200);
```

#### Web Inspector Colors

  Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
  option. These are WebKit web inspectors, Firefox ([since version
  31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
  and the Firebug plugin for Firefox (any version).

  Colored output looks something like:

  ![](https://cloud.githubusercontent.com/assets/71256/3139768/b98c5fd8-e8ef-11e3-862a-f7253b6f47c6.png)

## Output streams

  By default `debug` will log to stderr, however this can be configured per-namespace by overriding the `log` method:

Example _stdout.js_:

```js
var debug = require('debug');
var error = debug('app:error');

// by default stderr is used
error('goes to stderr!');

var log = debug('app:log');
// set this namespace to log via console.log
log.log = console.log.bind(console); // don't forget to bind to console!
log('goes to stdout');
error('still goes to stderr!');

// set all output to go via console.info
// overrides all per-namespace log settings
debug.log = console.info.bind(console);
error('now goes to stdout via console.info');
log('still goes to stdout, but via console.info now');
```

## Authors

 - TJ Holowaychuk
 - Nathan Rajlich
 - Andrew Rhyne

## Backers

Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/debug#backer)]

## Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/debug#sponsor)]

## License

(The MIT License)

Copyright (c) 2014-2016 TJ Holowaychuk <tj@vision-media.ca>

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.


debug

repo: visionmedia/debug

description: small debugging utility

keywords: debug log debugger


code:
// Karma configuration
// Generated on Fri Dec 16 2016 13:09:51 GMT+0000 (UTC)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon'],

    // list of files / patterns to load in the browser
    files: [
      'dist/debug.js',
      'test/*spec.js'
    ],

    // list of files to exclude
    exclude: [
      'src/node.js'
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}


code: module.exports = require('./src/node');


description: small debugging utility

author: TJ Holowaychuk <tj@vision-media.ca>

contributors: Nathan Rajlich <nathan@tootallnate.net> (http://n8.io)