code:
/* eslint-disable no-unused-vars */
/* eslint-disable no-use-before-define */
// For TS consumers who use Node and don't have dom in their tsconfig lib, import the necessary types here.
/// <reference lib="dom" />

/* Public API */

// eslint-disable-next-line
declare const hljs : HLJSApi;

type HLJSApi = PublicApi & ModesAPI

interface VuePlugin {
    install: (vue: any) => void
}

interface PublicApi {
    highlight: (codeOrlanguageName: string, optionsOrCode: string | HighlightOptions, ignoreIllegals?: boolean, continuation?: Mode) => HighlightResult
    highlightAuto: (code: string, languageSubset?: string[]) => AutoHighlightResult
    fixMarkup: (html: string) => string
    highlightBlock: (element: HTMLElement) => void
    highlightElement: (element: HTMLElement) => void
    configure: (options: Partial<HLJSOptions>) => void
    initHighlighting: () => void
    initHighlightingOnLoad: () => void
    highlightAll: () => void
    registerLanguage: (languageName: string, language: LanguageFn) => void
    unregisterLanguage: (languageName: string) => void
    listLanguages: () => string[]
    registerAliases: (aliasList: string | string[], { languageName } : {languageName: string}) => void
    getLanguage: (languageName: string) => Language | undefined
    requireLanguage: (languageName: string) => Language | never
    autoDetection: (languageName: string) => boolean
    inherit: <T>(original: T, ...args: Record<string, any>[]) => T
    addPlugin: (plugin: HLJSPlugin) => void
    debugMode: () => void
    safeMode: () => void
    versionString: string
    vuePlugin: () => VuePlugin
}

interface ModesAPI {
    SHEBANG: (mode?: Partial<Mode> & {binary?: string | RegExp}) => Mode
    BACKSLASH_ESCAPE: Mode
    QUOTE_STRING_MODE: Mode
    APOS_STRING_MODE: Mode
    PHRASAL_WORDS_MODE: Mode
    COMMENT: (begin: string | RegExp, end: string | RegExp, modeOpts?: Mode | {}) => Mode
    C_LINE_COMMENT_MODE: Mode
    C_BLOCK_COMMENT_MODE: Mode
    HASH_COMMENT_MODE: Mode
    NUMBER_MODE: Mode
    C_NUMBER_MODE: Mode
    BINARY_NUMBER_MODE: Mode
    CSS_NUMBER_MODE: Mode
    REGEXP_MODE: Mode
    TITLE_MODE: Mode
    UNDERSCORE_TITLE_MODE: Mode
    METHOD_GUARD: Mode
    END_SAME_AS_BEGIN: (mode: Mode) => Mode
    // built in regex
    IDENT_RE: string
    UNDERSCORE_IDENT_RE: string
    MATCH_NOTHING_RE: string
    NUMBER_RE: string
    C_NUMBER_RE: string
    BINARY_NUMBER_RE: string
    RE_STARTERS_RE: string
}

type LanguageFn = (hljs?: HLJSApi) => Language
type CompilerExt = (mode: Mode, parent: Mode | Language | null) => void

interface HighlightResult {
    relevance : number
    value : string
    language? : string
    emitter : Emitter
    illegal : boolean
    top? : Language | CompiledMode
    illegalBy? : illegalData
    sofar? : string
    errorRaised? : Error
    // * for auto-highlight
    second_best? : Omit<HighlightResult, 'second_best'>
    code?: string
}
interface AutoHighlightResult extends HighlightResult {}

interface illegalData {
    msg: string
    context: string
    mode: CompiledMode
}

type BeforeHighlightContext = {
  code: string,
  language: string,
  result?: HighlightResult
}
type PluginEvent = keyof HLJSPlugin;
type HLJSPlugin = {
    'after:highlight'?: (result: HighlightResult) => void,
    'before:highlight'?: (context: BeforeHighlightContext) => void,
    'after:highlightElement'?: (data: { el: Element, result: HighlightResult, text: string}) => void,
    'before:highlightElement'?: (data: { el: Element, language: string}) => void,
    // TODO: Old API, remove with v12
    'after:highlightBlock'?: (data: { block: Element, result: HighlightResult, text: string}) => void,
    'before:highlightBlock'?: (data: { block: Element, language: string}) => void,
}

interface EmitterConstructor {
    new (opts: any): Emitter
}

interface HighlightOptions {
    language: string
    ignoreIllegals?: boolean
}

interface HLJSOptions {
   noHighlightRe: RegExp
   languageDetectRe: RegExp
   classPrefix: string
   tabReplace?: string
   useBR: boolean
   languages?: string[]
   __emitter: EmitterConstructor
}

interface CallbackResponse {
    data: Record<string, any>
    ignoreMatch: () => void
    isMatchIgnored: boolean
}

/************
 PRIVATE API
 ************/

/* for jsdoc annotations in the JS source files */

type AnnotatedError = Error & {mode?: Mode | Language, languageName?: string, badRule?: Mode}

type ModeCallback = (match: RegExpMatchArray, response: CallbackResponse) => void
type HighlightedHTMLElement = HTMLElement & {result?: object, second_best?: object, parentNode: HTMLElement}
type EnhancedMatch = RegExpMatchArray & {rule: CompiledMode, type: MatchType}
type MatchType = "begin" | "end" | "illegal"

 interface Emitter {
    addKeyword(text: string, kind: string): void
    addText(text: string): void
    toHTML(): string
    finalize(): void
    closeAllNodes(): void
    openNode(kind: string): void
    closeNode(): void
    addSublanguage(emitter: Emitter, subLanguageName: string): void
 }

/* modes */

 interface ModeCallbacks {
     "on:end"?: Function,
     "on:begin"?: ModeCallback
 }

interface Mode extends ModeCallbacks, ModeDetails {

}

interface LanguageDetail {
    name?: string
    rawDefinition?: () => Language
    aliases?: string[]
    disableAutodetect?: boolean
    contains: (Mode)[]
    case_insensitive?: boolean
    keywords?: Record<string, any> | string
    isCompiled?: boolean,
    exports?: any,
    classNameAliases?: Record<string, string>
    compilerExtensions?: CompilerExt[]
    supersetOf?: string
}

type Language = LanguageDetail & Partial<Mode>

interface CompiledLanguage extends LanguageDetail, CompiledMode {
    isCompiled: true
    contains: CompiledMode[]
    keywords: Record<string, any>
}

type KeywordData = [string, number];
type KeywordDict = Record<string, KeywordData>

type CompiledMode = Omit<Mode, 'contains'> &
    {
        contains: CompiledMode[]
        keywords: KeywordDict
        data: Record<string, any>
        terminatorEnd: string
        keywordPatternRe: RegExp
        beginRe: RegExp
        endRe: RegExp
        illegalRe: RegExp
        matcher: any
        isCompiled: true
        starts?: CompiledMode
        parent?: CompiledMode
    }

interface ModeDetails {
    begin?: RegExp | string
    match?: RegExp | string
    end?: RegExp | string
    className?: string
    contains?: ("self" | Mode)[]
    endsParent?: boolean
    endsWithParent?: boolean
    endSameAsBegin?: boolean
    skip?: boolean
    excludeBegin?: boolean
    excludeEnd?: boolean
    returnBegin?: boolean
    returnEnd?: boolean
    __beforeBegin?: Function
    parent?: Mode
    starts?:Mode
    lexemes?: string | RegExp
    keywords?: Record<string, any> | string
    beginKeywords?: string
    relevance?: number
    illegal?: string | RegExp | Array<string | RegExp>
    variants?: Mode[]
    cachedVariants?: Mode[]
    // parsed
    subLanguage?: string | string[]
    isCompiled?: boolean
    label?: string
}

// deprecated API since v10
// declare module 'highlight.js/lib/highlight.js';

declare module 'highlight.js' {
    export = hljs;
}

declare module 'highlight.js/lib/core' {
    export = hljs;
}

declare module 'highlight.js/lib/core.js' {
    export = hljs;
}

declare module 'highlight.js/lib/languages/*' {
    export default function(hljs?: HLJSApi): LanguageDetail;
}


code:
# Change Log

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [2.8.9](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9) (2021-04-07)

### Bug Fixes

* backport regex fix from [#76](https://github.com/npm/hosted-git-info/issues/76) ([29adfe5](https://github.com/npm/hosted-git-info/commit/29adfe5)), closes [#84](https://github.com/npm/hosted-git-info/issues/84)

## [2.8.8](https://github.com/npm/hosted-git-info/compare/v2.8.7...v2.8.8) (2020-02-29)

### Bug Fixes

* [#61](https://github.com/npm/hosted-git-info/issues/61) & [#65](https://github.com/npm/hosted-git-info/issues/65) addressing issues w/ url.URL implmentation which regressed node 6 support ([5038b18](https://github.com/npm/hosted-git-info/commit/5038b18)), closes [#66](https://github.com/npm/hosted-git-info/issues/66)

## [2.8.7](https://github.com/npm/hosted-git-info/compare/v2.8.6...v2.8.7) (2020-02-26)

### Bug Fixes

* Do not attempt to use url.URL when unavailable ([2d0bb66](https://github.com/npm/hosted-git-info/commit/2d0bb66)), closes [#61](https://github.com/npm/hosted-git-info/issues/61) [#62](https://github.com/npm/hosted-git-info/issues/62)
* Do not pass scp-style URLs to the WhatWG url.URL ([f2cdfcf](https://github.com/npm/hosted-git-info/commit/f2cdfcf)), closes [#60](https://github.com/npm/hosted-git-info/issues/60)

## [2.8.6](https://github.com/npm/hosted-git-info/compare/v2.8.5...v2.8.6) (2020-02-25)

## [2.8.5](https://github.com/npm/hosted-git-info/compare/v2.8.4...v2.8.5) (2019-10-07)

### Bug Fixes

* updated pathmatch for gitlab ([e8325b5](https://github.com/npm/hosted-git-info/commit/e8325b5)), closes [#51](https://github.com/npm/hosted-git-info/issues/51)
* updated pathmatch for gitlab ([ffe056f](https://github.com/npm/hosted-git-info/commit/ffe056f))

## [2.8.4](https://github.com/npm/hosted-git-info/compare/v2.8.3...v2.8.4) (2019-08-12)

## [2.8.3](https://github.com/npm/hosted-git-info/compare/v2.8.2...v2.8.3) (2019-08-12)

## [2.8.2](https://github.com/npm/hosted-git-info/compare/v2.8.1...v2.8.2) (2019-08-05)

### Bug Fixes

* http protocol use sshurl by default ([3b1d629](https://github.com/npm/hosted-git-info/commit/3b1d629)), closes [#48](https://github.com/npm/hosted-git-info/issues/48)

## [2.8.1](https://github.com/npm/hosted-git-info/compare/v2.8.0...v2.8.1) (2019-08-05)

### Bug Fixes

* ignore noCommittish on tarball url generation ([5d4a8d7](https://github.com/npm/hosted-git-info/commit/5d4a8d7))
* use gist tarball url that works for anonymous gists ([1692435](https://github.com/npm/hosted-git-info/commit/1692435))

# [2.8.0](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.0) (2019-08-05)

### Bug Fixes

* Allow slashes in gitlab project section ([bbcf7b2](https://github.com/npm/hosted-git-info/commit/bbcf7b2)), closes [#46](https://github.com/npm/hosted-git-info/issues/46) [#43](https://github.com/npm/hosted-git-info/issues/43)
* **git-host:** disallow URI-encoded slash (%2F) in `path` ([3776fa5](https://github.com/npm/hosted-git-info/commit/3776fa5)), closes [#44](https://github.com/npm/hosted-git-info/issues/44)
* **gitlab:** Do not URL encode slashes in project name for GitLab https URL ([cbf04f9](https://github.com/npm/hosted-git-info/commit/cbf04f9)), closes [#47](https://github.com/npm/hosted-git-info/issues/47)
* do not allow invalid gist urls ([d5cf830](https://github.com/npm/hosted-git-info/commit/d5cf830))
* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([e518222](https://github.com/npm/hosted-git-info/commit/e518222)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)

### Features

* give these objects a name ([60abaea](https://github.com/npm/hosted-git-info/commit/60abaea))

## [2.7.1](https://github.com/npm/hosted-git-info/compare/v2.7.0...v2.7.1) (2018-07-07)

### Bug Fixes

* **index:** Guard against non-string types ([5bc580d](https://github.com/npm/hosted-git-info/commit/5bc580d))
* **parse:** Crash on strings that parse to having no host ([c931482](https://github.com/npm/hosted-git-info/commit/c931482)), closes [#35](https://github.com/npm/hosted-git-info/issues/35)

# [2.7.0](https://github.com/npm/hosted-git-info/compare/v2.6.1...v2.7.0) (2018-07-06)

### Bug Fixes

* **github tarball:** update github tarballtemplate ([6efd582](https://github.com/npm/hosted-git-info/commit/6efd582)), closes [#34](https://github.com/npm/hosted-git-info/issues/34)
* **gitlab docs:** switched to lowercase anchors for readmes ([701bcd1](https://github.com/npm/hosted-git-info/commit/701bcd1))

### Features

* **all:** Support www. prefixes on hostnames ([3349575](https://github.com/npm/hosted-git-info/commit/3349575)), closes [#32](https://github.com/npm/hosted-git-info/issues/32)

## [2.6.1](https://github.com/npm/hosted-git-info/compare/v2.6.0...v2.6.1) (2018-06-25)

### Bug Fixes

* **Revert:** "compat: remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25))" ([cce5a62](https://github.com/npm/hosted-git-info/commit/cce5a62))
* **Revert:** "git-host: fix forgotten extend()" ([a815ec9](https://github.com/npm/hosted-git-info/commit/a815ec9))

# [2.6.0](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.6.0) (2018-03-07)

### Bug Fixes

* **compat:** remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25)) ([627ab55](https://github.com/npm/hosted-git-info/commit/627ab55))
* **git-host:** fix forgotten extend() ([eba1f7b](https://github.com/npm/hosted-git-info/commit/eba1f7b))

### Features

* **browse:** fragment support for browse() ([#28](https://github.com/npm/hosted-git-info/issues/28)) ([cd5e5bb](https://github.com/npm/hosted-git-info/commit/cd5e5bb))

license: mit


code:
# hosted-git-info

This will let you identify and transform various git hosts URLs between
protocols.  It also can tell you what the URL is for the raw path for
particular file for direct access without git.

## Example

```javascript
var hostedGitInfo = require("hosted-git-info")
var info = hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git", opts)
/* info looks like:
{
  type: "github",
  domain: "github.com",
  user: "npm",
  project: "hosted-git-info"
}
*/
```

If the URL can't be matched with a git host, `null` will be returned.  We
can match git, ssh and https urls.  Additionally, we can match ssh connect
strings (`git@github.com:npm/hosted-git-info`) and shortcuts (eg,
`github:npm/hosted-git-info`).  Github specifically, is detected in the case
of a third, unprefixed, form: `npm/hosted-git-info`.

If it does match, the returned object has properties of:

* info.type -- The short name of the service
* info.domain -- The domain for git protocol use
* info.user -- The name of the user/org on the git host
* info.project -- The name of the project on the git host

## Version Contract

The major version will be bumped any time…

* The constructor stops accepting URLs that it previously accepted.
* A method is removed.
* A method can no longer accept the number and type of arguments it previously accepted.
* A method can return a different type than it currently returns.

Implications:

* I do not consider the specific format of the urls returned from, say
  `.https()` to be a part of the contract.  The contract is that it will
  return a string that can be used to fetch the repo via HTTPS.  But what
  that string looks like, specifically, can change.
* Dropping support for a hosted git provider would constitute a breaking
  change.

## Usage

### var info = hostedGitInfo.fromUrl(gitSpecifier[, options])

* *gitSpecifer* is a URL of a git repository or a SCP-style specifier of one.
* *options* is an optional object. It can have the following properties:
  * *noCommittish* — If true then committishes won't be included in generated URLs.
  * *noGitPlus* — If true then `git+` won't be prefixed on URLs.

## Methods

All of the methods take the same options as the `fromUrl` factory.  Options
provided to a method override those provided to the constructor.

* info.file(path, opts)

Given the path of a file relative to the repository, returns a URL for
directly fetching it from the githost.  If no committish was set then
`master` will be used as the default.

For example `hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git#v1.0.0").file("package.json")`
would return `https://raw.githubusercontent.com/npm/hosted-git-info/v1.0.0/package.json`

* info.shortcut(opts)

eg, `github:npm/hosted-git-info`

* info.browse(path, fragment, opts)

eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0`,
`https://github.com/npm/hosted-git-info/tree/v1.2.0/package.json`,
`https://github.com/npm/hosted-git-info/tree/v1.2.0/REAMDE.md#supported-hosts`

* info.bugs(opts)

eg, `https://github.com/npm/hosted-git-info/issues`

* info.docs(opts)

eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0#readme`

* info.https(opts)

eg, `git+https://github.com/npm/hosted-git-info.git`

* info.sshurl(opts)

eg, `git+ssh://git@github.com/npm/hosted-git-info.git`

* info.ssh(opts)

eg, `git@github.com:npm/hosted-git-info.git`

* info.path(opts)

eg, `npm/hosted-git-info`

* info.tarball(opts)

eg, `https://github.com/npm/hosted-git-info/archive/v1.2.0.tar.gz`

* info.getDefaultRepresentation()

Returns the default output type. The default output type is based on the
string you passed in to be parsed

* info.toString(opts)

Uses the getDefaultRepresentation to call one of the other methods to get a URL for
this resource. As such `hostedGitInfo.fromUrl(url).toString()` will give
you a normalized version of the URL that still uses the same protocol.

Shortcuts will still be returned as shortcuts, but the special case github
form of `org/project` will be normalized to `github:org/project`.

SSH connect strings will be normalized into `git+ssh` URLs.

## Supported hosts

Currently this supports Github, Bitbucket and Gitlab. Pull requests for
additional hosts welcome.


code:
'use strict'

var gitHosts = module.exports = {
  github: {
    // First two are insecure and generally shouldn't be used any more, but
    // they are still supported.
    'protocols': [ 'git', 'http', 'git+ssh', 'git+https', 'ssh', 'https' ],
    'domain': 'github.com',
    'treepath': 'tree',
    'filetemplate': 'https://{auth@}raw.githubusercontent.com/{user}/{project}/{committish}/{path}',
    'bugstemplate': 'https://{domain}/{user}/{project}/issues',
    'gittemplate': 'git://{auth@}{domain}/{user}/{project}.git{#committish}',
    'tarballtemplate': 'https://codeload.{domain}/{user}/{project}/tar.gz/{committish}'
  },
  bitbucket: {
    'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
    'domain': 'bitbucket.org',
    'treepath': 'src',
    'tarballtemplate': 'https://{domain}/{user}/{project}/get/{committish}.tar.gz'
  },
  gitlab: {
    'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
    'domain': 'gitlab.com',
    'treepath': 'tree',
    'bugstemplate': 'https://{domain}/{user}/{project}/issues',
    'httpstemplate': 'git+https://{auth@}{domain}/{user}/{projectPath}.git{#committish}',
    'tarballtemplate': 'https://{domain}/{user}/{project}/repository/archive.tar.gz?ref={committish}',
    'pathmatch': /^[/]([^/]+)[/]((?!.*(\/-\/|\/repository\/archive\.tar\.gz\?=.*|\/repository\/[^/]+\/archive.tar.gz$)).*?)(?:[.]git|[/])?$/
  },
  gist: {
    'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ],
    'domain': 'gist.github.com',
    'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]{32,})(?:[.]git)?$/,
    'filetemplate': 'https://gist.githubusercontent.com/{user}/{project}/raw{/committish}/{path}',
    'bugstemplate': 'https://{domain}/{project}',
    'gittemplate': 'git://{domain}/{project}.git{#committish}',
    'sshtemplate': 'git@{domain}:/{project}.git{#committish}',
    'sshurltemplate': 'git+ssh://git@{domain}/{project}.git{#committish}',
    'browsetemplate': 'https://{domain}/{project}{/committish}',
    'browsefiletemplate': 'https://{domain}/{project}{/committish}{#path}',
    'docstemplate': 'https://{domain}/{project}{/committish}',
    'httpstemplate': 'git+https://{domain}/{project}.git{#committish}',
    'shortcuttemplate': '{type}:{project}{#committish}',
    'pathtemplate': '{project}{#committish}',
    'tarballtemplate': 'https://codeload.github.com/gist/{project}/tar.gz/{committish}',
    'hashformat': function (fragment) {
      return 'file-' + formatHashFragment(fragment)
    }
  }
}

var gitHostDefaults = {
  'sshtemplate': 'git@{domain}:{user}/{project}.git{#committish}',
  'sshurltemplate': 'git+ssh://git@{domain}/{user}/{project}.git{#committish}',
  'browsetemplate': 'https://{domain}/{user}/{project}{/tree/committish}',
  'browsefiletemplate': 'https://{domain}/{user}/{project}/{treepath}/{committish}/{path}{#fragment}',
  'docstemplate': 'https://{domain}/{user}/{project}{/tree/committish}#readme',
  'httpstemplate': 'git+https://{auth@}{domain}/{user}/{project}.git{#committish}',
  'filetemplate': 'https://{domain}/{user}/{project}/raw/{committish}/{path}',
  'shortcuttemplate': '{type}:{user}/{project}{#committish}',
  'pathtemplate': '{user}/{project}{#committish}',
  'pathmatch': /^[/]([^/]+)[/]([^/]+?)(?:[.]git|[/])?$/,
  'hashformat': formatHashFragment
}

Object.keys(gitHosts).forEach(function (name) {
  Object.keys(gitHostDefaults).forEach(function (key) {
    if (gitHosts[name][key]) return
    gitHosts[name][key] = gitHostDefaults[key]
  })
  gitHosts[name].protocols_re = RegExp('^(' +
    gitHosts[name].protocols.map(function (protocol) {
      return protocol.replace(/([\\+*{}()[\]$^|])/g, '\\$1')
    }).join('|') + '):$')
})

function formatHashFragment (fragment) {
  return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
}


code:
'use strict'
var gitHosts = require('./git-host-info.js')
/* eslint-disable node/no-deprecated-api */

// copy-pasta util._extend from node's source, to avoid pulling
// the whole util module into peoples' webpack bundles.
/* istanbul ignore next */
var extend = Object.assign || function _extend (target, source) {
  // Don't do anything if source isn't an object
  if (source === null || typeof source !== 'object') return target

  var keys = Object.keys(source)
  var i = keys.length
  while (i--) {
    target[keys[i]] = source[keys[i]]
  }
  return target
}

module.exports = GitHost
function GitHost (type, user, auth, project, committish, defaultRepresentation, opts) {
  var gitHostInfo = this
  gitHostInfo.type = type
  Object.keys(gitHosts[type]).forEach(function (key) {
    gitHostInfo[key] = gitHosts[type][key]
  })
  gitHostInfo.user = user
  gitHostInfo.auth = auth
  gitHostInfo.project = project
  gitHostInfo.committish = committish
  gitHostInfo.default = defaultRepresentation
  gitHostInfo.opts = opts || {}
}

GitHost.prototype.hash = function () {
  return this.committish ? '#' + this.committish : ''
}

GitHost.prototype._fill = function (template, opts) {
  if (!template) return
  var vars = extend({}, opts)
  vars.path = vars.path ? vars.path.replace(/^[/]+/g, '') : ''
  opts = extend(extend({}, this.opts), opts)
  var self = this
  Object.keys(this).forEach(function (key) {
    if (self[key] != null && vars[key] == null) vars[key] = self[key]
  })
  var rawAuth = vars.auth
  var rawcommittish = vars.committish
  var rawFragment = vars.fragment
  var rawPath = vars.path
  var rawProject = vars.project
  Object.keys(vars).forEach(function (key) {
    var value = vars[key]
    if ((key === 'path' || key === 'project') && typeof value === 'string') {
      vars[key] = value.split('/').map(function (pathComponent) {
        return encodeURIComponent(pathComponent)
      }).join('/')
    } else {
      vars[key] = encodeURIComponent(value)
    }
  })
  vars['auth@'] = rawAuth ? rawAuth + '@' : ''
  vars['#fragment'] = rawFragment ? '#' + this.hashformat(rawFragment) : ''
  vars.fragment = vars.fragment ? vars.fragment : ''
  vars['#path'] = rawPath ? '#' + this.hashformat(rawPath) : ''
  vars['/path'] = vars.path ? '/' + vars.path : ''
  vars.projectPath = rawProject.split('/').map(encodeURIComponent).join('/')
  if (opts.noCommittish) {
    vars['#committish'] = ''
    vars['/tree/committish'] = ''
    vars['/committish'] = ''
    vars.committish = ''
  } else {
    vars['#committish'] = rawcommittish ? '#' + rawcommittish : ''
    vars['/tree/committish'] = vars.committish
      ? '/' + vars.treepath + '/' + vars.committish
      : ''
    vars['/committish'] = vars.committish ? '/' + vars.committish : ''
    vars.committish = vars.committish || 'master'
  }
  var res = template
  Object.keys(vars).forEach(function (key) {
    res = res.replace(new RegExp('[{]' + key + '[}]', 'g'), vars[key])
  })
  if (opts.noGitPlus) {
    return res.replace(/^git[+]/, '')
  } else {
    return res
  }
}

GitHost.prototype.ssh = function (opts) {
  return this._fill(this.sshtemplate, opts)
}

GitHost.prototype.sshurl = function (opts) {
  return this._fill(this.sshurltemplate, opts)
}

GitHost.prototype.browse = function (P, F, opts) {
  if (typeof P === 'string') {
    if (typeof F !== 'string') {
      opts = F
      F = null
    }
    return this._fill(this.browsefiletemplate, extend({
      fragment: F,
      path: P
    }, opts))
  } else {
    return this._fill(this.browsetemplate, P)
  }
}

GitHost.prototype.docs = function (opts) {
  return this._fill(this.docstemplate, opts)
}

GitHost.prototype.bugs = function (opts) {
  return this._fill(this.bugstemplate, opts)
}

GitHost.prototype.https = function (opts) {
  return this._fill(this.httpstemplate, opts)
}

GitHost.prototype.git = function (opts) {
  return this._fill(this.gittemplate, opts)
}

GitHost.prototype.shortcut = function (opts) {
  return this._fill(this.shortcuttemplate, opts)
}

GitHost.prototype.path = function (opts) {
  return this._fill(this.pathtemplate, opts)
}

GitHost.prototype.tarball = function (opts_) {
  var opts = extend({}, opts_, { noCommittish: false })
  return this._fill(this.tarballtemplate, opts)
}

GitHost.prototype.file = function (P, opts) {
  return this._fill(this.filetemplate, extend({ path: P }, opts))
}

GitHost.prototype.getDefaultRepresentation = function () {
  return this.default
}

GitHost.prototype.toString = function (opts) {
  if (this.default && typeof this[this.default] === 'function') return this[this.default](opts)
  return this.sshurl(opts)
}


code:
'use strict'
var url = require('url')
var gitHosts = require('./git-host-info.js')
var GitHost = module.exports = require('./git-host.js')

var protocolToRepresentationMap = {
  'git+ssh:': 'sshurl',
  'git+https:': 'https',
  'ssh:': 'sshurl',
  'git:': 'git'
}

function protocolToRepresentation (protocol) {
  return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
}

var authProtocols = {
  'git:': true,
  'https:': true,
  'git+https:': true,
  'http:': true,
  'git+http:': true
}

var cache = {}

module.exports.fromUrl = function (giturl, opts) {
  if (typeof giturl !== 'string') return
  var key = giturl + JSON.stringify(opts || {})

  if (!(key in cache)) {
    cache[key] = fromUrl(giturl, opts)
  }

  return cache[key]
}

function fromUrl (giturl, opts) {
  if (giturl == null || giturl === '') return
  var url = fixupUnqualifiedGist(
    isGitHubShorthand(giturl) ? 'github:' + giturl : giturl
  )
  var parsed = parseGitUrl(url)
  var shortcutMatch = url.match(/^([^:]+):(?:[^@]+@)?(?:([^/]*)\/)?([^#]+)/)
  var matches = Object.keys(gitHosts).map(function (gitHostName) {
    try {
      var gitHostInfo = gitHosts[gitHostName]
      var auth = null
      if (parsed.auth && authProtocols[parsed.protocol]) {
        auth = parsed.auth
      }
      var committish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null
      var user = null
      var project = null
      var defaultRepresentation = null
      if (shortcutMatch && shortcutMatch[1] === gitHostName) {
        user = shortcutMatch[2] && decodeURIComponent(shortcutMatch[2])
        project = decodeURIComponent(shortcutMatch[3].replace(/\.git$/, ''))
        defaultRepresentation = 'shortcut'
      } else {
        if (parsed.host && parsed.host !== gitHostInfo.domain && parsed.host.replace(/^www[.]/, '') !== gitHostInfo.domain) return
        if (!gitHostInfo.protocols_re.test(parsed.protocol)) return
        if (!parsed.path) return
        var pathmatch = gitHostInfo.pathmatch
        var matched = parsed.path.match(pathmatch)
        if (!matched) return
        /* istanbul ignore else */
        if (matched[1] !== null && matched[1] !== undefined) {
          user = decodeURIComponent(matched[1].replace(/^:/, ''))
        }
        project = decodeURIComponent(matched[2])
        defaultRepresentation = protocolToRepresentation(parsed.protocol)
      }
      return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
    } catch (ex) {
      /* istanbul ignore else */
      if (ex instanceof URIError) {
      } else throw ex
    }
  }).filter(function (gitHostInfo) { return gitHostInfo })
  if (matches.length !== 1) return
  return matches[0]
}

function isGitHubShorthand (arg) {
  // Note: This does not fully test the git ref format.
  // See https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
  //
  // The only way to do this properly would be to shell out to
  // git-check-ref-format, and as this is a fast sync function,
  // we don't want to do that.  Just let git fail if it turns
  // out that the commit-ish is invalid.
  // GH usernames cannot start with . or -
  return /^[^:@%/\s.-][^:@%/\s]*[/][^:@\s/%]+(?:#.*)?$/.test(arg)
}

function fixupUnqualifiedGist (giturl) {
  // necessary for round-tripping gists
  var parsed = url.parse(giturl)
  if (parsed.protocol === 'gist:' && parsed.host && !parsed.path) {
    return parsed.protocol + '/' + parsed.host
  } else {
    return giturl
  }
}

function parseGitUrl (giturl) {
  var matched = giturl.match(/^([^@]+)@([^:/]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
  if (!matched) {
    var legacy = url.parse(giturl)
    // If we don't have url.URL, then sorry, this is just not fixable.
    // This affects Node <= 6.12.
    if (legacy.auth && typeof url.URL === 'function') {
      // git urls can be in the form of scp-style/ssh-connect strings, like
      // git+ssh://user@host.com:some/path, which the legacy url parser
      // supports, but WhatWG url.URL class does not.  However, the legacy
      // parser de-urlencodes the username and password, so something like
      // https://user%3An%40me:p%40ss%3Aword@x.com/ becomes
      // https://user:n@me:p@ss:word@x.com/ which is all kinds of wrong.
      // Pull off just the auth and host, so we dont' get the confusing
      // scp-style URL, then pass that to the WhatWG parser to get the
      // auth properly escaped.
      var authmatch = giturl.match(/[^@]+@[^:/]+/)
      /* istanbul ignore else - this should be impossible */
      if (authmatch) {
        var whatwg = new url.URL(authmatch[0])
        legacy.auth = whatwg.username || ''
        if (whatwg.password) legacy.auth += ':' + whatwg.password
      }
    }
    return legacy
  }
  return {
    protocol: 'git+ssh:',
    slashes: true,
    auth: matched[1],
    host: matched[2],
    port: null,
    hostname: matched[2],
    hash: matched[4],
    search: null,
    query: null,
    pathname: '/' + matched[3],
    path: '/' + matched[3],
    href: 'git+ssh://' + matched[1] + '@' + matched[2] +
          '/' + matched[3] + (matched[4] || '')
  }
}


hosted-git-info

description: Provides metadata and conversions from repository urls for Github, Bitbucket and Gitlab

type: git

keywords: git github bitbucket gitlab

author: Rebecca Turner <me@re-becca.org> (http://re-becca.org)

license: ISC

prerelease: npm t

postrelease: npm publish --tag=ancient-legacy-fixes && git push --follow-tags

posttest: standard

release: standard-version -s

test:coverage: tap --coverage-report=html -J --coverage=90 --no-esm test/*.js

test: tap -J --coverage=90 --no-esm test/*.js


code:
language: node_js
node_js:
  - "iojs"
branches:
  only:
    - master


code:
# HPACK.js

[![Build Status](https://secure.travis-ci.org/indutny/hpack.js.png)](http://travis-ci.org/indutny/hpack.js)
[![NPM version](https://badge.fury.io/js/hpack.js.svg)](http://badge.fury.io/js/hpack.js)

Plain-JS implementation of [HPACK][0].

## Usage

```javascript
var hpack = require('hpack.js');

var comp = hpack.compressor.create({ table: { size: 256 } });
var decomp = hpack.decompressor.create({ table: { size: 256 } });

comp.write([ { name: 'host', value: 'localhost' } ]);
var raw = comp.read();
console.log(raw);
// <Buffer 66 86 a0 e4 1d 13 9d 09>

decomp.write(raw);
decomp.execute();
console.log(decomp.read());
// { name: 'host', value: 'localhost', neverIndex: false }
```

#### LICENSE

This software is licensed under the MIT License.

Copyright Fedor Indutny, 2015.

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.

[0]: https://tools.ietf.org/html/rfc7541


code:
#!/usr/bin/env node
var hpack = require('../');

var options = {
  table: { size: 1024 }
};

var compressor = hpack.compressor.create(options);

var vector = [];
for (var i = 0; i < 1024; i++) {
  vector.push({
    name: 'kind-of-big-header-name__',
    value: 'not-so-small value yes!',
    huffman: true,
    neverIndex: true
  });
}
compressor.write(vector);
var input = compressor.read();

console.time('decompressor');
for (var i = 0; i < 2000; i++) {
  var decompressor = hpack.decompressor.create(options);

  decompressor.write(input);
  decompressor.execute();
  while (true) {
    var chunk = decompressor.read();
    if (!chunk)
      break;
  }
}
console.timeEnd('decompressor');


code:
var hpack = exports;

hpack.utils = require('./hpack/utils');
hpack.huffman = require('./hpack/huffman');
hpack['static-table'] = require('./hpack/static-table');
hpack.table = require('./hpack/table');

hpack.decoder = require('./hpack/decoder');
hpack.decompressor = require('./hpack/decompressor');

hpack.encoder = require('./hpack/encoder');
hpack.compressor = require('./hpack/compressor');


code:
var hpack = require('../hpack');
var utils = hpack.utils;
var encoder = hpack.encoder;
var table = hpack.table;
var assert = utils.assert;

var inherits = require('inherits');
var Duplex = require('readable-stream').Duplex;

function Compressor(options) {
  Duplex.call(this, {
    writableObjectMode: true
  });

  this._encoder = null;
  this._table = table.create(options.table);
}
inherits(Compressor, Duplex);
module.exports = Compressor;

Compressor.create = function create(options) {
  return new Compressor(options);
};

Compressor.prototype._read = function _read() {
  // We only push!
};

Compressor.prototype._write = function _write(data, enc, cb) {
  assert(Array.isArray(data), 'Compressor.write() expects list of headers');

  this._encoder = encoder.create();
  for (var i = 0; i < data.length; i++)
    this._encodeHeader(data[i]);

  var data = this._encoder.render();
  this._encoder = null;

  cb(null);
  for (var i = 0; i < data.length; i++)
    this.push(data[i]);
};

Compressor.prototype.updateTableSize = function updateTableSize(size) {
  if (size >= this._table.protocolMaxSize) {
    size = this._table.protocolMaxSize;

    var enc = encoder.create();

    // indexed = 0
    // incremental = 0
    // update = 1
    enc.encodeBits(1, 3);
    enc.encodeInt(size);

    var data = enc.render();
    for (var i = 0; i < data.length; i++)
      this.push(data[i]);
  }

  this._table.updateSize(size);
};

Compressor.prototype.reset = function reset() {
  var enc = encoder.create();
  var size = this._table.maxSize;

  // indexed = 0
  // incremental = 0
  // update = 1
  enc.encodeBits(1, 3);
  enc.encodeInt(0);

  // Evict everything
  this._table.updateSize(0);

  // indexed = 0
  // incremental = 0
  // update = 1
  enc.encodeBits(1, 3);
  enc.encodeInt(size);

  // Revert size
  this._table.updateSize(size);

  var data = enc.render();
  for (var i = 0; i < data.length; i++)
    this.push(data[i]);
};

Compressor.prototype._encodeHeader = function _encodeHeader(header) {
  if (header.neverIndex) {
    var index = 0;
    var neverIndex = 1;
    var isIndexed = 0;
    var isIncremental = 0;
  } else {
    var index = this._table.reverseLookup(header.name, header.value);
    var isIndexed = index > 0;
    var isIncremental = header.incremental !== false;
    var neverIndex = 0;
  }

  this._encoder.encodeBit(isIndexed);
  if (isIndexed) {
    this._encoder.encodeInt(index);
    return;
  }

  var name = utils.toArray(header.name);
  var value = utils.toArray(header.value);

  this._encoder.encodeBit(isIncremental);
  if (isIncremental) {
    this._table.add(header.name, header.value, name.length, value.length);
  } else {
    // Update = false
    this._encoder.encodeBit(0);
    this._encoder.encodeBit(neverIndex);
  }

  // index is negative for `name`-only headers
  this._encoder.encodeInt(-index);
  if (index === 0)
    this._encoder.encodeStr(name, header.huffman !== false);
  this._encoder.encodeStr(value, header.huffman !== false);
};


code:
var hpack = require('../hpack');
var utils = hpack.utils;
var huffman = hpack.huffman.decode;
var assert = utils.assert;

var OffsetBuffer = require('obuf');

function Decoder() {
  this.buffer = new OffsetBuffer();
  this.bitOffset = 0;

  // Used internally in decodeStr
  this._huffmanNode = null;
}
module.exports = Decoder;

Decoder.create = function create() {
  return new Decoder();
};

Decoder.prototype.isEmpty = function isEmpty() {
  return this.buffer.isEmpty();
};

Decoder.prototype.push = function push(chunk) {
  this.buffer.push(chunk);
};

Decoder.prototype.decodeBit = function decodeBit() {
  // Need at least one octet
  assert(this.buffer.has(1), 'Buffer too small for an int');

  var octet;
  var offset = this.bitOffset;

  if (++this.bitOffset === 8) {
    octet = this.buffer.readUInt8();
    this.bitOffset = 0;
  } else {
    octet = this.buffer.peekUInt8();
  }
  return (octet >>> (7 - offset)) & 1;
};

// Just for testing
Decoder.prototype.skipBits = function skipBits(n) {
  this.bitOffset += n;
  this.buffer.skip(this.bitOffset >> 3);
  this.bitOffset &= 0x7;
};

Decoder.prototype.decodeInt = function decodeInt() {
  // Need at least one octet
  assert(this.buffer.has(1), 'Buffer too small for an int');

  var prefix = 8 - this.bitOffset;

  // We are going to end up octet-aligned
  this.bitOffset = 0;

  var max = (1 << prefix) - 1;
  var octet = this.buffer.readUInt8() & max;

  // Fast case - int fits into the prefix
  if (octet !== max)
    return octet;

  // TODO(indutny): what about > 32bit numbers?
  var res = 0;
  var isLast = false;
  var len = 0;
  do {
    octet = this.buffer.readUInt8();
    isLast = (octet & 0x80) === 0;

    res <<= 7;
    res |= octet & 0x7f;
    len++;
  } while (!isLast);
  assert(isLast, 'Incomplete data for multi-octet integer');
  assert(len <= 4, 'Integer does not fit into 32 bits');

  // Reverse bits
  res = (res >>> 21) |
        (((res >> 14) & 0x7f) << 7) |
        (((res >> 7) & 0x7f) << 14) |
        ((res & 0x7f) << 21);
  res >>= (4 - len) * 7;

  // Append prefix max
  res += max;

  return res;
};

Decoder.prototype.decodeHuffmanWord = function decodeHuffmanWord(input,
                                                                 inputBits,
                                                                 out) {
  var root = huffman;
  var node = this._huffmanNode;
  var word = input;
  var bits = inputBits;

  for (; bits > 0; word &= (1 << bits) - 1) {
    // Nudge the word bit length to match it
    for (var i = Math.max(0, bits - 8); i < bits; i++) {
      var subnode = node[word >>> i];
      if (typeof subnode !== 'number') {
        node = subnode;
        bits = i;
        break;
      }

      if (subnode === 0)
        continue;

      // Word bit length should match
      if ((subnode >>> 9) !== bits - i) {
        subnode = 0;
        continue;
      }

      var octet = subnode & 0x1ff;
      assert(octet !== 256, 'EOS in encoding');
      out.push(octet);
      node = root;

      bits = i;
      break;
    }
    if (subnode === 0)
      break;
  }
  this._huffmanNode = node;

  return bits;
};

Decoder.prototype.decodeStr = function decodeStr() {
  var isHuffman = this.decodeBit();
  var len = this.decodeInt();
  assert(this.buffer.has(len), 'Not enough octets for string');

  if (!isHuffman)
    return this.buffer.take(len);

  this._huffmanNode = huffman;

  var out = [];

  var word = 0;
  var bits = 0;
  var lastKey = 0;
  for (var i = 0; i < len; i++) {
    word <<= 8;
    word |= this.buffer.readUInt8();
    bits += 8;

    bits = this.decodeHuffmanWord(word, bits, out);
    lastKey = word >> bits;
    word &= (1 << bits) - 1;
  }
  assert(this._huffmanNode === huffman, '8-bit EOS');
  assert(word + 1 === (1 << bits), 'Final sequence is not EOS');

  this._huffmanNode = null;

  return out;
};


code:
var hpack = require('../hpack');
var utils = hpack.utils;
var decoder = hpack.decoder;
var table = hpack.table;
var assert = utils.assert;

var inherits = require('inherits');
var Duplex = require('readable-stream').Duplex;

function Decompressor(options) {
  Duplex.call(this, {
    readableObjectMode: true
  });

  this._decoder = decoder.create();
  this._table = table.create(options.table);
}
inherits(Decompressor, Duplex);
module.exports = Decompressor;

Decompressor.create = function create(options) {
  return new Decompressor(options);
};

Decompressor.prototype._read = function _read() {
  // We only push!
};

Decompressor.prototype._write = function _write(data, enc, cb) {
  this._decoder.push(data);

  cb(null);
};

Decompressor.prototype.execute = function execute(cb) {
  while (!this._decoder.isEmpty()) {
    try {
      this._execute();
    } catch (err) {
      if (cb)
        return done(err);
      else
        return this.emit('error', err);
    }
  }

  if (cb)
    done(null);

  function done(err) {
    process.nextTick(function() {
      cb(err);
    });
  }
};

Decompressor.prototype.updateTableSize = function updateTableSize(size) {
  this._table.updateSize(size);
};

Decompressor.prototype._execute = function _execute() {
  var isIndexed = this._decoder.decodeBit();
  if (isIndexed)
    return this._processIndexed();

  var isIncremental = this._decoder.decodeBit();
  var neverIndex = 0;
  if (!isIncremental) {
    var isUpdate = this._decoder.decodeBit();
    if (isUpdate)
      return this._processUpdate();

    neverIndex = this._decoder.decodeBit();
  }

  this._processLiteral(isIncremental, neverIndex);
};

Decompressor.prototype._processIndexed = function _processIndexed() {
  var index = this._decoder.decodeInt();

  var lookup = this._table.lookup(index);
  this.push({ name: lookup.name, value: lookup.value, neverIndex: false });
};

Decompressor.prototype._processLiteral = function _processLiteral(inc, never) {
  var index = this._decoder.decodeInt();

  var name;
  var nameSize;

  // Literal header-name too
  if (index === 0) {
    name = this._decoder.decodeStr();
    nameSize = name.length;
    name = utils.stringify(name);
  } else {
    var lookup = this._table.lookup(index);
    nameSize = lookup.nameSize;
    name = lookup.name;
  }

  var value = this._decoder.decodeStr();
  var valueSize = value.length;
  value = utils.stringify(value);

  if (inc)
    this._table.add(name, value, nameSize, valueSize);

  this.push({ name: name, value: value, neverIndex: never !== 0});
};

Decompressor.prototype._processUpdate = function _processUpdate() {
  var size = this._decoder.decodeInt();
  this.updateTableSize(size);
};


code:
var hpack = require('../hpack');
var utils = hpack.utils;
var huffman = hpack.huffman.encode;
var assert = utils.assert;

var WBuf = require('wbuf');

function Encoder() {
  this.buffer = new WBuf();
  this.word = 0;
  this.bitOffset = 0;
}
module.exports = Encoder;

Encoder.create = function create() {
  return new Encoder();
};

Encoder.prototype.render = function render() {
  return this.buffer.render();
};

Encoder.prototype.encodeBit = function encodeBit(bit) {
  var octet;

  this.word <<= 1;
  this.word |= bit;
  this.bitOffset++;

  if (this.bitOffset === 8) {
    this.buffer.writeUInt8(this.word);
    this.word = 0;
    this.bitOffset = 0;
  }
};

Encoder.prototype.encodeBits = function encodeBits(bits, len) {
  var left = bits;
  var leftLen = len;

  while (leftLen > 0) {
    var avail = Math.min(leftLen, 8 - this.bitOffset);
    var toWrite = left >>> (leftLen - avail);

    if (avail === 8) {
      this.buffer.writeUInt8(toWrite);
    } else {
      this.word <<= avail;
      this.word |= toWrite;
      this.bitOffset += avail;
      if (this.bitOffset === 8) {
        this.buffer.writeUInt8(this.word);
        this.word = 0;
        this.bitOffset = 0;
      }
    }

    leftLen -= avail;
    left &= (1 << leftLen) - 1;
  }
};

// Just for testing
Encoder.prototype.skipBits = function skipBits(num) {
  this.bitOffset += num;
  this.buffer.skip(this.bitOffset >> 3);
  this.bitOffset &= 0x7;
};

Encoder.prototype.encodeInt = function encodeInt(num) {
  var prefix = 8 - this.bitOffset;

  // We are going to end up octet-aligned
  this.bitOffset = 0;

  var max = (1 << prefix) - 1;

  // Fast case - int fits into the prefix
  if (num < max) {
    this.buffer.writeUInt8((this.word << prefix) | num);
    return octet;
  }

  var left = num - max;
  this.buffer.writeUInt8((this.word << prefix) | max);
  do {
    var octet = left & 0x7f;
    left >>= 7;
    if (left !== 0)
      octet |= 0x80;

    this.buffer.writeUInt8(octet);
  } while (left !== 0);
};

Encoder.prototype.encodeStr = function encodeStr(value, isHuffman) {
  this.encodeBit(isHuffman ? 1 : 0);

  if (!isHuffman) {
    this.buffer.reserve(value.length + 1);
    this.encodeInt(value.length);
    for (var i = 0; i < value.length; i++)
      this.buffer.writeUInt8(value[i]);
    return;
  }

  var codes = [];
  var len = 0;
  var pad = 0;

  for (var i = 0; i < value.length; i++) {
    var code = huffman[value[i]];
    codes.push(code);
    len += code[0];
  }
  if (len % 8 !== 0)
    pad = 8 - (len % 8);
  len += pad;

  this.buffer.reserve((len / 8) + 1);
  this.encodeInt(len / 8);
  for (var i = 0; i < codes.length; i++) {
    var code = codes[i];
    this.encodeBits(code[1], code[0]);
  }

  // Append padding
  this.encodeBits(0xff >>> (8 - pad), pad);
};


code:
exports.table = [
  {
    "name": ":authority",
    "value": "",
    "nameSize": 10,
    "totalSize": 42
  },
  {
    "name": ":method",
    "value": "GET",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":method",
    "value": "POST",
    "nameSize": 7,
    "totalSize": 43
  },
  {
    "name": ":path",
    "value": "/",
    "nameSize": 5,
    "totalSize": 38
  },
  {
    "name": ":path",
    "value": "/index.html",
    "nameSize": 5,
    "totalSize": 48
  },
  {
    "name": ":scheme",
    "value": "http",
    "nameSize": 7,
    "totalSize": 43
  },
  {
    "name": ":scheme",
    "value": "https",
    "nameSize": 7,
    "totalSize": 44
  },
  {
    "name": ":status",
    "value": "200",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "204",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "206",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "304",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "400",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "404",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": ":status",
    "value": "500",
    "nameSize": 7,
    "totalSize": 42
  },
  {
    "name": "accept-charset",
    "value": "",
    "nameSize": 14,
    "totalSize": 46
  },
  {
    "name": "accept-encoding",
    "value": "gzip, deflate",
    "nameSize": 15,
    "totalSize": 60
  },
  {
    "name": "accept-language",
    "value": "",
    "nameSize": 15,
    "totalSize": 47
  },
  {
    "name": "accept-ranges",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "accept",
    "value": "",
    "nameSize": 6,
    "totalSize": 38
  },
  {
    "name": "access-control-allow-origin",
    "value": "",
    "nameSize": 27,
    "totalSize": 59
  },
  {
    "name": "age",
    "value": "",
    "nameSize": 3,
    "totalSize": 35
  },
  {
    "name": "allow",
    "value": "",
    "nameSize": 5,
    "totalSize": 37
  },
  {
    "name": "authorization",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "cache-control",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "content-disposition",
    "value": "",
    "nameSize": 19,
    "totalSize": 51
  },
  {
    "name": "content-encoding",
    "value": "",
    "nameSize": 16,
    "totalSize": 48
  },
  {
    "name": "content-language",
    "value": "",
    "nameSize": 16,
    "totalSize": 48
  },
  {
    "name": "content-length",
    "value": "",
    "nameSize": 14,
    "totalSize": 46
  },
  {
    "name": "content-location",
    "value": "",
    "nameSize": 16,
    "totalSize": 48
  },
  {
    "name": "content-range",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "content-type",
    "value": "",
    "nameSize": 12,
    "totalSize": 44
  },
  {
    "name": "cookie",
    "value": "",
    "nameSize": 6,
    "totalSize": 38
  },
  {
    "name": "date",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "etag",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "expect",
    "value": "",
    "nameSize": 6,
    "totalSize": 38
  },
  {
    "name": "expires",
    "value": "",
    "nameSize": 7,
    "totalSize": 39
  },
  {
    "name": "from",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "host",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "if-match",
    "value": "",
    "nameSize": 8,
    "totalSize": 40
  },
  {
    "name": "if-modified-since",
    "value": "",
    "nameSize": 17,
    "totalSize": 49
  },
  {
    "name": "if-none-match",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "if-range",
    "value": "",
    "nameSize": 8,
    "totalSize": 40
  },
  {
    "name": "if-unmodified-since",
    "value": "",
    "nameSize": 19,
    "totalSize": 51
  },
  {
    "name": "last-modified",
    "value": "",
    "nameSize": 13,
    "totalSize": 45
  },
  {
    "name": "link",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "location",
    "value": "",
    "nameSize": 8,
    "totalSize": 40
  },
  {
    "name": "max-forwards",
    "value": "",
    "nameSize": 12,
    "totalSize": 44
  },
  {
    "name": "proxy-authenticate",
    "value": "",
    "nameSize": 18,
    "totalSize": 50
  },
  {
    "name": "proxy-authorization",
    "value": "",
    "nameSize": 19,
    "totalSize": 51
  },
  {
    "name": "range",
    "value": "",
    "nameSize": 5,
    "totalSize": 37
  },
  {
    "name": "referer",
    "value": "",
    "nameSize": 7,
    "totalSize": 39
  },
  {
    "name": "refresh",
    "value": "",
    "nameSize": 7,
    "totalSize": 39
  },
  {
    "name": "retry-after",
    "value": "",
    "nameSize": 11,
    "totalSize": 43
  },
  {
    "name": "server",
    "value": "",
    "nameSize": 6,
    "totalSize": 38
  },
  {
    "name": "set-cookie",
    "value": "",
    "nameSize": 10,
    "totalSize": 42
  },
  {
    "name": "strict-transport-security",
    "value": "",
    "nameSize": 25,
    "totalSize": 57
  },
  {
    "name": "transfer-encoding",
    "value": "",
    "nameSize": 17,
    "totalSize": 49
  },
  {
    "name": "user-agent",
    "value": "",
    "nameSize": 10,
    "totalSize": 42
  },
  {
    "name": "vary",
    "value": "",
    "nameSize": 4,
    "totalSize": 36
  },
  {
    "name": "via",
    "value": "",
    "nameSize": 3,
    "totalSize": 35
  },
  {
    "name": "www-authenticate",
    "value": "",
    "nameSize": 16,
    "totalSize": 48
  }
];
exports.map = {
  ":authority": {
    "index": 1,
    "values": {
      "": 1
    }
  },
  ":method": {
    "index": 2,
    "values": {
      "GET": 2,
      "POST": 3
    }
  },
  ":path": {
    "index": 4,
    "values": {
      "/": 4,
      "/index.html": 5
    }
  },
  ":scheme": {
    "index": 6,
    "values": {
      "http": 6,
      "https": 7
    }
  },
  ":status": {
    "index": 8,
    "values": {
      "200": 8,
      "204": 9,
      "206": 10,
      "304": 11,
      "400": 12,
      "404": 13,
      "500": 14
    }
  },
  "accept-charset": {
    "index": 15,
    "values": {
      "": 15
    }
  },
  "accept-encoding": {
    "index": 16,
    "values": {
      "gzip, deflate": 16
    }
  },
  "accept-language": {
    "index": 17,
    "values": {
      "": 17
    }
  },
  "accept-ranges": {
    "index": 18,
    "values": {
      "": 18
    }
  },
  "accept": {
    "index": 19,
    "values": {
      "": 19
    }
  },
  "access-control-allow-origin": {
    "index": 20,
    "values": {
      "": 20
    }
  },
  "age": {
    "index": 21,
    "values": {
      "": 21
    }
  },
  "allow": {
    "index": 22,
    "values": {
      "": 22
    }
  },
  "authorization": {
    "index": 23,
    "values": {
      "": 23
    }
  },
  "cache-control": {
    "index": 24,
    "values": {
      "": 24
    }
  },
  "content-disposition": {
    "index": 25,
    "values": {
      "": 25
    }
  },
  "content-encoding": {
    "index": 26,
    "values": {
      "": 26
    }
  },
  "content-language": {
    "index": 27,
    "values": {
      "": 27
    }
  },
  "content-length": {
    "index": 28,
    "values": {
      "": 28
    }
  },
  "content-location": {
    "index": 29,
    "values": {
      "": 29
    }
  },
  "content-range": {
    "index": 30,
    "values": {
      "": 30
    }
  },
  "content-type": {
    "index": 31,
    "values": {
      "": 31
    }
  },
  "cookie": {
    "index": 32,
    "values": {
      "": 32
    }
  },
  "date": {
    "index": 33,
    "values": {
      "": 33
    }
  },
  "etag": {
    "index": 34,
    "values": {
      "": 34
    }
  },
  "expect": {
    "index": 35,
    "values": {
      "": 35
    }
  },
  "expires": {
    "index": 36,
    "values": {
      "": 36
    }
  },
  "from": {
    "index": 37,
    "values": {
      "": 37
    }
  },
  "host": {
    "index": 38,
    "values": {
      "": 38
    }
  },
  "if-match": {
    "index": 39,
    "values": {
      "": 39
    }
  },
  "if-modified-since": {
    "index": 40,
    "values": {
      "": 40
    }
  },
  "if-none-match": {
    "index": 41,
    "values": {
      "": 41
    }
  },
  "if-range": {
    "index": 42,
    "values": {
      "": 42
    }
  },
  "if-unmodified-since": {
    "index": 43,
    "values": {
      "": 43
    }
  },
  "last-modified": {
    "index": 44,
    "values": {
      "": 44
    }
  },
  "link": {
    "index": 45,
    "values": {
      "": 45
    }
  },
  "location": {
    "index": 46,
    "values": {
      "": 46
    }
  },
  "max-forwards": {
    "index": 47,
    "values": {
      "": 47
    }
  },
  "proxy-authenticate": {
    "index": 48,
    "values": {
      "": 48
    }
  },
  "proxy-authorization": {
    "index": 49,
    "values": {
      "": 49
    }
  },
  "range": {
    "index": 50,
    "values": {
      "": 50
    }
  },
  "referer": {
    "index": 51,
    "values": {
      "": 51
    }
  },
  "refresh": {
    "index": 52,
    "values": {
      "": 52
    }
  },
  "retry-after": {
    "index": 53,
    "values": {
      "": 53
    }
  },
  "server": {
    "index": 54,
    "values": {
      "": 54
    }
  },
  "set-cookie": {
    "index": 55,
    "values": {
      "": 55
    }
  },
  "strict-transport-security": {
    "index": 56,
    "values": {
      "": 56
    }
  },
  "transfer-encoding": {
    "index": 57,
    "values": {
      "": 57
    }
  },
  "user-agent": {
    "index": 58,
    "values": {
      "": 58
    }
  },
  "vary": {
    "index": 59,
    "values": {
      "": 59
    }
  },
  "via": {
    "index": 60,
    "values": {
      "": 60
    }
  },
  "www-authenticate": {
    "index": 61,
    "values": {
      "": 61
    }
  }
};


code:
var hpack = require('../hpack');
var utils = hpack.utils;
var assert = utils.assert;

function Table(options) {
  this['static'] = hpack['static-table'];
  this.dynamic = [];
  this.size = 0;
  this.maxSize = 0;
  this.length = this['static'].table.length;
  this.protocolMaxSize = options.maxSize;
  this.maxSize = this.protocolMaxSize;
  this.lookupDepth = options.lookupDepth || 32;
}
module.exports = Table;

Table.create = function create(options) {
  return new Table(options);
};

Table.prototype.lookup = function lookup(index) {
  assert(index !== 0, 'Zero indexed field');
  assert(index <= this.length, 'Indexed field OOB')

  if (index <= this['static'].table.length)
    return this['static'].table[index - 1];
  else
    return this.dynamic[this.length - index];
};

Table.prototype.reverseLookup = function reverseLookup(name, value) {
  var staticEntry = this['static'].map[name];
  if (staticEntry && staticEntry.values[value])
    return staticEntry.values[value];

  // Reverse search dynamic table (new items are at the end of it)
  var limit = Math.max(0, this.dynamic.length - this.lookupDepth);
  for (var i = this.dynamic.length - 1; i >= limit; i--) {
    var entry = this.dynamic[i];
    if (entry.name === name && entry.value === value)
      return this.length - i;

    if (entry.name === name) {
      // Prefer smaller index
      if (staticEntry)
        break;
      return -(this.length - i);
    }
  }

  if (staticEntry)
    return -staticEntry.index;

  return 0;
};

Table.prototype.add = function add(name, value, nameSize, valueSize) {
  var totalSize = nameSize + valueSize + 32;

  this.dynamic.push({
    name: name,
    value: value,
    nameSize: nameSize,
    totalSize: totalSize
  });
  this.size += totalSize;
  this.length++;

  this.evict();
};

Table.prototype.evict = function evict() {
  while (this.size > this.maxSize) {
    var entry = this.dynamic.shift();
    this.size -= entry.totalSize;
    this.length--;
  }
  assert(this.size >= 0, 'Table size sanity check failed');
};

Table.prototype.updateSize = function updateSize(size) {
  assert(size <= this.protocolMaxSize, 'Table size bigger than maximum');
  this.maxSize = size;
  this.evict();
};


code:
exports.assert = function assert(cond, text) {
  if (!cond)
    throw new Error(text);
};

exports.stringify = function stringify(arr) {
  var res = '';
  for (var i = 0; i < arr.length; i++)
    res += String.fromCharCode(arr[i]);
  return res;
};

exports.toArray = function toArray(str) {
  var res = [];
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    var hi = c >>> 8;
    var lo = c & 0xff;
    if (hi)
      res.push(hi, lo);
    else
      res.push(lo);
  }
  return res;
};


code:
sudo: false
language: node_js
before_install:
  - (test $NPM_LEGACY && npm install -g npm@2 && npm install -g npm@3) || true
notifications:
  email: false
matrix:
  fast_finish: true
  include:
  - node_js: '0.8'
    env: NPM_LEGACY=true
  - node_js: '0.10'
    env: NPM_LEGACY=true
  - node_js: '0.11'
    env: NPM_LEGACY=true
  - node_js: '0.12'
    env: NPM_LEGACY=true
  - node_js: 1
    env: NPM_LEGACY=true
  - node_js: 2
    env: NPM_LEGACY=true
  - node_js: 3
    env: NPM_LEGACY=true
  - node_js: 4
  - node_js: 5
  - node_js: 6
  - node_js: 7
  - node_js: 8
  - node_js: 9
script: "npm run test"
env:
  global:
  - secure: rE2Vvo7vnjabYNULNyLFxOyt98BoJexDqsiOnfiD6kLYYsiQGfr/sbZkPMOFm9qfQG7pjqx+zZWZjGSswhTt+626C0t/njXqug7Yps4c3dFblzGfreQHp7wNX5TFsvrxd6dAowVasMp61sJcRnB2w8cUzoe3RAYUDHyiHktwqMc=
  - secure: g9YINaKAdMatsJ28G9jCGbSaguXCyxSTy+pBO6Ch0Cf57ZLOTka3HqDj8p3nV28LUIHZ3ut5WO43CeYKwt4AUtLpBS3a0dndHdY6D83uY6b2qh5hXlrcbeQTq2cvw2y95F7hm4D1kwrgZ7ViqaKggRcEupAL69YbJnxeUDKWEdI=


code:
# Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

* (a) The contribution was created in whole or in part by me and I
  have the right to submit it under the open source license
  indicated in the file; or

* (b) The contribution is based upon previous work that, to the best
  of my knowledge, is covered under an appropriate open source
  license and I have the right under that license to submit that
  work with modifications, whether created in whole or in part
  by me, under the same open source license (unless I am
  permitted to submit under a different license), as indicated
  in the file; or

* (c) The contribution was provided directly to me by some other
  person who certified (a), (b) or (c) and I have not modified
  it.

* (d) I understand and agree that this project and the contribution
  are public and that a record of the contribution (including all
  personal information I submit with it, including my sign-off) is
  maintained indefinitely and may be redistributed consistent with
  this project or the open source license(s) involved.

## Moderation Policy

The [Node.js Moderation Policy] applies to this WG.

## Code of Conduct

The [Node.js Code of Conduct][] applies to this WG.

[Node.js Code of Conduct]:
https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md
[Node.js Moderation Policy]:
https://github.com/nodejs/TSC/blob/master/Moderation-Policy.md


code:
### Streams Working Group

The Node.js Streams is jointly governed by a Working Group
(WG)
that is responsible for high-level guidance of the project.

The WG has final authority over this project including:

* Technical direction
* Project governance and process (including this policy)
* Contribution policy
* GitHub repository hosting
* Conduct guidelines
* Maintaining the list of additional Collaborators

For the current list of WG members, see the project
[README.md](./README.md#current-project-team-members).

### Collaborators

The readable-stream GitHub repository is
maintained by the WG and additional Collaborators who are added by the
WG on an ongoing basis.

Individuals making significant and valuable contributions are made
Collaborators and given commit-access to the project. These
individuals are identified by the WG and their addition as
Collaborators is discussed during the WG meeting.

_Note:_ If you make a significant contribution and are not considered
for commit-access log an issue or contact a WG member directly and it
will be brought up in the next WG meeting.

Modifications of the contents of the readable-stream repository are
made on
a collaborative basis. Anybody with a GitHub account may propose a
modification via pull request and it will be considered by the project
Collaborators. All pull requests must be reviewed and accepted by a
Collaborator with sufficient expertise who is able to take full
responsibility for the change. In the case of pull requests proposed
by an existing Collaborator, an additional Collaborator is required
for sign-off. Consensus should be sought if additional Collaborators
participate and there is disagreement around a particular
modification. See _Consensus Seeking Process_ below for further detail
on the consensus model used for governance.

Collaborators may opt to elevate significant or controversial
modifications, or modifications that have not found consensus to the
WG for discussion by assigning the ***WG-agenda*** tag to a pull
request or issue. The WG should serve as the final arbiter where
required.

For the current list of Collaborators, see the project
[README.md](./README.md#members).

### WG Membership

WG seats are not time-limited.  There is no fixed size of the WG.
However, the expected target is between 6 and 12, to ensure adequate
coverage of important areas of expertise, balanced with the ability to
make decisions efficiently.

There is no specific set of requirements or qualifications for WG
membership beyond these rules.

The WG may add additional members to the WG by unanimous consensus.

A WG member may be removed from the WG by voluntary resignation, or by
unanimous consensus of all other WG members.

Changes to WG membership should be posted in the agenda, and may be
suggested as any other agenda item (see "WG Meetings" below).

If an addition or removal is proposed during a meeting, and the full
WG is not in attendance to participate, then the addition or removal
is added to the agenda for the subsequent meeting.  This is to ensure
that all members are given the opportunity to participate in all
membership decisions.  If a WG member is unable to attend a meeting
where a planned membership decision is being made, then their consent
is assumed.

No more than 1/3 of the WG members may be affiliated with the same
employer.  If removal or resignation of a WG member, or a change of
employment by a WG member, creates a situation where more than 1/3 of
the WG membership shares an employer, then the situation must be
immediately remedied by the resignation or removal of one or more WG
members affiliated with the over-represented employer(s).

### WG Meetings

The WG meets occasionally on a Google Hangout On Air. A designated moderator
approved by the WG runs the meeting. Each meeting should be
published to YouTube.

Items are added to the WG agenda that are considered contentious or
are modifications of governance, contribution policy, WG membership,
or release process.

The intention of the agenda is not to approve or review all patches;
that should happen continuously on GitHub and be handled by the larger
group of Collaborators.

Any community member or contributor can ask that something be added to
the next meeting's agenda by logging a GitHub Issue. Any Collaborator,
WG member or the moderator can add the item to the agenda by adding
the ***WG-agenda*** tag to the issue.

Prior to each WG meeting the moderator will share the Agenda with
members of the WG. WG members can add any items they like to the
agenda at the beginning of each meeting. The moderator and the WG
cannot veto or remove items.

The WG may invite persons or representatives from certain projects to
participate in a non-voting capacity.

The moderator is responsible for summarizing the discussion of each
agenda item and sends it as a pull request after the meeting.

### Consensus Seeking Process

The WG follows a
[Consensus
Seeking](http://en.wikipedia.org/wiki/Consensus-seeking_decision-making)
decision-making model.

When an agenda item has appeared to reach a consensus the moderator
will ask "Does anyone object?" as a final call for dissent from the
consensus.

If an agenda item cannot reach a consensus a WG member can call for
either a closing vote or a vote to table the issue to the next
meeting. The call for a vote must be seconded by a majority of the WG
or else the discussion will continue. Simple majority wins.

Note that changes to WG membership require a majority consensus.  See
"WG Membership" above.


code:
# readable-stream

***Node-core v8.17.0 streams for userland*** [![Build Status](https://travis-ci.org/nodejs/readable-stream.svg?branch=master)](https://travis-ci.org/nodejs/readable-stream)

[![NPM](https://nodei.co/npm/readable-stream.png?downloads=true&downloadRank=true)](https://nodei.co/npm/readable-stream/)
[![NPM](https://nodei.co/npm-dl/readable-stream.png?&months=6&height=3)](https://nodei.co/npm/readable-stream/)

[![Sauce Test Status](https://saucelabs.com/browser-matrix/readable-stream.svg)](https://saucelabs.com/u/readable-stream)

```bash
npm install --save readable-stream
```

***Node-core streams for userland***

This package is a mirror of the Streams2 and Streams3 implementations in
Node-core.

Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v8.17.0/docs/api/stream.html).

If you want to guarantee a stable streams base, regardless of what version of
Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).

As of version 2.0.0 **readable-stream** uses semantic versioning.

# Streams Working Group

`readable-stream` is maintained by the Streams Working Group, which
oversees the development and maintenance of the Streams API within
Node.js. The responsibilities of the Streams Working Group include:

* Addressing stream issues on the Node.js issue tracker.
* Authoring and editing stream documentation within the Node.js project.
* Reviewing changes to stream subclasses within the Node.js project.
* Redirecting changes to streams from the Node.js project to this
  project.
* Assisting in the implementation of stream providers within Node.js.
* Recommending versions of `readable-stream` to be included in Node.js.
* Messaging about the future of streams to give the community advance
  notice of changes.

## Team Members

* **Chris Dickinson** ([@chrisdickinson](https://github.com/chrisdickinson)) <christopher.s.dickinson@gmail.com>
  - Release GPG key: 9554F04D7259F04124DE6B476D5A82AC7E37093B
* **Calvin Metcalf** ([@calvinmetcalf](https://github.com/calvinmetcalf)) <calvin.metcalf@gmail.com>
  - Release GPG key: F3EF5F62A87FC27A22E643F714CE4FF5015AA242
* **Rod Vagg** ([@rvagg](https://github.com/rvagg)) <rod@vagg.org>
  - Release GPG key: DD8F2338BAE7501E3DD5AC78C273792F7D83545D
* **Sam Newman** ([@sonewman](https://github.com/sonewman)) <newmansam@outlook.com>
* **Mathias Buus** ([@mafintosh](https://github.com/mafintosh)) <mathiasbuus@gmail.com>
* **Domenic Denicola** ([@domenic](https://github.com/domenic)) <d@domenic.me>
* **Matteo Collina** ([@mcollina](https://github.com/mcollina)) <matteo.collina@gmail.com>
  - Release GPG key: 3ABC01543F22DD2239285CDD818674489FBC127E
* **Irina Shestak** ([@lrlna](https://github.com/lrlna)) <shestak.irina@gmail.com>


code:
# streams WG Meeting 2015-01-30

## Links

* **Google Hangouts Video**: http://www.youtube.com/watch?v=I9nDOSGfwZg
* **GitHub Issue**: https://github.com/iojs/readable-stream/issues/106
* **Original Minutes Google Doc**: https://docs.google.com/document/d/17aTgLnjMXIrfjgNaTUnHQO7m3xgzHR2VXBTmi03Qii4/

## Agenda

Extracted from https://github.com/iojs/readable-stream/labels/wg-agenda prior to meeting.

* adopt a charter [#105](https://github.com/iojs/readable-stream/issues/105)
* release and versioning strategy [#101](https://github.com/iojs/readable-stream/issues/101)
* simpler stream creation [#102](https://github.com/iojs/readable-stream/issues/102)
* proposal: deprecate implicit flowing of streams [#99](https://github.com/iojs/readable-stream/issues/99)

## Minutes

### adopt a charter

* group: +1's all around

### What versioning scheme should be adopted?
* group: +1’s 3.0.0
* domenic+group: pulling in patches from other sources where appropriate
* mikeal: version independently, suggesting versions for io.js
* mikeal+domenic: work with TC to notify in advance of changes
simpler stream creation

### streamline creation of streams
* sam: streamline creation of streams
* domenic: nice simple solution posted
  but, we lose the opportunity to change the model
  may not be backwards incompatible (double check keys)

  **action item:** domenic will check

### remove implicit flowing of streams on(‘data’)
* add isFlowing / isPaused
* mikeal: worrying that we’re documenting polyfill methods – confuses users
* domenic: more reflective API is probably good, with warning labels for users
* new section for mad scientists (reflective stream access)
* calvin: name the “third state”
* mikeal: maybe borrow the name from whatwg?
* domenic: we’re missing the “third state”
* consensus: kind of difficult to name the third state
* mikeal: figure out differences in states / compat
* mathias: always flow on data – eliminates third state
  * explore what it breaks

**action items:**
* ask isaac for ability to list packages by what public io.js APIs they use (esp. Stream)
* ask rod/build for infrastructure
* **chris**: explore the “flow on data” approach
* add isPaused/isFlowing
* add new docs section
* move isPaused to that section


code:
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

// a duplex stream is just a stream that is both readable and writable.
// Since JS doesn't have multiple prototypal inheritance, this class
// prototypally inherits from Readable, and then parasitically from
// Writable.

'use strict';

/*<replacement>*/

var pna = require('process-nextick-args');
/*</replacement>*/

/*<replacement>*/
var objectKeys = Object.keys || function (obj) {
  var keys = [];
  for (var key in obj) {
    keys.push(key);
  }return keys;
};
/*</replacement>*/

module.exports = Duplex;

/*<replacement>*/
var util = Object.create(require('core-util-is'));
util.inherits = require('inherits');
/*</replacement>*/

var Readable = require('./_stream_readable');
var Writable = require('./_stream_writable');

util.inherits(Duplex, Readable);

{
  // avoid scope creep, the keys array can then be collected
  var keys = objectKeys(Writable.prototype);
  for (var v = 0; v < keys.length; v++) {
    var method = keys[v];
    if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
  }
}

function Duplex(options) {
  if (!(this instanceof Duplex)) return new Duplex(options);

  Readable.call(this, options);
  Writable.call(this, options);

  if (options && options.readable === false) this.readable = false;

  if (options && options.writable === false) this.writable = false;

  this.allowHalfOpen = true;
  if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;

  this.once('end', onend);
}

Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
  // making it explicit this property is not enumerable
  // because otherwise some prototype manipulation in
  // userland will fail
  enumerable: false,
  get: function () {
    return this._writableState.highWaterMark;
  }
});

// the no-half-open enforcer
function onend() {
  // if we allow half-open state, or if the writable side ended,
  // then we're ok.
  if (this.allowHalfOpen || this._writableState.ended) return;

  // no more data can be written.
  // But allow more writes to happen in this tick.
  pna.nextTick(onEndNT, this);
}

function onEndNT(self) {
  self.end();
}

Object.defineProperty(Duplex.prototype, 'destroyed', {
  get: function () {
    if (this._readableState === undefined || this._writableState === undefined) {
      return false;
    }
    return this._readableState.destroyed && this._writableState.destroyed;
  },
  set: function (value) {
    // we ignore the value if the stream
    // has not been initialized yet
    if (this._readableState === undefined || this._writableState === undefined) {
      return;
    }

    // backward compatibility, the user is explicitly
    // managing destroyed
    this._readableState.destroyed = value;
    this._writableState.destroyed = value;
  }
});

Duplex.prototype._destroy = function (err, cb) {
  this.push(null);
  this.end();

  pna.nextTick(cb, err);
};


code:
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

// a passthrough stream.
// basically just the most minimal sort of Transform stream.
// Every written chunk gets output as-is.

'use strict';

module.exports = PassThrough;

var Transform = require('./_stream_transform');

/*<replacement>*/
var util = Object.create(require('core-util-is'));
util.inherits = require('inherits');
/*</replacement>*/

util.inherits(PassThrough, Transform);

function PassThrough(options) {
  if (!(this instanceof PassThrough)) return new PassThrough(options);

  Transform.call(this, options);
}

PassThrough.prototype._transform = function (chunk, encoding, cb) {
  cb(null, chunk);
};