Showing preview only (6,497K chars total). Download the full file or copy to clipboard to get everything.
Repository: workshopper/learnyounode
Branch: master
Commit: 6b8b8f16fcfb
Files: 408
Total size: 6.1 MB
Directory structure:
gitextract_5wp5uvc2/
├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── README.vi.md
├── bin/
│ └── learnyounode
├── docs/
│ ├── bl.html
│ ├── concat-stream.html
│ └── through2-map.html
├── docs-nodejs/
│ ├── addons.html
│ ├── assert.html
│ ├── async_hooks.html
│ ├── buffer.html
│ ├── child_process.html
│ ├── cli.html
│ ├── cluster.html
│ ├── console.html
│ ├── crypto.html
│ ├── debugger.html
│ ├── deprecations.html
│ ├── dgram.html
│ ├── dns.html
│ ├── domain.html
│ ├── errors.html
│ ├── esm.html
│ ├── events.html
│ ├── fs.html
│ ├── globals.html
│ ├── http.html
│ ├── http2.html
│ ├── https.html
│ ├── inspector.html
│ ├── intl.html
│ ├── modules.html
│ ├── n-api.html
│ ├── net.html
│ ├── os.html
│ ├── path.html
│ ├── perf_hooks.html
│ ├── policy.html
│ ├── process.html
│ ├── punycode.html
│ ├── querystring.html
│ ├── readline.html
│ ├── repl.html
│ ├── report.html
│ ├── stream.html
│ ├── string_decoder.html
│ ├── timers.html
│ ├── tls.html
│ ├── tracing.html
│ ├── tty.html
│ ├── url.html
│ ├── util.html
│ ├── v8.html
│ ├── vm.html
│ └── worker_threads.html
├── exercises/
│ ├── baby_steps/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── filtered_ls/
│ │ ├── exercise.js
│ │ ├── file-list.json
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── hello_world/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_pt-br/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_tr/
│ │ │ └── solution.js
│ │ └── solution_vi/
│ │ └── solution.js
│ ├── http_client/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_collect/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_file_server/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_json_api_server/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_uppercaserer/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── juggling_async/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── make_it_modular/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ ├── solution.js
│ │ │ └── solution_filter.js
│ │ ├── verify.js
│ │ └── wrap-requires.js
│ ├── my_first_async_io/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_es/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_uk/
│ │ │ └── solution.js
│ │ ├── solution_vi/
│ │ │ └── solution.js
│ │ ├── solution_zh-cn/
│ │ │ └── solution.js
│ │ └── solution_zh-tw/
│ │ └── solution.js
│ ├── my_first_io/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_uk/
│ │ │ └── solution.js
│ │ ├── solution_vi/
│ │ │ └── solution.js
│ │ ├── solution_zh-cn/
│ │ │ └── solution.js
│ │ ├── solution_zh-tw/
│ │ │ └── solution.js
│ │ └── wrap.js
│ └── time_server/
│ ├── exercise.js
│ ├── problem.es.md
│ ├── problem.fr.md
│ ├── problem.it.md
│ ├── problem.ja.md
│ ├── problem.ko.md
│ ├── problem.md
│ ├── problem.nb-no.md
│ ├── problem.pl.md
│ ├── problem.pt-br.md
│ ├── problem.ru.md
│ ├── problem.tr.md
│ ├── problem.uk.md
│ ├── problem.vi.md
│ ├── problem.zh-cn.md
│ ├── problem.zh-tw.md
│ └── solution/
│ └── solution.js
├── i18n/
│ ├── credits/
│ │ └── it.txt
│ ├── en.json
│ ├── es.json
│ ├── fr.json
│ ├── it.json
│ ├── ja.json
│ ├── ko.json
│ ├── nb-no.json
│ ├── pl.json
│ ├── pt-br.json
│ ├── ru.json
│ ├── tr.json
│ ├── uk.json
│ ├── vi.json
│ ├── zh-cn.json
│ └── zh-tw.json
├── learnyounode.js
├── lib/
│ ├── rndport.js
│ └── words.js
├── package.json
├── test/
│ ├── baby_steps/
│ │ ├── invalid_01.js
│ │ └── valid_01.js
│ ├── filtered_ls/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ └── valid_01.js
│ ├── hello_world/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ └── valid_01_ja.js
│ ├── http_client/
│ │ └── valid_01.js
│ ├── http_collect/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ ├── valid_02.js
│ │ ├── valid_03.js
│ │ ├── valid_04.js
│ │ └── valid_05.js
│ ├── http_file_server/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ ├── http_json_api_server/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ ├── http_uppercaserer/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ └── valid_01.js
│ ├── juggling_async/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ └── valid_02.js
│ ├── make_it_modular/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ ├── invalid_04.js
│ │ ├── invalid_05.js
│ │ ├── invalid_06.js
│ │ ├── invalid_07.js
│ │ ├── invalid_08.js
│ │ ├── invalid_09.js
│ │ ├── invalid_10.js
│ │ ├── invalid_11.js
│ │ ├── invalid_12.js
│ │ ├── invalid_13.js
│ │ ├── invalid_14.js
│ │ ├── invalid_15.js
│ │ ├── module_invalid_01.js
│ │ ├── module_invalid_02.js
│ │ ├── module_invalid_03.js
│ │ ├── module_invalid_04.js
│ │ ├── module_invalid_05.js
│ │ ├── module_invalid_06.js
│ │ ├── module_invalid_07.js
│ │ ├── module_invalid_08.js
│ │ ├── module_invalid_09.js
│ │ ├── module_invalid_10.js
│ │ ├── module_invalid_11.js
│ │ ├── module_invalid_12.js
│ │ ├── module_invalid_13.js
│ │ ├── module_invalid_15.js
│ │ ├── module_valid_01.js
│ │ ├── module_valid_02.js
│ │ ├── valid_01.js
│ │ └── valid_02.js
│ ├── my_first_async_io/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── valid_01.js
│ │ ├── valid_02.js
│ │ └── valid_03.js
│ ├── my_first_io/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ └── time_server/
│ ├── invalid_01.js
│ └── valid_01.js
└── tools/
└── download-node-docs.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
package-lock.json
================================================
FILE: .jshintrc
================================================
{
"predef": [ ]
, "bitwise": false
, "camelcase": false
, "curly": false
, "eqeqeq": false
, "forin": false
, "immed": false
, "latedef": false
, "noarg": true
, "noempty": true
, "nonew": true
, "plusplus": false
, "quotmark": true
, "regexp": false
, "undef": true
, "unused": true
, "strict": false
, "trailing": true
, "maxlen": 120
, "asi": true
, "boss": true
, "debug": true
, "eqnull": true
, "esnext": true
, "evil": true
, "expr": true
, "funcscope": false
, "globalstrict": false
, "iterator": false
, "lastsemic": true
, "laxbreak": true
, "laxcomma": true
, "loopfunc": true
, "multistr": false
, "onecase": false
, "proto": false
, "regexdash": false
, "scripturl": true
, "smarttabs": false
, "shadow": false
, "sub": true
, "supernew": false
, "validthis": true
, "browser": true
, "couch": false
, "devel": false
, "dojo": false
, "mootools": false
, "node": true
, "nonstandard": true
, "prototypejs": false
, "rhino": false
, "worker": true
, "wsh": false
, "nomen": false
, "onevar": true
, "passfail": false
}
================================================
FILE: .npmignore
================================================
.jshintrc
.travis.yml
learnyounode.png
test
tools
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- node
- lts/*
sudo: false
os:
- linux
- osx
- windows
================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented from version 4.0.0 forward
in this file.
## 4.0.0 - 2019-09-12
- BREAKING: Dropped Node 8 support
- No more security warnings in production dependencies!
- All code, including in examples uses `const` and `let` instead of `var`
- All code, including in markdown, is `standard` compliant and consistent
- Replace code that uses deprecated 'url' module with `URL` class instead
- Outdated offline docs removed; we now include live links to the nodejs.org docs.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Code contributions are welcome and highly encouraged! For instructions on and help with creating a great pull request, please read the [workshopper contributing document](https://github.com/workshopper/org/blob/master/CONTRIBUTING.md).
If you have questions about contributing, please create an issue.
## Lead Maintainers
The role of lead maintainers is to triage and categorize issues, answer questions about contributing to the repository, review and give feedback on PRs, and maintain the quality of a workshopper's codebase and repository.
[Current Lead Maintainers](https://github.com/orgs/workshopper/teams/learnyounode-leads)
### Volunteer
Submitting many PRs? Please volunteer to lead this repository! Lead maintainers are selected in the philosophy of [Open Open Source](http://openopensource.org/):
> Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit.
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
=====================
Copyright (c) 2013-2015 learnyounode contributors
-------------------------------------------------
*learnyounode contributors listed at <https://github.com/rvagg/learnyounode#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.
================================================
FILE: README.md
================================================
# Learn You The Node.js For Much Win!
[](https://travis-ci.org/workshopper/learnyounode)
[](https://gitter.im/nodeschool/discussions?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](http://standardjs.com/)
[](https://www.codetriage.com/workshopper/learnyounode)
**An intro to Node.js via a set of self-guided workshops.**
[What is Node.js](https://github.com/nodeschool/what-is-node/blob/master/simple.en.md)
[](https://nodei.co/npm/learnyounode/) [](https://nodei.co/npm/learnyounode/)
## What is learnyounode?

<b><code>learnyounode</code></b> is a Node.js package that contains a series of workshop lessons which will teach you the basics of writing Node.js applications. The lessons start with a basic *"HELLO WORLD"* lesson, and then move on to more advanced exercises about dealing with synchronous & asynchronous I/O, filesystem operations, TCP and HTTP networking, events and streams.
## Installing learnyounode
1. Install [Node.js](http://nodejs.org/)
2. Run `npm install -g learnyounode` (this installs the learnyounode Node.js package globally). If this step fails, try one of the following fixes:
- Prefix the install command with sudo:
`sudo npm install -g learnyounode`
or
- [fix your npm permissions](https://docs.npmjs.com/getting-started/fixing-npm-permissions).
3. Test that learnyounode has been installed successfully by running the command `learnyounode` in your terminal. This will start the learnyounode application, and you should see a blue screen similar to the one in the screenshot above.
- (Ubuntu users) In case step 3 fails, run `sudo apt-get install nodejs-legacy`
4. **profit!**
## Completing your first exercise
1. **Start up learnyounode** in your terminal by running the command `learnyounode` (you should see a blue screen similar to the one in the screenshot above).
2. **Start a learnyounode exercise** by using the arrow keys to navigate, and the enter key to select a lesson. For this example, scroll to the "HELLO WORLD" lesson and press enter. This will result in three things happening:
1. The instructions for the "HELLO WORLD" lesson will now be printed out to your terminal (note: You may need to scroll up in your terminal to see the beginning of the lesson instructions if it has been cut off by your terminal window).
2. The `learnyounode verify` command will now be set to verify any script that you pass into it with the expected output of the lesson that you selected (in the case of the "HELLO WORLD" lesson, the command `learnyounode verify` will now check that the script file you pass in satisfies the expected outcomes of the "HELLO WORLD" lesson by making sure the script prints the text "HELLO WORLD" to stdout).
3. The learnyounode application will exit, allowing you to use your terminal again.
3. **Create your solution for the exercise** by creating a new script file named "program.js" and following the instructions and hints that were printed out above for the lesson. For the "HELLO WORLD" lesson, your script "program.js" should have code in it that prints the text "HELLO WORLD" to stdout when run with Node.js (you can test your script file with Node.js by using the command: `node program.js`).
4. **Verify that your solution to the lesson is correct** by running the command `learnyounode verify program.js` (note: if you named your script file something other than "program.js", replace "program.js" with the correct filename). If your solution is not correct, you will see a FAIL message along with some information about why your solution didn't pass the tests. In the case of a FAIL message, rework your solution until running the verify command passes. If your solution passes the tests, you should see a "PASS" message. Congratulations! :)
5. **Move on to the next lesson** if you have verified that your solution is correct. Repeat these instructions from step 1 and select the next lesson that you would like to do (it is suggested to do the lessons in order from top to bottom).
Once you have finished <b><code>learnyounode</code></b>, graduate to <b><code>[stream-adventure](https://github.com/substack/stream-adventure)</code></b> for a set of exercises that dig in to Node's streams.
### Contributors
<b><code>learnyounode</code></b> is proudly brought to you by the following hackers:
<table><tbody>
<tr><th align="left">Rod Vagg</th><td><a href="https://github.com/rvagg">GitHub/rvagg</a></td><td><a href="http://twitter.com/rvagg">Twitter/@rvagg</a></td></tr>
<tr><th align="left">Andrey Sidorov</th><td><a href="https://github.com/sidorares">GitHub/sidorares</a></td><td><a href="http://twitter.com/sidorares">Twitter/@sidorares</a></td></tr>
<tr><th align="left">Julián Duque</th><td><a href="https://github.com/julianduque">GitHub/julianduque</a></td><td><a href="http://twitter.com/julian_duque">Twitter/@julian_duque</a></td></tr>
<tr><th align="left">Lars-Magnus Skog</th><td><a href="https://github.com/ralphtheninja">GitHub/ralphtheninja</a></td><td><a href="http://twitter.com/ralphtheninja">Twitter/@ralphtheninja</a></td></tr>
<tr><th align="left">Tim Inman</th><td><a href="https://github.com/thehack">GitHub/thehack</a></td><td><a href="http://twitter.com/timinman">Twitter/@timinman</a></td></tr>
<tr><th align="left">Dan Flettre</th><td><a href="https://github.com/Flet">GitHub/Flet</a></td><td><a href="http://twitter.com/flettre">Twitter/@flettre</a></td></tr>
<tr><th align="left">Leigh Zhu</th><td><a href="https://github.com/lisposter">GitHub/lisposter</a></td><td><a href="http://twitter.com/lisposter">Twitter/@lisposter</a></td></tr>
<tr><th align="left">Lucas F. da Costa</th><td><a href="https://github.com/lucasfcosta">GitHub/lucasfcosta</a></td><td></td></tr>
<tr><th align="left">Martin Heidegger</th><td><a href="https://github.com/martinheidegger">GitHub/martinheidegger</a></td><td><a href="http://twitter.com/leichtgewicht">Twitter/@leichtgewicht</a></td></tr>
<tr><th align="left">Toshiharu Harada</th><td><a href="https://github.com/haradats">GitHub/haradats</a></td><td><a href="http://twitter.com/haradats">Twitter/@haradats</a></td></tr>
<tr><th align="left">Eric Douglas</th><td><a href="https://github.com/ericdouglas">GitHub/ericdouglas</a></td><td><a href="http://twitter.com/ericdouglas_">Twitter/@ericdouglas_</a></td></tr>
<tr><th align="left">Alejandro Oviedo</th><td><a href="https://github.com/a0viedo">GitHub/a0viedo</a></td><td><a href="http://twitter.com/a0viedo">Twitter/@a0viedo</a></td></tr>
<tr><th align="left">Leonardo Nascimento</th><td><a href="https://github.com/leonascimento">GitHub/leonascimento</a></td><td><a href="http://twitter.com/leonardo386">Twitter/leonardo386</a></td></tr>
<tr><th align="left">Christophe Porteneuve</th><td><a href="https://github.com/tdd">GitHub/tdd</a></td><td><a href="http://twitter.com/porteneuve">Twitter/@porteneuve</a></td></tr>
<tr><th align="left">Do Minh Hai</th><td><a href="https://github.com/dominhhai">GitHub/dominhhai</a></td><td><a href="http://twitter.com/minhhai3b">Twitter/@minhhai3b</a></td></tr>
<tr><th align="left">Phung Van Tu</th><td><a href="https://github.com/minatu2d">GitHub/minatu2d</a></td><td><a href="http://twitter.com/minatu2d">Twitter/@minatu2d</a></td></tr>
<tr><th align="left">Shim</th><td><a href="https://github.com/marocchino">GitHub/marocchino</a></td><td><a href="http://twitter.com/marocchino">Twitter/@marocchino</a></td></tr>
<tr><th align="left">Chayoung You</th><td><a href="https://github.com/yous">GitHub/yous</a></td><td><a href="http://twitter.com/_Yous">Twitter/@_Yous</a></td></tr>
<tr><th align="left">Espen Dalløkken</th><td><a href="https://github.com/leftieFriele">GitHub/leftieFriele</a></td><td><a href="http://twitter.com/leftieFriele">Twitter/leftieFriele</a></td></tr>
</tbody></table>
## License
**learnyounode** is Copyright (c) 2013-2015 learnyounode contributors (listed above) and licenced under the MIT licence. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE.md file for more details.
**learnyounode** builds on the excellent work by [@substack](https://github.com/substack) and [@maxogden](https://github.com/maxogden) who created **[stream-adventure](https://github.com/substack/stream-adventure)** which serves as the original foundation for **learnyounode**.
================================================
FILE: README.vi.md
================================================
# Cho đời phong phú hơn với Node.js!
[](https://travis-ci.org/workshopper/learnyounode)
[](https://gitter.im/nodeschool/discussions?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](http://standardjs.com/)
**Giới thiệu về Node.js qua các bài tập.**
[](https://nodei.co/npm/learnyounode/) [](https://nodei.co/npm/learnyounode/)

1. Cài đặt [Node.js](http://nodejs.org/)
2. Chạy lệnh `sudo npm install learnyounode -g`
3. Chạy lệnh `learnyounode`
4. **.. Nghiệm thu!**
<b><code>learnyounode</code></b> là một tập các bài tập về Node.js. Các bài tập này được sắp xếp theo độ phức tạp từ cơ bản với *"HELLO WORLD"* tới các phần nâng cao hơn như làm việc với xuất/nhập đồng bộ và bất đồng bộ, hệ thống file, lập trình mạng với TCP và HTTP, các sự kiện và dòng dữ liệu.
Sau khi hoàn thành các bài tập phần <b><code>learnyounode</code></b> này, bạn nên tiếp tục làm phần <b><code>[stream-adventure](https://github.com/substack/stream-adventure)</code></b> để hiểu sâu hơn về các dòng dữ liệu của Node.
### Cộng tác viên
<b><code>learnyounode</code></b> tự hào được sự đóng góp của các hacker dưới đây:
<table><tbody>
<tr><th align="left">Rod Vagg</th><td><a href="https://github.com/rvagg">GitHub/rvagg</a></td><td><a href="http://twitter.com/rvagg">Twitter/@rvagg</a></td></tr>
<tr><th align="left">Andrey Sidorov</th><td><a href="https://github.com/sidorares">GitHub/sidorares</a></td><td><a href="http://twitter.com/sidorares">Twitter/@sidorares</a></td></tr>
<tr><th align="left">Julián Duque</th><td><a href="https://github.com/julianduque">GitHub/julianduque</a></td><td><a href="http://twitter.com/julian_duque">Twitter/@julian_duque</a></td></tr>
<tr><th align="left">Lars-Magnus Skog</th><td><a href="https://github.com/ralphtheninja">GitHub/ralphtheninja</a></td><td><a href="http://twitter.com/ralphtheninja">Twitter/@ralphtheninja</a></td></tr>
<tr><th align="left">Tim Inman</th><td><a href="https://github.com/thehack">GitHub/thehack</a></td><td><a href="http://twitter.com/timinman">Twitter/@timinman</a></td></tr>
<tr><th align="left">Dan Flettre</th><td><a href="https://github.com/Flet">GitHub/Flet</a></td><td><a href="http://twitter.com/flettre">Twitter/@flettre</a></td></tr>
<tr><th align="left">Leigh Zhu</th><td><a href="https://github.com/lisposter">GitHub/lisposter</a></td><td><a href="http://twitter.com/lisposter">Twitter/@lisposter</a></td></tr>
<tr><th align="left">Lucas F. da Costa</th><td><a href="https://github.com/lucasfcosta">GitHub/lucasfcosta</a></td><td></td></tr>
<tr><th align="left">Martin Heidegger</th><td><a href="https://github.com/martinheidegger">GitHub/martinheidegger</a></td><td><a href="http://twitter.com/leichtgewicht">Twitter/@leichtgewicht</a></td></tr>
<tr><th align="left">Toshiharu Harada</th><td><a href="https://github.com/haradats">GitHub/haradats</a></td><td><a href="http://twitter.com/haradats">Twitter/@haradats</a></td></tr>
<tr><th align="left">Eric Douglas</th><td><a href="https://github.com/ericdouglas">GitHub/ericdouglas</a></td><td><a href="http://twitter.com/ericdouglas_">Twitter/@ericdouglas_</a></td></tr>
<tr><th align="left">Alejandro Oviedo</th><td><a href="https://github.com/a0viedo">GitHub/a0viedo</a></td><td><a href="http://twitter.com/a0viedo">Twitter/@a0viedo</a></td></tr>
<tr><th align="left">Leonardo Nascimento</th><td><a href="https://github.com/leonascimento">GitHub/leonascimento</a></td><td><a href="http://twitter.com/leonardo386">Twitter/leonardo386</a></td></tr>
<tr><th align="left">Christophe Porteneuve</th><td><a href="https://github.com/tdd">GitHub/tdd</a></td><td><a href="http://twitter.com/porteneuve">Twitter/@porteneuve</a></td></tr>
<tr><th align="left">Do Minh Hai</th><td><a href="https://github.com/dominhhai">GitHub/dominhhai</a></td><td><a href="http://twitter.com/minhhai3b">Twitter/@minhhai3b</a></td></tr>
<tr><th align="left">Phung Van Tu</th><td><a href="https://github.com/minatu2d">GitHub/minatu2d</a></td><td><a href="http://twitter.com/minatu2d">Twitter/@minatu2d</a></td></tr>
</tbody></table>
## Giấy phép
**learnyounode** thuộc bản quyền (c) 2013-2015 cộng tác viên learnyounode (liệt kê phía trên) và cấp phép dưới giấy phép MIT. Tất cả các quyền không rõ ràng được cấp bởi giấy phép MIT sẽ được quy định riêng. Xem thêm file LICENSE.md để biết thêm chi tiết.
**learnyounode** là thành quả dựa trên sự làm việc cần mẫn của 2 lập trình viên [@substack](https://github.com/substack) và [@maxogden](https://github.com/maxogden). Hai lập trình viên tuyệt vời này đã tạo ra **[stream-adventure](https://github.com/substack/stream-adventure)** - một nền tảng cơ bản cho **learnyounode**.
================================================
FILE: bin/learnyounode
================================================
#!/usr/bin/env node
require('../learnyounode').execute(process.argv.slice(2))
================================================
FILE: docs/bl.html
================================================
<!doctype html>
<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="created-with" content="https://github.com/rvagg/gfm2html">
<style type="text/css">
/* most of normalize.css */
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}[hidden],template{display:none;}html{font-family:sans-serif;/*1*/-ms-text-size-adjust:100%;/*2*/-webkit-text-size-adjust:100%;/*2*/}body{margin:0;}a{background:transparent;}a:focus{outline:thindotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em0;}abbr[title]{border-bottom:1pxdotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C""\201D""\2018""\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}table{border-collapse:collapse;border-spacing:0;}
html {
font: 14px 'Helvetica Neue', Helvetica, arial, freesans, clean, sans-serif;
}
.container {
line-height: 1.6;
color: #333;
background: #eee;
border-radius: 3px;
padding: 3px;
width: 790px;
margin: 10px auto;
}
.body-content {
background-color: #fff;
border: 1px solid #CACACA;
padding: 30px;
}
.body-content > *:first-child {
margin-top: 0 !important;
}
a, a:visited {
color: #4183c4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
.markdown-body h1
, .markdown-body h2
, .markdown-body h3
, .markdown-body h4
, .markdown-body h5
, .markdown-body h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
}
h1 {
font-size: 2.5em;
color: #000;
border-bottom: 1px solid #ddd;
}
h2 {
font-size: 2em;
border-bottom: 1px solid #eee;
color: #000;
}
img {
max-width: 100%;
}
hr {
background: transparent url("/img/hr.png") repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
td, th {
border: 1px solid #ccc;
padding: 6px 13px;
}
th {
font-weight: bold;
}
blockquote {
border-left: 4px solid #ddd;
padding: 0 15px;
color: #777;
}
blockquote > :last-child, blockquote > :first-child {
margin-bottom: 0px;
}
pre, code {
font-size: 13px;
font-family: 'UbuntuMono', monospace;
white-space: nowrap;
margin: 0 2px;
padding: 0px 5px;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre > code {
white-space: pre;
}
pre {
overflow-x: auto;
white-space: pre;
padding: 10px;
line-height: 150%;
background-color: #f8f8f8;
border-color: #ccc;
}
pre code, pre tt {
margin: 0;
padding: 0;
border: 0;
background-color: transparent;
border: none;
}
.highlight .c
, .highlight .cm
, .highlight .cp
, .highlight .c1 {
color:#999988;
font-style:italic;
}
.highlight .err {
color:#a61717;
background-color:#e3d2d2
}
.highlight .o
, .highlight .gs
, .highlight .kc
, .highlight .kd
, .highlight .kn
, .highlight .kp
, .highlight .kr {
font-weight:bold
}
.highlight .cs {
color:#999999;
font-weight:bold;
font-style:italic
}
.highlight .gd {
color:#000000;
background-color:#ffdddd
}
.highlight .gd .x {
color:#000000;
background-color:#ffaaaa
}
.highlight .ge {
font-style:italic
}
.highlight .gr
, .highlight .gt {
color:#aa0000
}
.highlight .gh
, .highlight .bp {
color:#999999
}
.highlight .gi {
color:#000000;
background-color:#ddffdd
}
.highlight .gi .x {
color:#000000;
background-color:#aaffaa
}
.highlight .go {
color:#888888
}
.highlight .gp
, .highlight .nn {
color:#555555
}
.highlight .gu {
color:#800080;
font-weight:bold
}
.highlight .kt {
color:#445588;
font-weight:bold
}
.highlight .m
, .highlight .mf
, .highlight .mh
, .highlight .mi
, .highlight .mo
, .highlight .il {
color:#009999
}
.highlight .s
, .highlight .sb
, .highlight .sc
, .highlight .sd
, .highlight .s2
, .highlight .se
, .highlight .sh
, .highlight .si
, .highlight .sx
, .highlight .s1 {
color:#d14
}
.highlight .n {
color:#333333
}
.highlight .na
, .highlight .no
, .highlight .nv
, .highlight .vc
, .highlight .vg
, .highlight .vi
, .highlight .nb {
color:#0086B3
}
.highlight .nc {
color:#445588;
font-weight:bold
}
.highlight .ni {
color:#800080
}
.highlight .ne
, .highlight .nf {
color:#990000;
font-weight:bold
}
.highlight .nt {
color:#000080
}
.highlight .ow {
font-weight:bold
}
.highlight .w {
color:#bbbbbb
}
.highlight .sr {
color:#009926
}
.highlight .ss {
color:#990073
}
.highlight .gc {
color:#999;
background-color:#EAF2F5
}</style>
</head>
<body>
<div class="container">
<div class="body-content"><h1 id="bl-bufferlist-">bl <em>(BufferList)</em></h1>
<p><a href="http://travis-ci.org/rvagg/bl"><img src="https://secure.travis-ci.org/rvagg/bl.png" alt="Build Status"></a></p>
<p><strong>A Node.js Buffer list collector, reader and streamer thingy.</strong></p>
<p><strong>bl</strong> is a storage object for collections of Node Buffers, exposing them with the main Buffer readable API. Also works as a duplex stream so you can collect buffers from a stream that emits them and emit buffers to a stream that consumes them!</p>
<p>The original buffers are kept intact and copies are only done as necessary. Any reads that require the use of a single original buffer will return a slice of that buffer only (which references the same memory as the original buffer). Reads that span buffers perform concatenation as required and return the results transparently.</p>
<div class="highlight"><pre><span class="kr">const</span> <span class="nx">BufferList</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">bl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BufferList</span><span class="p">()</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'abcd'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'efg'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">'hi'</span><span class="p">)</span> <span class="c1">// bl will also accept & convert Strings</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'j'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">([</span> <span class="mh">0x3</span><span class="p">,</span> <span class="mh">0x4</span> <span class="p">]))</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="c1">// 12</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span> <span class="c1">// 'abcdefghij'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">10</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span> <span class="c1">// 'defghij'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span> <span class="c1">// 'def'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">8</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span> <span class="c1">// 'defgh'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span> <span class="c1">// 'fghij'</span>
<span class="c1">// or just use toString!</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="c1">// 'abcdefghij\u0003\u0004'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">8</span><span class="p">))</span> <span class="c1">// 'defgh'</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span> <span class="c1">// 'fghij'</span>
<span class="c1">// other standard Buffer readables</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">readUInt16BE</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span> <span class="c1">// 0x0304</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">readUInt16LE</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span> <span class="c1">// 0x0403</span>
</pre></div>
<p>Give it a callback in the constructor and use it just like <strong><a href="https://github.com/maxogden/node-concat-stream">concat-stream</a></strong>:</p>
<div class="highlight"><pre><span class="kr">const</span> <span class="nx">bl</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="p">,</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">)</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">createReadStream</span><span class="p">(</span><span class="s1">'README.md'</span><span class="p">)</span>
<span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">bl</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// note 'new' isn't strictly required</span>
<span class="c1">// `data` is a complete Buffer object containing the full data</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span>
<span class="p">})</span>
</pre></div>
<p>Note that when you use the <em>callback</em> method like this, the resulting <code>data</code> parameter is a concatenation of all <code>Buffer</code> objects in the list. If you want to avoid the overhead of this concatenation (in cases of extreme performance consciousness), then avoid the <em>callback</em> method and just listen to <code>'end'</code> instead, like a standard Stream.</p>
<p>Or to fetch a URL using <a href="https://github.com/substack/hyperquest">hyperquest</a> (should work with <a href="http://github.com/mikeal/request">request</a> and even plain Node http too!):</p>
<div class="highlight"><pre><span class="kr">const</span> <span class="nx">hyperquest</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'hyperquest'</span><span class="p">)</span>
<span class="p">,</span> <span class="nx">bl</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="p">,</span> <span class="nx">url</span> <span class="o">=</span> <span class="s1">'https://raw.github.com/rvagg/bl/master/README.md'</span>
<span class="nx">hyperquest</span><span class="p">(</span><span class="nx">url</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">bl</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span>
<span class="p">}))</span>
</pre></div>
<p>Or, use it as a readable stream to recompose a list of Buffers to an output source:</p>
<div class="highlight"><pre><span class="kr">const</span> <span class="nx">BufferList</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="p">,</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">bl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BufferList</span><span class="p">()</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'abcd'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'efg'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'hi'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'j'</span><span class="p">))</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">fs</span><span class="p">.</span><span class="nx">createWriteStream</span><span class="p">(</span><span class="s1">'gibberish.txt'</span><span class="p">))</span>
</pre></div>
<h2 id="api">API</h2>
<ul>
<li><a href="#ctor"><code><b>new BufferList([ callback ])</b></code></a></li>
<li><a href="#length"><code>bl.<b>length</b></code></a></li>
<li><a href="#append"><code>bl.<b>append(buffer)</b></code></a></li>
<li><a href="#get"><code>bl.<b>get(index)</b></code></a></li>
<li><a href="#slice"><code>bl.<b>slice([ start[, end ] ])</b></code></a></li>
<li><a href="#copy"><code>bl.<b>copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])</b></code></a></li>
<li><a href="#duplicate"><code>bl.<b>duplicate()</b></code></a></li>
<li><a href="#consume"><code>bl.<b>consume(bytes)</b></code></a></li>
<li><a href="#toString"><code>bl.<b>toString([encoding, [ start, [ end ]]])</b></code></a></li>
<li><a href="#readXX"><code>bl.<b>readDoubleBE()</b></code>, <code>bl.<b>readDoubleLE()</b></code>, <code>bl.<b>readFloatBE()</b></code>, <code>bl.<b>readFloatLE()</b></code>, <code>bl.<b>readInt32BE()</b></code>, <code>bl.<b>readInt32LE()</b></code>, <code>bl.<b>readUInt32BE()</b></code>, <code>bl.<b>readUInt32LE()</b></code>, <code>bl.<b>readInt16BE()</b></code>, <code>bl.<b>readInt16LE()</b></code>, <code>bl.<b>readUInt16BE()</b></code>, <code>bl.<b>readUInt16LE()</b></code>, <code>bl.<b>readInt8()</b></code>, <code>bl.<b>readUInt8()</b></code></a></li>
<li><a href="#streams">Streams</a></li>
</ul>
<hr>
<p><a name="ctor"></a></p>
<h3 id="new-bufferlist-callback-buffer-buffer-array-">new BufferList([ callback | buffer | buffer array ])</h3>
<p>The constructor takes an optional callback, if supplied, the callback will be called with an error argument followed by a reference to the <strong>bl</strong> instance, when <code>bl.end()</code> is called (i.e. from a piped stream). This is a convenient method of collecting the entire contents of a stream, particularly when the stream is <em>chunky</em>, such as a network stream.</p>
<p>Normally, no arguments are required for the constructor, but you can initialise the list by passing in a single <code>Buffer</code> object or an array of <code>Buffer</code> object.</p>
<p><code>new</code> is not strictly required, if you don't instantiate a new object, it will be done automatically for you so you can create a new instance simply with:</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">bl</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">myinstance</span> <span class="o">=</span> <span class="nx">bl</span><span class="p">()</span>
<span class="c1">// equivilant to:</span>
<span class="kd">var</span> <span class="nx">BufferList</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'bl'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">myinstance</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BufferList</span><span class="p">()</span>
</pre></div>
<hr>
<p><a name="length"></a></p>
<h3 id="bl-length">bl.length</h3>
<p>Get the length of the list in bytes. This is the sum of the lengths of all of the buffers contained in the list, minus any initial offset for a semi-consumed buffer at the beginning. Should accurately represent the total number of bytes that can be read from the list.</p>
<hr>
<p><a name="append"></a></p>
<h3 id="bl-append-buffer-">bl.append(buffer)</h3>
<p><code>append(buffer)</code> adds an additional buffer to the internal list.</p>
<hr>
<p><a name="get"></a></p>
<h3 id="bl-get-index-">bl.get(index)</h3>
<p><code>get()</code> will return the byte at the specified index.</p>
<hr>
<p><a name="slice"></a></p>
<h3 id="bl-slice-start-end-">bl.slice([ start, [ end ] ])</h3>
<p><code>slice()</code> returns a new <code>Buffer</code> object containing the bytes within the range specified. Both <code>start</code> and <code>end</code> are optional and will default to the beginning and end of the list respectively.</p>
<p>If the requested range spans a single internal buffer then a slice of that buffer will be returned which shares the original memory range of that Buffer. If the range spans multiple buffers then copy operations will likely occur to give you a uniform Buffer.</p>
<hr>
<p><a name="copy"></a></p>
<h3 id="bl-copy-dest-deststart-srcstart-srcend-">bl.copy(dest, [ destStart, [ srcStart [, srcEnd ] ] ])</h3>
<p><code>copy()</code> copies the content of the list in the <code>dest</code> buffer, starting from <code>destStart</code> and containing the bytes within the range specified with <code>srcStart</code> to <code>srcEnd</code>. <code>destStart</code>, <code>start</code> and <code>end</code> are optional and will default to the beginning of the <code>dest</code> buffer, and the beginning and end of the list respectively.</p>
<hr>
<p><a name="duplicate"></a></p>
<h3 id="bl-duplicate-">bl.duplicate()</h3>
<p><code>duplicate()</code> performs a <strong>shallow-copy</strong> of the list. The internal Buffers remains the same, so if you change the underlying Buffers, the change will be reflected in both the original and the duplicate. This method is needed if you want to call <code>consume()</code> or <code>pipe()</code> and still keep the original list.Example:</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">bl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BufferList</span><span class="p">()</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">'hello'</span><span class="p">)</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">' world'</span><span class="p">)</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">'\n'</span><span class="p">)</span>
<span class="nx">bl</span><span class="p">.</span><span class="nx">duplicate</span><span class="p">().</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">,</span> <span class="p">{</span> <span class="nx">end</span><span class="o">:</span> <span class="kc">false</span> <span class="p">})</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bl</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span>
</pre></div>
<hr>
<p><a name="consume"></a></p>
<h3 id="bl-consume-bytes-">bl.consume(bytes)</h3>
<p><code>consume()</code> will shift bytes <em>off the start of the list</em>. The number of bytes consumed don't need to line up with the sizes of the internal Buffers—initial offsets will be calculated accordingly in order to give you a consistent view of the data.</p>
<hr>
<p><a name="toString"></a></p>
<h3 id="bl-tostring-encoding-start-end-">bl.toString([encoding, [ start, [ end ]]])</h3>
<p><code>toString()</code> will return a string representation of the buffer. The optional <code>start</code> and <code>end</code> arguments are passed on to <code>slice()</code>, while the <code>encoding</code> is passed on to <code>toString()</code> of the resulting Buffer. See the <a href="http://nodejs.org/docs/latest/api/buffer.html#buffer_buf_tostring_encoding_start_end">Buffer#toString()</a> documentation for more information.</p>
<hr>
<p><a name="readXX"></a></p>
<h3 id="-code-bl-readdoublebe-code-code-bl-readdoublele-code-code-bl-readfloatbe-code-code-bl-readfloatle-code-code-bl-readint32be-code-code-bl-readint32le-code-code-bl-readuint32be-code-code-bl-readuint32le-code-code-bl-readint16be-code-code-bl-readint16le-code-code-bl-readuint16be-code-code-bl-readuint16le-code-code-bl-readint8-code-code-bl-readuint8-code-"><code>bl.readDoubleBE()</code>, <code>bl.readDoubleLE()</code>, <code>bl.readFloatBE()</code>, <code>bl.readFloatLE()</code>, <code>bl.readInt32BE()</code>, <code>bl.readInt32LE()</code>, <code>bl.readUInt32BE()</code>, <code>bl.readUInt32LE()</code>, <code>bl.readInt16BE()</code>, <code>bl.readInt16LE()</code>, <code>bl.readUInt16BE()</code>, <code>bl.readUInt16LE()</code>, <code>bl.readInt8()</code>, <code>bl.readUInt8()</code></h3>
<p>All of the standard byte-reading methods of the <code>Buffer</code> interface are implemented and will operate across internal Buffer boundaries transparently.</p>
<p>See the <b><code><a href="http://nodejs.org/docs/latest/api/buffer.html">Buffer</a></code></b> documentation for how these work.</p>
<hr>
<p><a name="streams"></a></p>
<h3 id="streams">Streams</h3>
<p><strong>bl</strong> is a Node <strong><a href="http://nodejs.org/docs/latest/api/stream.html#stream_class_stream_duplex">Duplex Stream</a></strong>, so it can be read from and written to like a standard Node stream. You can also <code>pipe()</code> to and from a <strong>bl</strong> instance.</p>
<hr>
<h2 id="contributors">Contributors</h2>
<p><strong>bl</strong> is brought to you by the following hackers:</p>
<ul>
<li><a href="https://github.com/rvagg">Rod Vagg</a></li>
<li><a href="https://github.com/mcollina">Matteo Collina</a></li>
</ul>
<p>=======</p>
<h2 id="license">License</h2>
<p><strong>bl</strong> is Copyright (c) 2013 Rod Vagg <a href="https://twitter.com/rvagg">@rvagg</a> and licenced under the MIT licence. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.</p>
</div>
</div>
</body>
</html>
================================================
FILE: docs/concat-stream.html
================================================
<!doctype html>
<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="created-with" content="https://github.com/rvagg/gfm2html">
<style type="text/css">
/* most of normalize.css */
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}[hidden],template{display:none;}html{font-family:sans-serif;/*1*/-ms-text-size-adjust:100%;/*2*/-webkit-text-size-adjust:100%;/*2*/}body{margin:0;}a{background:transparent;}a:focus{outline:thindotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em0;}abbr[title]{border-bottom:1pxdotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C""\201D""\2018""\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}table{border-collapse:collapse;border-spacing:0;}
html {
font: 14px 'Helvetica Neue', Helvetica, arial, freesans, clean, sans-serif;
}
.container {
line-height: 1.6;
color: #333;
background: #eee;
border-radius: 3px;
padding: 3px;
width: 790px;
margin: 10px auto;
}
.body-content {
background-color: #fff;
border: 1px solid #CACACA;
padding: 30px;
}
.body-content > *:first-child {
margin-top: 0 !important;
}
a, a:visited {
color: #4183c4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
.markdown-body h1
, .markdown-body h2
, .markdown-body h3
, .markdown-body h4
, .markdown-body h5
, .markdown-body h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
}
h1 {
font-size: 2.5em;
color: #000;
border-bottom: 1px solid #ddd;
}
h2 {
font-size: 2em;
border-bottom: 1px solid #eee;
color: #000;
}
img {
max-width: 100%;
}
hr {
background: transparent url("/img/hr.png") repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
td, th {
border: 1px solid #ccc;
padding: 6px 13px;
}
th {
font-weight: bold;
}
blockquote {
border-left: 4px solid #ddd;
padding: 0 15px;
color: #777;
}
blockquote > :last-child, blockquote > :first-child {
margin-bottom: 0px;
}
pre, code {
font-size: 13px;
font-family: 'UbuntuMono', monospace;
white-space: nowrap;
margin: 0 2px;
padding: 0px 5px;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre > code {
white-space: pre;
}
pre {
overflow-x: auto;
white-space: pre;
padding: 10px;
line-height: 150%;
background-color: #f8f8f8;
border-color: #ccc;
}
pre code, pre tt {
margin: 0;
padding: 0;
border: 0;
background-color: transparent;
border: none;
}
.highlight .c
, .highlight .cm
, .highlight .cp
, .highlight .c1 {
color:#999988;
font-style:italic;
}
.highlight .err {
color:#a61717;
background-color:#e3d2d2
}
.highlight .o
, .highlight .gs
, .highlight .kc
, .highlight .kd
, .highlight .kn
, .highlight .kp
, .highlight .kr {
font-weight:bold
}
.highlight .cs {
color:#999999;
font-weight:bold;
font-style:italic
}
.highlight .gd {
color:#000000;
background-color:#ffdddd
}
.highlight .gd .x {
color:#000000;
background-color:#ffaaaa
}
.highlight .ge {
font-style:italic
}
.highlight .gr
, .highlight .gt {
color:#aa0000
}
.highlight .gh
, .highlight .bp {
color:#999999
}
.highlight .gi {
color:#000000;
background-color:#ddffdd
}
.highlight .gi .x {
color:#000000;
background-color:#aaffaa
}
.highlight .go {
color:#888888
}
.highlight .gp
, .highlight .nn {
color:#555555
}
.highlight .gu {
color:#800080;
font-weight:bold
}
.highlight .kt {
color:#445588;
font-weight:bold
}
.highlight .m
, .highlight .mf
, .highlight .mh
, .highlight .mi
, .highlight .mo
, .highlight .il {
color:#009999
}
.highlight .s
, .highlight .sb
, .highlight .sc
, .highlight .sd
, .highlight .s2
, .highlight .se
, .highlight .sh
, .highlight .si
, .highlight .sx
, .highlight .s1 {
color:#d14
}
.highlight .n {
color:#333333
}
.highlight .na
, .highlight .no
, .highlight .nv
, .highlight .vc
, .highlight .vg
, .highlight .vi
, .highlight .nb {
color:#0086B3
}
.highlight .nc {
color:#445588;
font-weight:bold
}
.highlight .ni {
color:#800080
}
.highlight .ne
, .highlight .nf {
color:#990000;
font-weight:bold
}
.highlight .nt {
color:#000080
}
.highlight .ow {
font-weight:bold
}
.highlight .w {
color:#bbbbbb
}
.highlight .sr {
color:#009926
}
.highlight .ss {
color:#990073
}
.highlight .gc {
color:#999;
background-color:#EAF2F5
}</style>
</head>
<body>
<div class="container">
<div class="body-content"><h1 id="concat-stream">concat-stream</h1>
<div class="highlight"><pre><span class="nv">$ </span>npm install concat-stream
</pre></div>
<p>then</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">concat</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'concat-stream'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">read</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">createReadStream</span><span class="p">(</span><span class="s1">'readme.md'</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">write</span> <span class="o">=</span> <span class="nx">concat</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{})</span>
<span class="nx">read</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">write</span><span class="p">)</span>
</pre></div>
<p>works with arrays too!</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">write</span> <span class="o">=</span> <span class="nx">concat</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{})</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">write</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">])</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">write</span><span class="p">([</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">])</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span>
<span class="c1">// data will be [1,2,3,4,5,6] in the above callback</span>
</pre></div>
<p>works with buffers too! can't believe the deals!</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">write</span> <span class="o">=</span> <span class="nx">concat</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{})</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'hello '</span><span class="p">))</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s1">'world'</span><span class="p">))</span>
<span class="nx">write</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span>
<span class="c1">// data will be a buffer that toString()s to 'hello world' in the above callback</span>
</pre></div>
<p>MIT LICENSE</p>
</div>
</div>
</body>
</html>
================================================
FILE: docs/through2-map.html
================================================
<!doctype html>
<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="created-with" content="https://github.com/rvagg/gfm2html">
<style type="text/css">
/* most of normalize.css */
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}[hidden],template{display:none;}html{font-family:sans-serif;/*1*/-ms-text-size-adjust:100%;/*2*/-webkit-text-size-adjust:100%;/*2*/}body{margin:0;}a{background:transparent;}a:focus{outline:thindotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em0;}abbr[title]{border-bottom:1pxdotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C""\201D""\2018""\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}table{border-collapse:collapse;border-spacing:0;}
html {
font: 14px 'Helvetica Neue', Helvetica, arial, freesans, clean, sans-serif;
}
.container {
line-height: 1.6;
color: #333;
background: #eee;
border-radius: 3px;
padding: 3px;
width: 790px;
margin: 10px auto;
}
.body-content {
background-color: #fff;
border: 1px solid #CACACA;
padding: 30px;
}
.body-content > *:first-child {
margin-top: 0 !important;
}
a, a:visited {
color: #4183c4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
.markdown-body h1
, .markdown-body h2
, .markdown-body h3
, .markdown-body h4
, .markdown-body h5
, .markdown-body h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
}
h1 {
font-size: 2.5em;
color: #000;
border-bottom: 1px solid #ddd;
}
h2 {
font-size: 2em;
border-bottom: 1px solid #eee;
color: #000;
}
img {
max-width: 100%;
}
hr {
background: transparent url("/img/hr.png") repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
td, th {
border: 1px solid #ccc;
padding: 6px 13px;
}
th {
font-weight: bold;
}
blockquote {
border-left: 4px solid #ddd;
padding: 0 15px;
color: #777;
}
blockquote > :last-child, blockquote > :first-child {
margin-bottom: 0px;
}
pre, code {
font-size: 13px;
font-family: 'UbuntuMono', monospace;
white-space: nowrap;
margin: 0 2px;
padding: 0px 5px;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre > code {
white-space: pre;
}
pre {
overflow-x: auto;
white-space: pre;
padding: 10px;
line-height: 150%;
background-color: #f8f8f8;
border-color: #ccc;
}
pre code, pre tt {
margin: 0;
padding: 0;
border: 0;
background-color: transparent;
border: none;
}
.highlight .c
, .highlight .cm
, .highlight .cp
, .highlight .c1 {
color:#999988;
font-style:italic;
}
.highlight .err {
color:#a61717;
background-color:#e3d2d2
}
.highlight .o
, .highlight .gs
, .highlight .kc
, .highlight .kd
, .highlight .kn
, .highlight .kp
, .highlight .kr {
font-weight:bold
}
.highlight .cs {
color:#999999;
font-weight:bold;
font-style:italic
}
.highlight .gd {
color:#000000;
background-color:#ffdddd
}
.highlight .gd .x {
color:#000000;
background-color:#ffaaaa
}
.highlight .ge {
font-style:italic
}
.highlight .gr
, .highlight .gt {
color:#aa0000
}
.highlight .gh
, .highlight .bp {
color:#999999
}
.highlight .gi {
color:#000000;
background-color:#ddffdd
}
.highlight .gi .x {
color:#000000;
background-color:#aaffaa
}
.highlight .go {
color:#888888
}
.highlight .gp
, .highlight .nn {
color:#555555
}
.highlight .gu {
color:#800080;
font-weight:bold
}
.highlight .kt {
color:#445588;
font-weight:bold
}
.highlight .m
, .highlight .mf
, .highlight .mh
, .highlight .mi
, .highlight .mo
, .highlight .il {
color:#009999
}
.highlight .s
, .highlight .sb
, .highlight .sc
, .highlight .sd
, .highlight .s2
, .highlight .se
, .highlight .sh
, .highlight .si
, .highlight .sx
, .highlight .s1 {
color:#d14
}
.highlight .n {
color:#333333
}
.highlight .na
, .highlight .no
, .highlight .nv
, .highlight .vc
, .highlight .vg
, .highlight .vi
, .highlight .nb {
color:#0086B3
}
.highlight .nc {
color:#445588;
font-weight:bold
}
.highlight .ni {
color:#800080
}
.highlight .ne
, .highlight .nf {
color:#990000;
font-weight:bold
}
.highlight .nt {
color:#000080
}
.highlight .ow {
font-weight:bold
}
.highlight .w {
color:#bbbbbb
}
.highlight .sr {
color:#009926
}
.highlight .ss {
color:#990073
}
.highlight .gc {
color:#999;
background-color:#EAF2F5
}</style>
</head>
<body>
<div class="container">
<div class="body-content"><h1 id="through2-map">through2-map</h1>
<p><a href="https://nodei.co/npm/through2-map/"><img src="https://nodei.co/npm/through2-map.png" alt="NPM"></a></p>
<p>This is a super thin wrapper around <a href="https://npmjs.com/through2">through2</a> that works like <code>Array.prototype.map</code> but for streams.</p>
<p>For when through2 is just too verbose :wink:</p>
<p>Note you will <strong>NOT</strong> be able to skip chunks. This is intended for modification only. If you want filter the stream content, use either <code>through2</code> or <code>through2-filter</code>.</p>
<p><strong>IMPORTANT:</strong> If you return <code>null</code> from your function, the stream will end there.</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">map</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">"through2-map"</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">truncate</span> <span class="o">=</span> <span class="nx">map</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">chunk</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="p">})</span>
<span class="c1">// vs. with through2:</span>
<span class="kd">var</span> <span class="nx">truncate</span> <span class="o">=</span> <span class="nx">through2</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">,</span> <span class="nx">encoding</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">chunk</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">()</span>
<span class="p">})</span>
<span class="c1">// Then use your map:</span>
<span class="nx">source</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">truncate</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">sink</span><span class="p">)</span>
<span class="c1">// Additionally accepts `wantStrings` argument to conver buffers into strings</span>
<span class="kd">var</span> <span class="nx">stripTags</span> <span class="o">=</span> <span class="nx">map</span><span class="p">({</span><span class="nx">wantStrings</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">str</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// OMG don't actually use this</span>
<span class="k">return</span> <span class="nx">str</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/<.*?>/g</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
<span class="p">})</span>
<span class="c1">// Works like `Array.prototype.map` meaning you can specify a function that</span>
<span class="c1">// takes up to two* arguments: fn(chunk, index)</span>
<span class="kd">var</span> <span class="nx">spaceout</span> <span class="o">=</span> <span class="nx">map</span><span class="p">({</span><span class="nx">wantStrings</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">index</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="o">?</span> <span class="nx">chunk</span> <span class="o">+</span> <span class="s2">"\n\n"</span> <span class="o">:</span> <span class="nx">chunk</span>
<span class="p">})</span>
<span class="c1">// vs. with through2:</span>
<span class="kd">var</span> <span class="nx">spaceout</span> <span class="o">=</span> <span class="nx">through2</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">,</span> <span class="nx">encoding</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">index</span> <span class="o">==</span> <span class="kc">undefined</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">index</span> <span class="o">=</span> <span class="mi">0</span>
<span class="kd">var</span> <span class="nx">buf</span> <span class="o">=</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">index</span><span class="o">++</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="o">?</span> <span class="nx">Buffer</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">chunk</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Buffer</span><span class="p">(</span><span class="s2">"\n\n"</span><span class="p">))</span> <span class="o">:</span> <span class="nx">chunk</span>
<span class="k">this</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">buf</span><span class="p">)</span>
<span class="k">return</span> <span class="nx">callback</span><span class="p">()</span>
<span class="p">})</span>
</pre></div>
<p>*Differences from <code>Array.prototype.map</code>:</p>
<ul>
<li>Cannot insert <code>null</code> elements into the stream without aborting.</li>
<li>No third <code>array</code> callback argument. That would require realizing the entire stream, which is generally counter-productive to stream operations.</li>
<li><code>Array.prototype.map</code> doesn't modify the source Array, which is somewhat nonsensical when applied to streams.</li>
</ul>
<h2 id="options">Options</h2>
<ul>
<li>wantStrings: Automatically call chunk.toString() for the super lazy.</li>
<li>all other through2 options</li>
</ul>
<h1 id="license">LICENSE</h1>
<p>MIT</p>
</div>
</div>
</body>
</html>
================================================
FILE: docs-nodejs/addons.html
================================================
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>C++ Addons | Node.js v12.10.0 Documentation</title>
<link rel="stylesheet" href="data:text/css;base64,LyogbGF0aW4tZXh0ICovCkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnTGF0byc7CiAgZm9udC1zdHlsZTogaXRhbGljOwogIGZvbnQtd2VpZ2h0OiA0MDA7CiAgc3JjOiBsb2NhbCgnTGF0byBJdGFsaWMnKSwgbG9jYWwoJ0xhdG8tSXRhbGljJyksIHVybChodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tL3MvbGF0by92MTYvUzZ1OHc0Qk1VVFBIanhzQVVpLXFOaVhnN2VVMC53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEl0YWxpYycpLCBsb2NhbCgnTGF0by1JdGFsaWMnKSwgdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9sYXRvL3YxNi9TNnU4dzRCTVVUUEhqeHNBWEMtcU5pWGc3US53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDAwMC0wMEZGLCBVKzAxMzEsIFUrMDE1Mi0wMTUzLCBVKzAyQkItMDJCQywgVSswMkM2LCBVKzAyREEsIFUrMDJEQywgVSsyMDAwLTIwNkYsIFUrMjA3NCwgVSsyMEFDLCBVKzIxMjIsIFUrMjE5MSwgVSsyMTkzLCBVKzIyMTIsIFUrMjIxNSwgVStGRUZGLCBVK0ZGRkQ7Cn0KLyogbGF0aW4tZXh0ICovCkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnTGF0byc7CiAgZm9udC1zdHlsZTogbm9ybWFsOwogIGZvbnQtd2VpZ2h0OiA0MDA7CiAgc3JjOiBsb2NhbCgnTGF0byBSZWd1bGFyJyksIGxvY2FsKCdMYXRvLVJlZ3VsYXInKSwgdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9sYXRvL3YxNi9TNnV5dzRCTVVUUEhqeEF3WGlXdEZDZlE3QS53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBzcmM6IGxvY2FsKCdMYXRvIFJlZ3VsYXInKSwgbG9jYWwoJ0xhdG8tUmVndWxhcicpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dXl3NEJNVVRQSGp4NHdYaVd0RkNjLndvZmYyKSBmb3JtYXQoJ3dvZmYyJyk7CiAgdW5pY29kZS1yYW5nZTogVSswMDAwLTAwRkYsIFUrMDEzMSwgVSswMTUyLTAxNTMsIFUrMDJCQi0wMkJDLCBVKzAyQzYsIFUrMDJEQSwgVSswMkRDLCBVKzIwMDAtMjA2RiwgVSsyMDc0LCBVKzIwQUMsIFUrMjEyMiwgVSsyMTkxLCBVKzIxOTMsIFUrMjIxMiwgVSsyMjE1LCBVK0ZFRkYsIFUrRkZGRDsKfQovKiBsYXRpbi1leHQgKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEJvbGQnKSwgbG9jYWwoJ0xhdG8tQm9sZCcpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dTl3NEJNVVRQSGg2VVZTd2FQR1EzcTVkME43dy53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEJvbGQnKSwgbG9jYWwoJ0xhdG8tQm9sZCcpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dTl3NEJNVVRQSGg2VVZTd2lQR1EzcTVkMC53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDAwMC0wMEZGLCBVKzAxMzEsIFUrMDE1Mi0wMTUzLCBVKzAyQkItMDJCQywgVSswMkM2LCBVKzAyREEsIFUrMDJEQywgVSsyMDAwLTIwNkYsIFUrMjA3NCwgVSsyMEFDLCBVKzIxMjIsIFUrMjE5MSwgVSsyMTkzLCBVKzIyMTIsIFUrMjIxNSwgVStGRUZGLCBVK0ZGRkQ7Cn0K">
<link rel="stylesheet" href="data:text/css;base64,LyotLS0tLS0tLS0tLS0tLS0tLS0tLS0gTGF5b3V0IGFuZCBUeXBvZ3JhcGh5IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qLwpodG1sIHsKICBmb250LXNpemU6IDFyZW07CiAgb3ZlcmZsb3ctd3JhcDogYnJlYWstd29yZDsKICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDsKICAtbW96LW9zeC1mb250LXNtb290aGluZzogZ3JheXNjYWxlOwogIC13ZWJraXQtZm9udC12YXJpYW50LWxpZ2F0dXJlczogbm9uZTsKICAgICAgICAgIGZvbnQtdmFyaWFudC1saWdhdHVyZXM6IG5vbmU7Cn0KCiogewogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7Cn0KCmJvZHkgewogIGZvbnQtZmFtaWx5OiAiTGF0byIsICJMdWNpZGEgR3JhbmRlIiwgIkx1Y2lkYSBTYW5zIFVuaWNvZGUiLCAiTHVjaWRhIFNhbnMiLCBWZXJkYW5hLCBUYWhvbWEsIHNhbnMtc2VyaWY7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDA7CiAgY29sb3I6ICMzMzM7CiAgYmFja2dyb3VuZDogI2ZmZjsKfQoKaDEgeyBmb250LXNpemU6IDIuNXJlbSB9CmgyIHsgZm9udC1zaXplOiAycmVtIH0KaDMgeyBmb250LXNpemU6IDEuNzVyZW0gfQpoNCB7IGZvbnQtc2l6ZTogMS41cmVtIH0KaDUgeyBmb250LXNpemU6IDEuMjVyZW0gfQpoNiB7IGZvbnQtc2l6ZTogMXJlbSB9CgpoMSwgaDIsIGgzLCBoNCwgaDUsIGg2IHsKICBtYXJnaW46IDEuNXJlbSAwIDFyZW07CiAgdGV4dC1yZW5kZXJpbmc6IG9wdGltaXplTGVnaWJpbGl0eTsKICBmb250LXdlaWdodDogNzAwOwogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKcHJlLCB0dCwgY29kZSwgLnByZSwgc3Bhbi50eXBlLCBhLnR5cGUgewogIGZvbnQtZmFtaWx5OiBTRk1vbm8tUmVndWxhciwgTWVubG8sIENvbnNvbGFzLCAiTGliZXJhdGlvbiBNb25vIiwgIkNvdXJpZXIgTmV3IiwgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogLjllbTsKfQoKI2NvbnRlbnQgewogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKYSwgYTpsaW5rLCBhOmFjdGl2ZSB7CiAgY29sb3I6ICM0Mzg1M2Q7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGJvcmRlci1yYWRpdXM6IDJweDsKICBwYWRkaW5nOiAxcHggM3B4Owp9CgphOmhvdmVyLCBhOmZvY3VzIHsKICBjb2xvcjogI2ZmZjsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjNDM4NTNkOwogIG91dGxpbmU6IG5vbmU7Cn0KCnN0cm9uZyB7CiAgZm9udC13ZWlnaHQ6IDcwMDsKfQoKY29kZSBhOmhvdmVyIHsKICBiYWNrZ3JvdW5kOiBub25lOwp9CgplbSBjb2RlIHsKICBmb250LXN0eWxlOiBub3JtYWw7Cn0KCiNjaGFuZ2Vsb2cgI2d0b2MgewogIGRpc3BsYXk6IG5vbmU7Cn0KCiNndG9jIHsKICBtYXJnaW4tdG9wOiAuNXJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwp9CgojZ3RvYyB1bCB7CiAgbGlzdC1zdHlsZTogbm9uZTsKICBtYXJnaW4tbGVmdDogMDsKICBsaW5lLWhlaWdodDogMS41cmVtOwp9CgojZ3RvYyA+IHVsID4gbGkgewogIGRpc3BsYXk6IGlubGluZTsKICBib3JkZXItcmlnaHQ6IDFweCAjMDAwIHNvbGlkOwogIG1hcmdpbi1yaWdodDogMC40cmVtOwogIHBhZGRpbmctcmlnaHQ6IDAuNHJlbTsKfQoKI2d0b2MgPiB1bCA+IGxpOmxhc3QtY2hpbGQgewogIGJvcmRlci1yaWdodDogbm9uZTsKICBtYXJnaW4tcmlnaHQ6IDA7CiAgcGFkZGluZy1yaWdodDogMDsKfQoKbGkudmVyc2lvbi1waWNrZXIgewogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKbGkudmVyc2lvbi1waWNrZXI6aG92ZXIgPiBhIHsKICBib3JkZXItcmFkaXVzOiAycHggMnB4IDAgMDsKfQoKbGkudmVyc2lvbi1waWNrZXI6aG92ZXIgPiBvbCB7CiAgZGlzcGxheTogYmxvY2s7CiAgei1pbmRleDogMTsKfQoKbGkudmVyc2lvbi1waWNrZXIgYSBzcGFuIHsKICBmb250LXNpemU6IC43cmVtOwp9CgpvbC52ZXJzaW9uLXBpY2tlciB7CiAgYmFja2dyb3VuZDogI2ZmZjsKICBib3JkZXI6IDFweCAjNDM4NTNkIHNvbGlkOwogIGJvcmRlci1yYWRpdXM6IDAgMCAycHggMnB4OwogIGRpc3BsYXk6IG5vbmU7CiAgbGlzdC1zdHlsZTogbm9uZTsKICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgcmlnaHQ6IDA7CiAgdG9wOiAxLjI1cmVtOwogIHdpZHRoOiAxMDAlOwp9CgojZ3RvYyBvbC52ZXJzaW9uLXBpY2tlciBsaSB7CiAgZGlzcGxheTogYmxvY2s7CiAgYm9yZGVyLXJpZ2h0OiAwOwogIG1hcmdpbi1yaWdodDogMDsKfQoKb2wudmVyc2lvbi1waWNrZXIgbGkgYSB7CiAgYm9yZGVyLXJhZGl1czogMDsKICBkaXNwbGF5OiBibG9jazsKICBtYXJnaW46IDA7CiAgcGFkZGluZzogLjFyZW07CiAgcGFkZGluZy1sZWZ0OiAxcmVtOwp9CgpvbC52ZXJzaW9uLXBpY2tlciBsaTpsYXN0LWNoaWxkIGEgewogIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAxcHg7CiAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogMXB4Owp9CgoubGluZSB7CiAgd2lkdGg6IGNhbGMoMTAwJSAtIDFyZW0pOwogIGRpc3BsYXk6IGJsb2NrOwogIHBhZGRpbmctYm90dG9tOiAxcHg7Cn0KCi5hcGlfc3RhYmlsaXR5IHsKICBjb2xvcjogd2hpdGUgIWltcG9ydGFudDsKICBtYXJnaW46IDAgMCAxcmVtIDA7CiAgZm9udC1mYW1pbHk6ICJMYXRvIiwgIkx1Y2lkYSBHcmFuZGUiLCAiTHVjaWRhIFNhbnMgVW5pY29kZSIsICJMdWNpZGEgU2FucyIsIFZlcmRhbmEsIFRhaG9tYSwgc2Fucy1zZXJpZjsKICBwYWRkaW5nOiAxcmVtOwogIGxpbmUtaGVpZ2h0OiAxLjU7Cn0KCi5hcGlfc3RhYmlsaXR5ICogewogIGNvbG9yOiB3aGl0ZSAhaW1wb3J0YW50Owp9CgouYXBpX3N0YWJpbGl0eSBhIHsKICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsKfQoKLmFwaV9zdGFiaWxpdHkgYTpob3ZlciwgLmFwaV9zdGFiaWxpdHkgYTphY3RpdmUsIC5hcGlfc3RhYmlsaXR5IGE6Zm9jdXMgewogIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDI1NSwgLjQpOwp9CgouYXBpX3N0YWJpbGl0eSBhIGNvZGUgewogIGJhY2tncm91bmQ6IG5vbmU7Cn0KCi5hcGlfc3RhYmlsaXR5XzAgewogIGJhY2tncm91bmQtY29sb3I6ICNENjAwMjc7Cn0KCi5hcGlfc3RhYmlsaXR5XzEgewogIGJhY2tncm91bmQtY29sb3I6ICNFQzUzMTU7Cn0KCi5hcGlfc3RhYmlsaXR5XzIgewogIGJhY2tncm91bmQtY29sb3I6ICM0RUJBMEY7Cn0KCi5hcGlfbWV0YWRhdGEgewogIGZvbnQtc2l6ZTogLjg1cmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07Cn0KCi5hcGlfbWV0YWRhdGEgc3BhbiB7CiAgbWFyZ2luLXJpZ2h0OiAxcmVtOwp9CgouYXBpX21ldGFkYXRhIHNwYW46bGFzdC1jaGlsZCB7CiAgbWFyZ2luLXJpZ2h0OiAwcHg7Cn0KCnVsLnBsYWluIHsKICBsaXN0LXN0eWxlOiBub25lOwp9CgphYmJyIHsKICBib3JkZXItYm90dG9tOiAxcHggZG90dGVkICM0NTQ1NDU7Cn0KCnAgewogIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7CiAgbWFyZ2luOiAwIDAgMS4xMjVyZW0gMDsKICBsaW5lLWhlaWdodDogMS41Owp9CgojYXBpY29udGVudCA+ICo6bGFzdC1jaGlsZCB7CiAgbWFyZ2luLWJvdHRvbTogMDsKICBwYWRkaW5nLWJvdHRvbTogMnJlbTsKfQoKdGFibGUgewogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7CiAgbWFyZ2luOiAwIDAgMS41cmVtIDA7Cn0KCnRoLCB0ZCB7CiAgYm9yZGVyOiAxcHggc29saWQgI2FhYTsKICBwYWRkaW5nOiAuNzVyZW0gMXJlbSAuNzVyZW0gMXJlbTsKICB2ZXJ0aWNhbC1hbGlnbjogdG9wOwp9Cgp0aCB7CiAgdGV4dC1hbGlnbjpsZWZ0Owp9CgpvbCwgdWwsIGRsIHsKICBtYXJnaW46IDAgMCAuNnJlbSAwOwogIHBhZGRpbmc6IDA7Cn0KCm9sIHVsLCBvbCBvbCwgb2wgZGwsIHVsIHVsLCB1bCBvbCwgdWwgZGwsIGRsIHVsLCBkbCBvbCwgZGwgZGwgewogIG1hcmdpbi1ib3R0b206IDA7Cn0KCnVsLCBvbCB7CiAgbWFyZ2luLWxlZnQ6IDJyZW07Cn0KCmRsIGR0IHsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgbWFyZ2luOiAxLjVyZW0gMCAwOwp9CgpkbCBkZCB7CiAgcG9zaXRpb246IHJlbGF0aXZlOwogIG1hcmdpbjogMCAxcmVtIDA7Cn0KCmRkICsgZHQucHJlIHsKICBtYXJnaW4tdG9wOiAxLjZyZW07Cn0KCiNhcGljb250ZW50IHsKICBwYWRkaW5nLXRvcDogMXJlbTsKfQoKI2FwaWNvbnRlbnQgLmxpbmUgewogIHdpZHRoOiBjYWxjKDUwJSAtIDFyZW0pOwogIG1hcmdpbjogMXJlbSAxcmVtIC45NXJlbTsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjY2NjOwp9CgpoMiArIGgyIHsKICBtYXJnaW46IDAgMCAuNXJlbTsKfQoKaDMgKyBoMyB7CiAgbWFyZ2luOiAwIDAgLjVyZW07Cn0KCmgyLCBoMywgaDQsIGg1IHsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgcGFkZGluZy1yaWdodDogNDBweDsKfQoKLnNyY2xpbmsgewogIGZsb2F0OiByaWdodDsKICBmb250LXNpemU6IHNtYWxsZXI7Cn0KCmgxIHNwYW4sIGgyIHNwYW4sIGgzIHNwYW4sIGg0IHNwYW4gewogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICBkaXNwbGF5OiBibG9jazsKICB0b3A6IDA7CiAgcmlnaHQ6IDA7Cn0KCmgxIHNwYW46aG92ZXIsIGgyIHNwYW46aG92ZXIsIGgzIHNwYW46aG92ZXIsIGg0IHNwYW46aG92ZXIgewogIG9wYWNpdHk6IDE7Cn0KCmgxIHNwYW4gYSwgaDIgc3BhbiBhLCBoMyBzcGFuIGEsIGg0IHNwYW4gYSB7CiAgY29sb3I6ICMwMDA7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGZvbnQtd2VpZ2h0OiBib2xkOwp9CgpwcmUsIHR0LCBjb2RlIHsKICBsaW5lLWhlaWdodDogMS41cmVtOwogIG1hcmdpbjogMDsgcGFkZGluZzogMDsKfQoKLnByZSB7CiAgbGluZS1oZWlnaHQ6IDEuNXJlbTsKfQoKcHJlIHsKICBwYWRkaW5nOiAxcmVtOwogIHZlcnRpY2FsLWFsaWduOiB0b3A7CiAgYmFja2dyb3VuZDogI2YyZjJmMjsKICBtYXJnaW46IDFyZW07CiAgb3ZlcmZsb3cteDogYXV0bzsKfQoKcHJlID4gY29kZSB7CiAgcGFkZGluZzogMDsKfQoKcHJlICsgaDMgewogIG1hcmdpbi10b3A6IDIuMjI1cmVtOwp9Cgpjb2RlLnByZSB7CiAgd2hpdGUtc3BhY2U6IHByZTsKfQoKI2ludHJvIHsKICBtYXJnaW4tdG9wOiAxLjI1cmVtOwogIG1hcmdpbi1sZWZ0OiAxcmVtOwp9CgojaW50cm8gYSB7CiAgY29sb3I6ICNkZGQ7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmhyIHsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogbWVkaXVtIG5vbmU7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM3YTdhN2E7CiAgbWFyZ2luOiAwIDAgMXJlbSAwOwp9CgojdG9jIGgyIHsKICBtYXJnaW4tdG9wOiAwOwogIG1hcmdpbjogMS41cmVtIDA7Cn0KCiN0b2MgcCB7CiAgbWFyZ2luOiAwOwp9CgojdG9jIHVsIGEgewogIHRleHQtZGVjb3JhdGlvbjpub25lOwp9CgojdG9jIHVsIGxpIHsKICBtYXJnaW4tYm90dG9tOiAuNjY2cmVtOwogIGxpc3Qtc3R5bGU6IHNxdWFyZSBvdXRzaWRlOwp9CgojdG9jIGxpID4gdWwgewogIG1hcmdpbi10b3A6IC42NjZyZW07Cn0KCiN0b2MgLnN0YWJpbGl0eV8wOjphZnRlciB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2Q1MDAyNzsKICBjb2xvcjogI2ZmZjsKICBjb250ZW50OiAiZGVwcmVjYXRlZCI7CiAgbWFyZ2luLWxlZnQ6IC4yNXJlbTsKICBwYWRkaW5nOiAxcHggM3B4OwogIGJvcmRlci1yYWRpdXM6IDNweDsKfQoKI2FwaWNvbnRlbnQgbGkgewogIG1hcmdpbi1ib3R0b206IC41cmVtOwp9CgojYXBpY29udGVudCBsaTpsYXN0LWNoaWxkIHsKICBtYXJnaW4tYm90dG9tOiAwOwp9Cgp0dCwgY29kZSB7CiAgY29sb3I6ICMwNDA0MDQ7CiAgYmFja2dyb3VuZC1jb2xvcjogI2YyZjJmMjsKICBib3JkZXItcmFkaXVzOiAycHg7CiAgcGFkZGluZzogMXB4IDNweDsKfQoKLmFwaV9zdGFiaWxpdHkgY29kZSB7CiAgYmFja2dyb3VuZDogcmdiYSgwLCAwLCAwLCAuMSk7Cn0KCmEgY29kZSB7CiAgY29sb3I6IGluaGVyaXQ7CiAgYmFja2dyb3VuZDogaW5oZXJpdDsKICBwYWRkaW5nOiAwOwp9CgoudHlwZSB7CiAgbGluZS1oZWlnaHQ6IDEuNXJlbTsKfQoKI2NvbHVtbjEuaW50ZXJpb3IgewogIG1hcmdpbi1sZWZ0OiAyMzRweDsKICBwYWRkaW5nOiAwIDJyZW07CiAgLXdlYmtpdC1wYWRkaW5nLXN0YXJ0OiAxLjVyZW07Cn0KCiNjb2x1bW4yLmludGVyaW9yIHsKICB3aWR0aDogMjM0cHg7CiAgYmFja2dyb3VuZDogIzMzMzsKICBwb3NpdGlvbjogZml4ZWQ7CiAgbGVmdDogMDsKICB0b3A6IDA7CiAgYm90dG9tOiAwOwogIG92ZXJmbG93LXg6IGhpZGRlbjsKICBvdmVyZmxvdy15OiBzY3JvbGw7Cn0KCiNjb2x1bW4yIHVsIHsKICBsaXN0LXN0eWxlOiBub25lOwogIG1hcmdpbjogLjlyZW0gMCAuNXJlbTsKICBiYWNrZ3JvdW5kOiAjMzMzOwp9CgojY29sdW1uMiA+IDpmaXJzdC1jaGlsZCB7CiAgbWFyZ2luOiAxLjI1cmVtOwogIGZvbnQtc2l6ZTogMS41cmVtOwp9CgojY29sdW1uMiA+IHVsOm50aC1jaGlsZCgyKSB7CiAgbWFyZ2luOiAxLjI1cmVtIDAgLjVyZW07Cn0KCiNjb2x1bW4yID4gdWw6bGFzdC1jaGlsZCB7CiAgbWFyZ2luOiAuOXJlbSAwIDEuMjVyZW07Cn0KCiNjb2x1bW4yIHVsIGxpIHsKICBwYWRkaW5nLWxlZnQ6IDEuMjVyZW07CiAgbWFyZ2luLWJvdHRvbTogLjVyZW07CiAgcGFkZGluZy1ib3R0b206IC41cmVtOwp9CgojY29sdW1uMiAubGluZSB7CiAgbWFyZ2luOiAwIC41cmVtOwogIGJhY2tncm91bmQtY29sb3I6ICM3MDcwNzA7Cn0KCiNjb2x1bW4yIHVsIGxpOmxhc3QtY2hpbGQgewogIG1hcmdpbi1ib3R0b206IDA7Cn0KCiNjb2x1bW4yIHVsIGxpIGEgewogIGNvbG9yOiAjY2NjOwogIGJvcmRlci1yYWRpdXM6IDA7Cn0KCiNjb2x1bW4yIHVsIGxpIGEuYWN0aXZlLCAjY29sdW1uMiB1bCBsaSBhLmFjdGl2ZTpob3ZlciwKI2NvbHVtbjIgdWwgbGkgYS5hY3RpdmU6Zm9jdXMgewogIGNvbG9yOiAjNDM4NTNkOwogIGJvcmRlci1yYWRpdXM6IDA7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM0Mzg1M2Q7CiAgYmFja2dyb3VuZDogbm9uZTsKfQoKI2ludHJvIGE6aG92ZXIsICNpbnRybyBhOmZvY3VzLAojY29sdW1uMiB1bCBsaSBhOmhvdmVyLCAjY29sdW1uMiB1bCBsaSBhOmZvY3VzIHsKICBjb2xvcjogI2ZmZjsKICBiYWNrZ3JvdW5kOiBub25lOwp9CgpzcGFuID4gLm1hcmssIHNwYW4gPiAubWFyazp2aXNpdGVkIHsKICBjb2xvcjogIzcwNzA3MDsKICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgdG9wOiAwcHg7CiAgcmlnaHQ6IDBweDsKfQoKc3BhbiA+IC5tYXJrOmhvdmVyLCBzcGFuID4gLm1hcms6Zm9jdXMsIHNwYW4gPiAubWFyazphY3RpdmUgewogIGNvbG9yOiAjNDM4NTNkOwogIGJhY2tncm91bmQ6IG5vbmU7Cn0KCnRoID4gKjpsYXN0LWNoaWxkLCB0ZCA+ICo6bGFzdC1jaGlsZCB7CiAgbWFyZ2luLWJvdHRvbTogMDsKfQoKLmNoYW5nZWxvZyA+IHN1bW1hcnkgewogIG1hcmdpbjogLjVyZW0gMDsKICBwYWRkaW5nOiAuNXJlbSAwOwogIGN1cnNvcjogcG9pbnRlcjsKfQoKLyogc2ltcGxlciBjbGVhcmZpeCAqLwouY2xlYXJmaXg6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKICBkaXNwbGF5OiBibG9jazsKICBoZWlnaHQ6IDA7CiAgY2xlYXI6IGJvdGg7CiAgdmlzaWJpbGl0eTogaGlkZGVuOwp9CgouZ2l0aHViX2ljb24gewogIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7CiAgbWFyZ2luOiAtMnB4IDNweCAwIDA7Cn0KCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogMTAyNHB4KSB7CiAgI2NvbnRlbnQgewogICAgb3ZlcmZsb3c6IHZpc2libGU7CiAgfQogICNjb2x1bW4xLmludGVyaW9yIHsKICAgIG1hcmdpbi1sZWZ0OiAwOwogICAgcGFkZGluZy1sZWZ0OiAuNXJlbTsKICAgIHBhZGRpbmctcmlnaHQ6IC41cmVtOwogICAgd2lkdGg6IGF1dG87CiAgICBvdmVyZmxvdy15OiB2aXNpYmxlOwogIH0KICAjY29sdW1uMiB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KfQoKQG1lZGlhIHByaW50IHsKICBodG1sIHsKICAgIGhlaWdodDogYXV0bzsKICAgIGZvbnQtc2l6ZTogMC43NWVtOwogIH0KICAjY29sdW1uMi5pbnRlcmlvciB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KICAjY29sdW1uMS5pbnRlcmlvciB7CiAgICBtYXJnaW4tbGVmdDogMHB4OwogICAgcGFkZGluZzogMHB4OwogICAgb3ZlcmZsb3cteTogYXV0bzsKICB9CiAgLmFwaV9tZXRhZGF0YSwKICAjdG9jLAogIC5zcmNsaW5rLAogICNndG9jLAogIC5tYXJrIHsKICAgIGRpc3BsYXk6IG5vbmU7CiAgfQogIGgxIHsKICAgIGZvbnQtc2l6ZTogMnJlbTsKICB9CiAgaDIgewogICAgZm9udC1zaXplOiAxLjc1cmVtOwogIH0KICBoMyB7CiAgICBmb250LXNpemU6IDEuNXJlbTsKICB9CiAgaDQgewogICAgZm9udC1zaXplOiAxLjNyZW07CiAgfQogIGg1IHsKICAgIGZvbnQtc2l6ZTogMS4ycmVtOwogIH0KICBoNiB7CiAgICBmb250LXNpemU6IDEuMXJlbTsKICB9CiAgLmFwaV9zdGFiaWxpdHkgewogICAgZGlzcGxheTogaW5saW5lLWJsb2NrOwogIH0KICAuYXBpX3N0YWJpbGl0eSBhIHsKICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICB9CiAgYSB7CiAgICBjb2xvcjogaW5oZXJpdDsKICB9CiAgI2FwaWNvbnRlbnQgewogICAgb3ZlcmZsb3c6IGhpZGRlbjsKICB9Cn0K">
<link rel="stylesheet" href="data:text/css;base64,LnNoX3NvdXJjZUNvZGUgewogIGZvbnQtd2VpZ2h0OiBub3JtYWw7CiAgZm9udC1zdHlsZTogbm9ybWFsOwp9Cgouc2hfc291cmNlQ29kZSAuc2hfc3ltYm9sLAouc2hfc291cmNlQ29kZSAuc2hfY2JyYWNrZXQgewogIGNvbG9yOiAjMzMzOwp9Cgouc2hfc291cmNlQ29kZSAuc2hfa2V5d29yZCB7CiAgY29sb3I6ICMzMzg7Cn0KCi5zaF9zb3VyY2VDb2RlIC5zaF9zdHJpbmcsCi5zaF9zb3VyY2VDb2RlIC5zaF9yZWdleHAsCi5zaF9zb3VyY2VDb2RlIC5zaF9udW1iZXIsCi5zaF9zb3VyY2VDb2RlIC5zaF9zcGVjaWFsY2hhciB7CiAgY29sb3I6ICNFNTQzMDU7Cn0KCi5zaF9zb3VyY2VDb2RlIC5zaF9jb21tZW50IHsKICBjb2xvcjogIzY2NjsKICBmb250LXdlaWdodDogbGlnaHRlcjsKfQo=">
<link rel="canonical" href="https://nodejs.org/api/addons.html">
</head>
<body class="alt apidoc" id="api-section-addons">
<div id="content" class="clearfix">
<div id="column2" class="interior">
<div id="intro" class="interior">
<a href="https://nodejs.org/" title="Go back to the home page">
Node.js
</a>
</div>
<ul>
<li><a href="https://nodejs.org/api/documentation.html" class="nav-documentation">About these Docs</a></li>
<li><a href="https://nodejs.org/api/synopsis.html" class="nav-synopsis">Usage & Example</a></li>
</ul>
<div class="line"></div>
<ul>
<li><a href="https://nodejs.org/api/assert.html" class="nav-assert">Assertion Testing</a></li>
<li><a href="https://nodejs.org/api/async_hooks.html" class="nav-async_hooks">Async Hooks</a></li>
<li><a href="https://nodejs.org/api/buffer.html" class="nav-buffer">Buffer</a></li>
<li><a href="https://nodejs.org/api/addons.html" class="nav-addons active">C++ Addons</a></li>
<li><a href="https://nodejs.org/api/n-api.html" class="nav-n-api">C/C++ Addons - N-API</a></li>
<li><a href="https://nodejs.org/api/child_process.html" class="nav-child_process">Child Processes</a></li>
<li><a href="https://nodejs.org/api/cluster.html" class="nav-cluster">Cluster</a></li>
<li><a href="https://nodejs.org/api/cli.html" class="nav-cli">Command Line Options</a></li>
<li><a href="https://nodejs.org/api/console.html" class="nav-console">Console</a></li>
<li><a href="https://nodejs.org/api/crypto.html" class="nav-crypto">Crypto</a></li>
<li><a href="https://nodejs.org/api/debugger.html" class="nav-debugger">Debugger</a></li>
<li><a href="https://nodejs.org/api/deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
<li><a href="https://nodejs.org/api/dns.html" class="nav-dns">DNS</a></li>
<li><a href="https://nodejs.org/api/domain.html" class="nav-domain">Domain</a></li>
<li><a href="https://nodejs.org/api/esm.html" class="nav-esm">ECMAScript Modules</a></li>
<li><a href="https://nodejs.org/api/errors.html" class="nav-errors">Errors</a></li>
<li><a href="https://nodejs.org/api/events.html" class="nav-events">Events</a></li>
<li><a href="https://nodejs.org/api/fs.html" class="nav-fs">File System</a></li>
<li><a href="https://nodejs.org/api/globals.html" class="nav-globals">Globals</a></li>
<li><a href="https://nodejs.org/api/http.html" class="nav-http">HTTP</a></li>
<li><a href="https://nodejs.org/api/http2.html" class="nav-http2">HTTP/2</a></li>
<li><a href="https://nodejs.org/api/https.html" class="nav-https">HTTPS</a></li>
<li><a href="https://nodejs.org/api/inspector.html" class="nav-inspector">Inspector</a></li>
<li><a href="https://nodejs.org/api/intl.html" class="nav-intl">Internationalization</a></li>
<li><a href="https://nodejs.org/api/modules.html" class="nav-modules">Modules</a></li>
<li><a href="https://nodejs.org/api/net.html" class="nav-net">Net</a></li>
<li><a href="https://nodejs.org/api/os.html" class="nav-os">OS</a></li>
<li><a href="https://nodejs.org/api/path.html" class="nav-path">Path</a></li>
<li><a href="https://nodejs.org/api/perf_hooks.html" class="nav-perf_hooks">Performance Hooks</a></li>
<li><a href="https://nodejs.org/api/policy.html" class="nav-policy">Policies</a></li>
<li><a href="https://nodejs.org/api/process.html" class="nav-process">Process</a></li>
<li><a href="https://nodejs.org/api/punycode.html" class="nav-punycode">Punycode</a></li>
<li><a href="https://nodejs.org/api/querystring.html" class="nav-querystring">Query Strings</a></li>
<li><a href="https://nodejs.org/api/readline.html" class="nav-readline">Readline</a></li>
<li><a href="https://nodejs.org/api/repl.html" class="nav-repl">REPL</a></li>
<li><a href="https://nodejs.org/api/report.html" class="nav-report">Report</a></li>
<li><a href="https://nodejs.org/api/stream.html" class="nav-stream">Stream</a></li>
<li><a href="https://nodejs.org/api/string_decoder.html" class="nav-string_decoder">String Decoder</a></li>
<li><a href="https://nodejs.org/api/timers.html" class="nav-timers">Timers</a></li>
<li><a href="https://nodejs.org/api/tls.html" class="nav-tls">TLS/SSL</a></li>
<li><a href="https://nodejs.org/api/tracing.html" class="nav-tracing">Trace Events</a></li>
<li><a href="https://nodejs.org/api/tty.html" class="nav-tty">TTY</a></li>
<li><a href="https://nodejs.org/api/dgram.html" class="nav-dgram">UDP/Datagram</a></li>
<li><a href="https://nodejs.org/api/url.html" class="nav-url">URL</a></li>
<li><a href="https://nodejs.org/api/util.html" class="nav-util">Utilities</a></li>
<li><a href="https://nodejs.org/api/v8.html" class="nav-v8">V8</a></li>
<li><a href="https://nodejs.org/api/vm.html" class="nav-vm">VM</a></li>
<li><a href="https://nodejs.org/api/worker_threads.html" class="nav-worker_threads">Worker Threads</a></li>
<li><a href="https://nodejs.org/api/zlib.html" class="nav-zlib">Zlib</a></li>
</ul>
<div class="line"></div>
<ul>
<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">GitHub Repo & Issue Tracker</a></li>
</ul>
</div>
<div id="column1" data-id="addons" class="interior">
<header>
<h1>Node.js v12.10.0 Documentation</h1>
<div id="gtoc">
<ul>
<li>
<a href="https://nodejs.org/api/index.html" name="toc">Index</a>
</li>
<li>
<a href="https://nodejs.org/api/all.html">View on single page</a>
</li>
<li>
<a href="https://nodejs.org/api/addons.json">View as JSON</a>
</li>
<li class="version-picker">
<a href="#">View another version <span>▼</span></a>
<ol class="version-picker"><li><a href="https://nodejs.org/docs/latest-v12.x/api/addons.html">12.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v11.x/api/addons.html">11.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v10.x/api/addons.html">10.x <b>LTS</b></a></li>
<li><a href="https://nodejs.org/docs/latest-v9.x/api/addons.html">9.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v8.x/api/addons.html">8.x <b>LTS</b></a></li>
<li><a href="https://nodejs.org/docs/latest-v7.x/api/addons.html">7.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v6.x/api/addons.html">6.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v5.x/api/addons.html">5.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v4.x/api/addons.html">4.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v0.12.x/api/addons.html">0.12.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v0.10.x/api/addons.html">0.10.x</a></li></ol>
</li>
<li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/master/doc/api/addons.md"><span class="github_icon"><svg height="16" width="16" viewBox="0 0 16.1 16.1" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.5 15.6c.4 0 .5-.2.5-.4v-1.5c-2 .4-2.5-.5-2.7-1 0-.1-.5-.9-.8-1-.3-.2-.7-.6 0-.6.6 0 1 .6 1.2.8.7 1.2 1.9 1 2.4.7 0-.5.2-.9.5-1-1.8-.3-3.7-1-3.7-4 0-.9.3-1.6.8-2.2 0-.2-.3-1 .1-2 0 0 .7-.3 2.2.7a7.4 7.4 0 0 1 4 0c1.5-1 2.2-.8 2.2-.8.5 1.1.2 2 .1 2.1.5.6.8 1.3.8 2.2 0 3-1.9 3.7-3.6 4 .3.2.5.7.5 1.4v2.2c0 .2.1.5.5.4A8 8 0 0 0 16 8a8 8 0 0 0-8-8z"></path></svg></span>Edit on GitHub</a></li>
</ul>
</div>
<hr>
</header>
<div id="toc">
<h2>Table of Contents</h2>
<ul>
<li>
<p><a href="#addons_c_addons">C++ Addons</a></p>
<ul>
<li>
<p><a href="#addons_hello_world">Hello world</a></p>
<ul>
<li>
<p><a href="#addons_context_aware_addons">Context-aware addons</a></p>
<ul>
<li><a href="#addons_worker_support">Worker support</a></li>
</ul>
</li>
<li><a href="#addons_building">Building</a></li>
<li><a href="#addons_linking_to_node_js_own_dependencies">Linking to Node.js' own dependencies</a></li>
<li><a href="#addons_loading_addons_using_require">Loading Addons using require()</a></li>
</ul>
</li>
<li><a href="#addons_native_abstractions_for_node_js">Native Abstractions for Node.js</a></li>
<li><a href="#addons_n_api">N-API</a></li>
<li>
<p><a href="#addons_addon_examples">Addon examples</a></p>
<ul>
<li><a href="#addons_function_arguments">Function arguments</a></li>
<li><a href="#addons_callbacks">Callbacks</a></li>
<li><a href="#addons_object_factory">Object factory</a></li>
<li><a href="#addons_function_factory">Function factory</a></li>
<li><a href="#addons_wrapping_c_objects">Wrapping C++ objects</a></li>
<li><a href="#addons_factory_of_wrapped_objects">Factory of wrapped objects</a></li>
<li><a href="#addons_passing_wrapped_objects_around">Passing wrapped objects around</a></li>
<li>
<p><a href="#addons_atexit_hooks">AtExit hooks</a></p>
<ul>
<li><a href="#addons_void_atexit_callback_args">void AtExit(callback, args)</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div id="apicontent">
<h1>C++ Addons<span><a class="mark" href="#addons_c_addons" id="addons_c_addons">#</a></span></h1>
<p>Node.js Addons are dynamically-linked shared objects, written in C++, that
can be loaded into Node.js using the <a href="https://nodejs.org/api/modules.html#modules_require_id"><code>require()</code></a> function, and used
just as if they were an ordinary Node.js module. They are used primarily to
provide an interface between JavaScript running in Node.js and C/C++ libraries.</p>
<p>There are three options for implementing Addons: N-API, nan, or direct
use of internal V8, libuv and Node.js libraries. Unless you need direct
access to functionality which is not exposed by N-API, use N-API.
Refer to the section <a href="https://nodejs.org/api/n-api.html">C/C++ Addons - N-API</a>
for more information on N-API.</p>
<p>When not using N-API, implementing Addons is complicated,
involving knowledge of several components and APIs:</p>
<ul>
<li>
<p>V8: the C++ library Node.js currently uses to provide the
JavaScript implementation. V8 provides the mechanisms for creating objects,
calling functions, etc. V8's API is documented mostly in the
<code>v8.h</code> header file (<code>deps/v8/include/v8.h</code> in the Node.js source
tree), which is also available <a href="https://v8docs.nodesource.com/">online</a>.</p>
</li>
<li>
<p><a href="https://github.com/libuv/libuv">libuv</a>: The C library that implements the Node.js event loop, its worker
threads and all of the asynchronous behaviors of the platform. It also
serves as a cross-platform abstraction library, giving easy, POSIX-like
access across all major operating systems to many common system tasks, such
as interacting with the filesystem, sockets, timers, and system events. libuv
also provides a pthreads-like threading abstraction that may be used to
power more sophisticated asynchronous Addons that need to move beyond the
standard event loop. Addon authors are encouraged to think about how to
avoid blocking the event loop with I/O or other time-intensive tasks by
off-loading work via libuv to non-blocking system operations, worker threads
or a custom use of libuv's threads.</p>
</li>
<li>
<p>Internal Node.js libraries. Node.js itself exports a number of C++ APIs
that Addons can use — the most important of which is the
<code>node::ObjectWrap</code> class.</p>
</li>
<li>
<p>Node.js includes a number of other statically linked libraries including
OpenSSL. These other libraries are located in the <code>deps/</code> directory in the
Node.js source tree. Only the libuv, OpenSSL, V8 and zlib symbols are
purposefully re-exported by Node.js and may be used to various extents by
Addons.
See <a href="#addons_linking_to_node_js_own_dependencies">Linking to Node.js' own dependencies</a> for additional information.</p>
</li>
</ul>
<p>All of the following examples are available for <a href="https://github.com/nodejs/node-addon-examples">download</a> and may
be used as the starting-point for an Addon.</p>
<h2>Hello world<span><a class="mark" href="#addons_hello_world" id="addons_hello_world">#</a></span></h2>
<p>This "Hello world" example is a simple Addon, written in C++, that is the
equivalent of the following JavaScript code:</p>
<pre><code class="language-js">module.exports.hello = () => 'world';
</code></pre>
<p>First, create the file <code>hello.cc</code>:</p>
<pre><code class="language-cpp">// hello.cc
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(
isolate, "world", NewStringType::kNormal).ToLocalChecked());
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
} // namespace demo
</code></pre>
<p>All Node.js Addons must export an initialization function following
the pattern:</p>
<pre><code class="language-cpp">void Initialize(Local<Object> exports);
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
</code></pre>
<p>There is no semi-colon after <code>NODE_MODULE</code> as it's not a function (see
<code>node.h</code>).</p>
<p>The <code>module_name</code> must match the filename of the final binary (excluding
the <code>.node</code> suffix).</p>
<p>In the <code>hello.cc</code> example, then, the initialization function is <code>Initialize</code>
and the addon module name is <code>addon</code>.</p>
<p>When building addons with <code>node-gyp</code>, using the macro <code>NODE_GYP_MODULE_NAME</code> as
the first parameter of <code>NODE_MODULE()</code> will ensure that the name of the final
binary will be passed to <code>NODE_MODULE()</code>.</p>
<h3>Context-aware addons<span><a class="mark" href="#addons_context_aware_addons" id="addons_context_aware_addons">#</a></span></h3>
<p>There are environments in which Node.js addons may need to be loaded multiple
times in multiple contexts. For example, the <a href="https://electronjs.org/">Electron</a> runtime runs multiple
instances of Node.js in a single process. Each instance will have its own
<code>require()</code> cache, and thus each instance will need a native addon to behave
correctly when loaded via <code>require()</code>. From the addon's perspective, this means
that it must support multiple initializations.</p>
<p>A context-aware addon can be constructed by using the macro
<code>NODE_MODULE_INITIALIZER</code>, which expands to the name of a function which Node.js
will expect to find when it loads an addon. An addon can thus be initialized as
in the following example:</p>
<pre><code class="language-cpp">using namespace v8;
extern "C" NODE_MODULE_EXPORT void
NODE_MODULE_INITIALIZER(Local<Object> exports,
Local<Value> module,
Local<Context> context) {
/* Perform addon initialization steps here. */
}
</code></pre>
<p>Another option is to use the macro <code>NODE_MODULE_INIT()</code>, which will also
construct a context-aware addon. Unlike <code>NODE_MODULE()</code>, which is used to
construct an addon around a given addon initializer function,
<code>NODE_MODULE_INIT()</code> serves as the declaration of such an initializer to be
followed by a function body.</p>
<p>The following three variables may be used inside the function body following an
invocation of <code>NODE_MODULE_INIT()</code>:</p>
<ul>
<li><code>Local<Object> exports</code>,</li>
<li><code>Local<Value> module</code>, and</li>
<li><code>Local<Context> context</code></li>
</ul>
<p>The choice to build a context-aware addon carries with it the responsibility of
carefully managing global static data. Since the addon may be loaded multiple
times, potentially even from different threads, any global static data stored
in the addon must be properly protected, and must not contain any persistent
references to JavaScript objects. The reason for this is that JavaScript
objects are only valid in one context, and will likely cause a crash when
accessed from the wrong context or from a different thread than the one on which
they were created.</p>
<p>The context-aware addon can be structured to avoid global static data by
performing the following steps:</p>
<ul>
<li>defining a class which will hold per-addon-instance data. Such
a class should include a <code>v8::Persistent<v8::Object></code> which will hold a weak
reference to the addon's <code>exports</code> object. The callback associated with the weak
reference will then destroy the instance of the class.</li>
<li>constructing an instance of this class in the addon initializer such that the
<code>v8::Persistent<v8::Object></code> is set to the <code>exports</code> object.</li>
<li>storing the instance of the class in a <code>v8::External</code>, and</li>
<li>passing the <code>v8::External</code> to all methods exposed to JavaScript by passing it
to the <code>v8::FunctionTemplate</code> constructor which creates the native-backed
JavaScript functions. The <code>v8::FunctionTemplate</code> constructor's third parameter
accepts the <code>v8::External</code>.</li>
</ul>
<p>This will ensure that the per-addon-instance data reaches each binding that can
be called from JavaScript. The per-addon-instance data must also be passed into
any asynchronous callbacks the addon may create.</p>
<p>The following example illustrates the implementation of a context-aware addon:</p>
<pre><code class="language-cpp">#include <node.h>
using namespace v8;
class AddonData {
public:
AddonData(Isolate* isolate, Local<Object> exports):
call_count(0) {
// Link the existence of this object instance to the existence of exports.
exports_.Reset(isolate, exports);
exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter);
}
~AddonData() {
if (!exports_.IsEmpty()) {
// Reset the reference to avoid leaking data.
exports_.ClearWeak();
exports_.Reset();
}
}
// Per-addon data.
int call_count;
private:
// Method to call when "exports" is about to be garbage-collected.
static void DeleteMe(const WeakCallbackInfo<AddonData>& info) {
delete info.GetParameter();
}
// Weak handle to the "exports" object. An instance of this class will be
// destroyed along with the exports object to which it is weakly bound.
v8::Persistent<v8::Object> exports_;
};
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
// Retrieve the per-addon-instance data.
AddonData* data =
reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
data->call_count++;
info.GetReturnValue().Set((double)data->call_count);
}
// Initialize this addon to be context-aware.
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();
// Create a new instance of AddonData for this instance of the addon.
AddonData* data = new AddonData(isolate, exports);
// Wrap the data in a v8::External so we can pass it to the method we expose.
Local<External> external = External::New(isolate, data);
// Expose the method "Method" to JavaScript, and make sure it receives the
// per-addon-instance data we created above by passing `external` as the
// third parameter to the FunctionTemplate constructor.
exports->Set(context,
String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, Method, external)
->GetFunction(context).ToLocalChecked()).FromJust();
}
</code></pre>
<h4>Worker support<span><a class="mark" href="#addons_worker_support" id="addons_worker_support">#</a></span></h4>
<p>In order to support <a href="https://nodejs.org/api/worker_threads.html#worker_threads_class_worker"><code>Worker</code></a> threads, addons need to clean up any resources
they may have allocated when such a thread exists. This can be achieved through
the usage of the <code>AddEnvironmentCleanupHook()</code> function:</p>
<pre><code class="language-c++">void AddEnvironmentCleanupHook(v8::Isolate* isolate,
void (*fun)(void* arg),
void* arg);
</code></pre>
<p>This function adds a hook that will run before a given Node.js instance shuts
down. If necessary, such hooks can be removed using
<code>RemoveEnvironmentCleanupHook()</code> before they are run, which has the same
signature.</p>
<p>In order to be loaded from multiple Node.js environments,
such as a main thread and a Worker thread, an add-on needs to either:</p>
<ul>
<li>Be an N-API addon, or</li>
<li>Be declared as context-aware using <code>NODE_MODULE_INIT()</code> as described above</li>
</ul>
<h3>Building<span><a class="mark" href="#addons_building" id="addons_building">#</a></span></h3>
<p>Once the source code has been written, it must be compiled into the binary
<code>addon.node</code> file. To do so, create a file called <code>binding.gyp</code> in the
top-level of the project describing the build configuration of the module
using a JSON-like format. This file is used by <a href="https://github.com/nodejs/node-gyp">node-gyp</a> — a tool written
specifically to compile Node.js Addons.</p>
<pre><code class="language-json">{
"targets": [
{
"target_name": "addon",
"sources": [ "hello.cc" ]
}
]
}
</code></pre>
<p>A version of the <code>node-gyp</code> utility is bundled and distributed with
Node.js as part of <code>npm</code>. This version is not made directly available for
developers to use and is intended only to support the ability to use the
<code>npm install</code> command to compile and install Addons. Developers who wish to
use <code>node-gyp</code> directly can install it using the command
<code>npm install -g node-gyp</code>. See the <code>node-gyp</code> <a href="https://github.com/nodejs/node-gyp#installation">installation instructions</a> for
more information, including platform-specific requirements.</p>
<p>Once the <code>binding.gyp</code> file has been created, use <code>node-gyp configure</code> to
generate the appropriate project build files for the current platform. This
will generate either a <code>Makefile</code> (on Unix platforms) or a <code>vcxproj</code> file
(on Windows) in the <code>build/</code> directory.</p>
<p>Next, invoke the <code>node-gyp build</code> command to generate the compiled <code>addon.node</code>
file. This will be put into the <code>build/Release/</code> directory.</p>
<p>When using <code>npm install</code> to install a Node.js Addon, npm uses its own bundled
version of <code>node-gyp</code> to perform this same set of actions, generating a
compiled version of the Addon for the user's platform on demand.</p>
<p>Once built, the binary Addon can be used from within Node.js by pointing
<a href="https://nodejs.org/api/modules.html#modules_require_id"><code>require()</code></a> to the built <code>addon.node</code> module:</p>
<pre><code class="language-js">// hello.js
const addon = require('./build/Release/addon');
console.log(addon.hello());
// Prints: 'world'
</code></pre>
<p>Because the exact path to the compiled Addon binary can vary depending on how
it is compiled (i.e. sometimes it may be in <code>./build/Debug/</code>), Addons can use
the <a href="https://github.com/TooTallNate/node-bindings">bindings</a> package to load the compiled module.</p>
<p>While the <code>bindings</code> package implementation is more sophisticated in how it
locates Addon modules, it is essentially using a <code>try…catch</code> pattern similar to:</p>
<pre><code class="language-js">try {
return require('./build/Release/addon.node');
} catch (err) {
return require('./build/Debug/addon.node');
}
</code></pre>
<h3>Linking to Node.js' own dependencies<span><a class="mark" href="#addons_linking_to_node_js_own_dependencies" id="addons_linking_to_node_js_own_dependencies">#</a></span></h3>
<p>Node.js uses a number of statically linked libraries such as V8, libuv and
OpenSSL. All Addons are required to link to V8 and may link to any of the
other dependencies as well. Typically, this is as simple as including
the appropriate <code>#include <...></code> statements (e.g. <code>#include <v8.h></code>) and
<code>node-gyp</code> will locate the appropriate headers automatically. However, there
are a few caveats to be aware of:</p>
<ul>
<li>
<p>When <code>node-gyp</code> runs, it will detect the specific release version of Node.js
and download either the full source tarball or just the headers. If the full
source is downloaded, Addons will have complete access to the full set of
Node.js dependencies. However, if only the Node.js headers are downloaded, then
only the symbols exported by Node.js will be available.</p>
</li>
<li>
<p><code>node-gyp</code> can be run using the <code>--nodedir</code> flag pointing at a local Node.js
source image. Using this option, the Addon will have access to the full set of
dependencies.</p>
</li>
</ul>
<h3>Loading Addons using require()<span><a class="mark" href="#addons_loading_addons_using_require" id="addons_loading_addons_using_require">#</a></span></h3>
<p>The filename extension of the compiled Addon binary is <code>.node</code> (as opposed
to <code>.dll</code> or <code>.so</code>). The <a href="https://nodejs.org/api/modules.html#modules_require_id"><code>require()</code></a> function is written to look for
files with the <code>.node</code> file extension and initialize those as dynamically-linked
libraries.</p>
<p>When calling <a href="https://nodejs.org/api/modules.html#modules_require_id"><code>require()</code></a>, the <code>.node</code> extension can usually be
omitted and Node.js will still find and initialize the Addon. One caveat,
however, is that Node.js will first attempt to locate and load modules or
JavaScript files that happen to share the same base name. For instance, if
there is a file <code>addon.js</code> in the same directory as the binary <code>addon.node</code>,
then <a href="https://nodejs.org/api/modules.html#modules_require_id"><code>require('addon')</code></a> will give precedence to the <code>addon.js</code> file
and load it instead.</p>
<h2>Native Abstractions for Node.js<span><a class="mark" href="#addons_native_abstractions_for_node_js" id="addons_native_abstractions_for_node_js">#</a></span></h2>
<p>Each of the examples illustrated in this document make direct use of the
Node.js and V8 APIs for implementing Addons. It is important to understand
that the V8 API can, and has, changed dramatically from one V8 release to the
next (and one major Node.js release to the next). With each change, Addons may
need to be updated and recompiled in order to continue functioning. The Node.js
release schedule is designed to minimize the frequency and impact of such
changes but there is little that Node.js can do currently to ensure stability
of the V8 APIs.</p>
<p>The <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> (or <code>nan</code>) provide a set of tools that
Addon developers are recommended to use to keep compatibility between past and
future releases of V8 and Node.js. See the <code>nan</code> <a href="https://github.com/nodejs/nan/tree/master/examples/">examples</a> for an
illustration of how it can be used.</p>
<h2>N-API<span><a class="mark" href="#addons_n_api" id="addons_n_api">#</a></span></h2>
<p></p><div class="api_stability api_stability_2"><a href="https://nodejs.org/api/documentation.html#documentation_stability_index">Stability: 2</a> - Stable</div><p></p>
<p>N-API is an API for building native Addons. It is independent from
the underlying JavaScript runtime (e.g. V8) and is maintained as part of
Node.js itself. This API will be Application Binary Interface (ABI) stable
across versions of Node.js. It is intended to insulate Addons from
changes in the underlying JavaScript engine and allow modules
compiled for one version to run on later versions of Node.js without
recompilation. Addons are built/packaged with the same approach/tools
outlined in this document (node-gyp, etc.). The only difference is the
set of APIs that are used by the native code. Instead of using the V8
or <a href="https://github.com/nodejs/nan">Native Abstractions for Node.js</a> APIs, the functions available
in the N-API are used.</p>
<p>Creating and maintaining an addon that benefits from the ABI stability
provided by N-API carries with it certain
<a href="https://nodejs.org/api/n-api.html#n_api_implications_of_abi_stability">implementation considerations</a>.</p>
<p>To use N-API in the above "Hello world" example, replace the content of
<code>hello.cc</code> with the following. All other instructions remain the same.</p>
<pre><code class="language-cpp">// hello.cc using N-API
#include <node_api.h>
namespace demo {
napi_value Method(napi_env env, napi_callback_info args) {
napi_value greeting;
napi_status status;
status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
if (status != napi_ok) return nullptr;
return greeting;
}
napi_value init(napi_env env, napi_value exports) {
napi_status status;
napi_value fn;
status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
if (status != napi_ok) return nullptr;
status = napi_set_named_property(env, exports, "hello", fn);
if (status != napi_ok) return nullptr;
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
} // namespace demo
</code></pre>
<p>The functions available and how to use them are documented in the
section titled <a href="https://nodejs.org/api/n-api.html">C/C++ Addons - N-API</a>.</p>
<h2>Addon examples<span><a class="mark" href="#addons_addon_examples" id="addons_addon_examples">#</a></span></h2>
<p>Following are some example Addons intended to help developers get started. The
examples make use of the V8 APIs. Refer to the online <a href="https://v8docs.nodesource.com/">V8 reference</a>
for help with the various V8 calls, and V8's <a href="https://github.com/v8/v8/wiki/Embedder's%20Guide">Embedder's Guide</a> for an
explanation of several concepts used such as handles, scopes, function
templates, etc.</p>
<p>Each of these examples using the following <code>binding.gyp</code> file:</p>
<pre><code class="language-json">{
"targets": [
{
"target_name": "addon",
"sources": [ "addon.cc" ]
}
]
}
</code></pre>
<p>In cases where there is more than one <code>.cc</code> file, simply add the additional
filename to the <code>sources</code> array:</p>
<pre><code class="language-json">"sources": ["addon.cc", "myexample.cc"]
</code></pre>
<p>Once the <code>binding.gyp</code> file is ready, the example Addons can be configured and
built using <code>node-gyp</code>:</p>
<pre><code class="language-console">$ node-gyp configure build
</code></pre>
<h3>Function arguments<span><a class="mark" href="#addons_function_arguments" id="addons_function_arguments">#</a></span></h3>
<p>Addons will typically expose objects and functions that can be accessed from
JavaScript running within Node.js. When functions are invoked from JavaScript,
the input arguments and return value must be mapped to and from the C/C++
code.</p>
<p>The following example illustrates how to read function arguments passed from
JavaScript and how to return a result:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
namespace demo {
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
// This is the implementation of the "add" method
// Input arguments are passed using the
// const FunctionCallbackInfo<Value>& args struct
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
// Check the number of arguments passed.
if (args.Length() < 2) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate,
"Wrong number of arguments",
NewStringType::kNormal).ToLocalChecked()));
return;
}
// Check the argument types
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate,
"Wrong arguments",
NewStringType::kNormal).ToLocalChecked()));
return;
}
// Perform the operation
double value =
args[0].As<Number>()->Value() + args[1].As<Number>()->Value();
Local<Number> num = Number::New(isolate, value);
// Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
args.GetReturnValue().Set(num);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
</code></pre>
<p>Once compiled, the example Addon can be required and used from within Node.js:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
console.log('This should be eight:', addon.add(3, 5));
</code></pre>
<h3>Callbacks<span><a class="mark" href="#addons_callbacks" id="addons_callbacks">#</a></span></h3>
<p>It is common practice within Addons to pass JavaScript functions to a C++
function and execute them from there. The following example illustrates how
to invoke such callbacks:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
void RunCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[argc] = {
String::NewFromUtf8(isolate,
"hello world",
NewStringType::kNormal).ToLocalChecked() };
cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", RunCallback);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
</code></pre>
<p>This example uses a two-argument form of <code>Init()</code> that receives the full
<code>module</code> object as the second argument. This allows the Addon to completely
overwrite <code>exports</code> with a single function instead of adding the function as a
property of <code>exports</code>.</p>
<p>To test it, run the following JavaScript:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
addon((msg) => {
console.log(msg);
// Prints: 'hello world'
});
</code></pre>
<p>In this example, the callback function is invoked synchronously.</p>
<h3>Object factory<span><a class="mark" href="#addons_object_factory" id="addons_object_factory">#</a></span></h3>
<p>Addons can create and return new objects from within a C++ function as
illustrated in the following example. An object is created and returned with a
property <code>msg</code> that echoes the string passed to <code>createObject()</code>:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Object> obj = Object::New(isolate);
obj->Set(context,
String::NewFromUtf8(isolate,
"msg",
NewStringType::kNormal).ToLocalChecked(),
args[0]->ToString(context).ToLocalChecked())
.FromJust();
args.GetReturnValue().Set(obj);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
</code></pre>
<p>To test it in JavaScript:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
const obj1 = addon('hello');
const obj2 = addon('world');
console.log(obj1.msg, obj2.msg);
// Prints: 'hello world'
</code></pre>
<h3>Function factory<span><a class="mark" href="#addons_function_factory" id="addons_function_factory">#</a></span></h3>
<p>Another common scenario is creating JavaScript functions that wrap C++
functions and returning those back to JavaScript:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
void MyFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(
isolate, "hello world", NewStringType::kNormal).ToLocalChecked());
}
void CreateFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
Local<Function> fn = tpl->GetFunction(context).ToLocalChecked();
// omit this to make it anonymous
fn->SetName(String::NewFromUtf8(
isolate, "theFunction", NewStringType::kNormal).ToLocalChecked());
args.GetReturnValue().Set(fn);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateFunction);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
</code></pre>
<p>To test:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
const fn = addon();
console.log(fn());
// Prints: 'hello world'
</code></pre>
<h3>Wrapping C++ objects<span><a class="mark" href="#addons_wrapping_c_objects" id="addons_wrapping_c_objects">#</a></span></h3>
<p>It is also possible to wrap C++ objects/classes in a way that allows new
instances to be created using the JavaScript <code>new</code> operator:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Local;
using v8::Object;
void InitAll(Local<Object> exports) {
MyObject::Init(exports);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
</code></pre>
<p>Then, in <code>myobject.h</code>, the wrapper class inherits from <code>node::ObjectWrap</code>:</p>
<pre><code class="language-cpp">// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif
</code></pre>
<p>In <code>myobject.cc</code>, implement the various methods that are to be exposed.
Below, the method <code>plusOne()</code> is exposed by adding it to the constructor's
prototype:</p>
<pre><code class="language-cpp">// myobject.cc
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Local<Object> exports) {
Isolate* isolate = exports->GetIsolate();
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
Local<Context> context = isolate->GetCurrentContext();
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
exports->Set(context, String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(),
tpl->GetFunction(context).ToLocalChecked()).FromJust();
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> result =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(result);
}
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo
</code></pre>
<p>To build this example, the <code>myobject.cc</code> file must be added to the
<code>binding.gyp</code>:</p>
<pre><code class="language-json">{
"targets": [
{
"target_name": "addon",
"sources": [
"addon.cc",
"myobject.cc"
]
}
]
}
</code></pre>
<p>Test it with:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
const obj = new addon.MyObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13
</code></pre>
<p>The destructor for a wrapper object will run when the object is
garbage-collected. For destructor testing, there are command-line flags that
can be used to make it possible to force garbage collection. These flags are
provided by the underlying V8 JavaScript engine. They are subject to change
or removal at any time. They are not documented by Node.js or V8, and they
should never be used outside of testing.</p>
<h3>Factory of wrapped objects<span><a class="mark" href="#addons_factory_of_wrapped_objects" id="addons_factory_of_wrapped_objects">#</a></span></h3>
<p>Alternatively, it is possible to use a factory pattern to avoid explicitly
creating object instances using the JavaScript <code>new</code> operator:</p>
<pre><code class="language-js">const obj = addon.createObject();
// instead of:
// const obj = new addon.Object();
</code></pre>
<p>First, the <code>createObject()</code> method is implemented in <code>addon.cc</code>:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void InitAll(Local<Object> exports, Local<Object> module) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
</code></pre>
<p>In <code>myobject.h</code>, the static method <code>NewInstance()</code> is added to handle
instantiating the object. This method takes the place of using <code>new</code> in
JavaScript:</p>
<pre><code class="language-cpp">// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif
</code></pre>
<p>The implementation in <code>myobject.cc</code> is similar to the previous example:</p>
<pre><code class="language-cpp">// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
Local<Context> context = isolate->GetCurrentContext();
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo
</code></pre>
<p>Once again, to build this example, the <code>myobject.cc</code> file must be added to the
<code>binding.gyp</code>:</p>
<pre><code class="language-json">{
"targets": [
{
"target_name": "addon",
"sources": [
"addon.cc",
"myobject.cc"
]
}
]
}
</code></pre>
<p>Test it with:</p>
<pre><code class="language-js">// test.js
const createObject = require('./build/Release/addon');
const obj = createObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13
const obj2 = createObject(20);
console.log(obj2.plusOne());
// Prints: 21
console.log(obj2.plusOne());
// Prints: 22
console.log(obj2.plusOne());
// Prints: 23
</code></pre>
<h3>Passing wrapped objects around<span><a class="mark" href="#addons_passing_wrapped_objects_around" id="addons_passing_wrapped_objects_around">#</a></span></h3>
<p>In addition to wrapping and returning C++ objects, it is possible to pass
wrapped objects around by unwrapping them with the Node.js helper function
<code>node::ObjectWrap::Unwrap</code>. The following examples shows a function <code>add()</code>
that can take two <code>MyObject</code> objects as input arguments:</p>
<pre><code class="language-cpp">// addon.cc
#include <node.h>
#include <node_object_wrap.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
args[0]->ToObject(context).ToLocalChecked());
MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
args[1]->ToObject(context).ToLocalChecked());
double sum = obj1->value() + obj2->value();
args.GetReturnValue().Set(Number::New(isolate, sum));
}
void InitAll(Local<Object> exports) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(exports, "createObject", CreateObject);
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo
</code></pre>
<p>In <code>myobject.h</code>, a new public method is added to allow access to private values
after unwrapping the object.</p>
<pre><code class="language-cpp">// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
inline double value() const { return value_; }
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif
</code></pre>
<p>The implementation of <code>myobject.cc</code> is similar to before:</p>
<pre><code class="language-cpp">// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(
isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Context> context = isolate->GetCurrentContext();
constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ?
0 : args[0]->NumberValue(context).FromMaybe(0);
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
} // namespace demo
</code></pre>
<p>Test it with:</p>
<pre><code class="language-js">// test.js
const addon = require('./build/Release/addon');
const obj1 = addon.createObject(10);
const obj2 = addon.createObject(20);
const result = addon.add(obj1, obj2);
console.log(result);
// Prints: 30
</code></pre>
<h3>AtExit hooks<span><a class="mark" href="#addons_atexit_hooks" id="addons_atexit_hooks">#</a></span></h3>
<p>An <code>AtExit</code> hook is a function that is invoked after the Node.js event loop
has ended but before the JavaScript VM is terminated and Node.js shuts down.
<code>AtExit</code> hooks are registered using the <code>node::AtExit</code> API.</p>
<h4>void AtExit(callback, args)<span><a class="mark" href="#addons_void_atexit_callback_args" id="addons_void_atexit_callback_args">#</a></span></h4>
<ul>
<li><code>callback</code> <span class="type"><void (*)(void*)></span>
A pointer to the function to call at exit.</li>
<li><code>args</code> <span class="type"><void*></span>
A pointer to pass to the callback at exit.</li>
</ul>
<p>Registers exit hooks that run after the event loop has ended but before the VM
is killed.</p>
<p><code>AtExit</code> takes two parameters: a pointer to a callback function to run at exit,
and a pointer to untyped context data to be passed to that callback.</p>
<p>Callbacks are run in last-in first-out order.</p>
<p>The following <code>addon.cc</code> implements <code>AtExit</code>:</p>
<pre><code class="language-cpp">// addon.cc
#include <assert.h>
#include <stdlib.h>
#include <node.h>
namespace demo {
using node::AtExit;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
static char cookie[] = "yum yum";
static int at_exit_cb1_called = 0;
static int at_exit_cb2_called = 0;
static void at_exit_cb1(void* arg) {
Isolate* isolate = static_cast<Isolate*>(arg);
HandleScope scope(isolate);
Local<Object> obj = Object::New(isolate);
assert(!obj.IsEmpty()); // assert VM is still alive
assert(obj->IsObject());
at_exit_cb1_called++;
}
static void at_exit_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
at_exit_cb2_called++;
}
static void sanity_check(void*) {
assert(at_exit_cb1_called == 1);
assert(at_exit_cb2_called == 2);
}
void init(Local<Object> exports) {
AtExit(at_exit_cb2, cookie);
AtExit(at_exit_cb2, cookie);
AtExit(at_exit_cb1, exports->GetIsolate());
AtExit(sanity_check);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, init)
} // namespace demo
</code></pre>
<p>Test in JavaScript by running:</p>
<pre><code class="language-js">// test.js
require('./build/Release/addon');
</code></pre>
</div>
</div>
</div>
<script src="data:application/javascript;base64,LyoKU0hKUyAtIFN5bnRheCBIaWdobGlnaHRpbmcgaW4gSmF2YVNjcmlwdApDb3B5cmlnaHQgKEMpIDIwMDcsIDIwMDggZ25vbWJhdEB1c2Vycy5zb3VyY2Vmb3JnZS5uZXQKTGljZW5zZTogaHR0cDovL3NoanMuc291cmNlZm9yZ2UubmV0L2RvYy9ncGx2My5odG1sCiovCgppZiAoISB0aGlzLnNoX2xhbmd1YWdlcykgewogIHRoaXMuc2hfbGFuZ3VhZ2VzID0ge307Cn0KdmFyIHNoX3JlcXVlc3RzID0ge307CgpmdW5jdGlvbiBzaF9pc0VtYWlsQWRkcmVzcyh1cmwpIHsKICBpZiAoL15tYWlsdG86Ly50ZXN0KHVybCkpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgcmV0dXJuIHVybC5pbmRleE9mKCdAJykgIT09IC0xOwp9CgpmdW5jdGlvbiBzaF9zZXRIcmVmKHRhZ3MsIG51bVRhZ3MsIGlucHV0U3RyaW5nKSB7CiAgdmFyIHVybCA9IGlucHV0U3RyaW5nLnN1YnN0cmluZyh0YWdzW251bVRhZ3MgLSAyXS5wb3MsIHRhZ3NbbnVtVGFncyAtIDFdLnBvcyk7CiAgaWYgKHVybC5sZW5ndGggPj0gMiAmJiB1cmwuY2hhckF0KDApID09PSAnPCcgJiYgdXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICc+JykgewogICAgdXJsID0gdXJsLnN1YnN0cigxLCB1cmwubGVuZ3RoIC0gMik7CiAgfQogIGlmIChzaF9pc0VtYWlsQWRkcmVzcyh1cmwpKSB7CiAgICB1cmwgPSAnbWFpbHRvOicgKyB1cmw7CiAgfQogIHRhZ3NbbnVtVGFncyAtIDJdLm5vZGUuaHJlZiA9IHVybDsKfQoKLyoKS29ucXVlcm9yIGhhcyBhIGJ1ZyB3aGVyZSB0aGUgcmVndWxhciBleHByZXNzaW9uIC8kL2cgd2lsbCBub3QgbWF0Y2ggYXQgdGhlIGVuZApvZiBhIGxpbmUgbW9yZSB0aGFuIG9uY2U6CgogIHZhciByZWdleCA9IC8kL2c7CiAgdmFyIG1hdGNoOwoKICB2YXIgbGluZSA9ICcxMjM0NTY3ODkwJzsKICByZWdleC5sYXN0SW5kZXggPSAxMDsKICBtYXRjaCA9IHJlZ2V4LmV4ZWMobGluZSk7CgogIHZhciBsaW5lMiA9ICdhYmNkZSc7CiAgcmVnZXgubGFzdEluZGV4ID0gNTsKICBtYXRjaCA9IHJlZ2V4LmV4ZWMobGluZTIpOyAgLy8gZmFpbHMKKi8KZnVuY3Rpb24gc2hfa29ucXVlcm9yRXhlYyhzKSB7CiAgdmFyIHJlc3VsdCA9IFsnJ107CiAgcmVzdWx0LmluZGV4ID0gcy5sZW5ndGg7CiAgcmVzdWx0LmlucHV0ID0gczsKICByZXR1cm4gcmVzdWx0Owp9CgovKioKSGlnaGxpZ2h0cyBhbGwgZWxlbWVudHMgY29udGFpbmluZyBzb3VyY2UgY29kZSBpbiBhIHRleHQgc3RyaW5nLiAgVGhlIHJldHVybgp2YWx1ZSBpcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIHJlcHJlc2VudGluZyBhbiBIVE1MIHN0YXJ0IG9yIGVuZCB0YWcuICBFYWNoCm9iamVjdCBoYXMgYSBwcm9wZXJ0eSBuYW1lZCBwb3MsIHdoaWNoIGlzIGFuIGludGVnZXIgcmVwcmVzZW50aW5nIHRoZSB0ZXh0Cm9mZnNldCBvZiB0aGUgdGFnLiBFdmVyeSBzdGFydCB0YWcgYWxzbyBoYXMgYSBwcm9wZXJ0eSBuYW1lZCBub2RlLCB3aGljaCBpcyB0aGUKRE9NIGVsZW1lbnQgc3RhcnRlZCBieSB0aGUgdGFnLiBFbmQgdGFncyBkbyBub3QgaGF2ZSB0aGlzIHByb3BlcnR5LgpAcGFyYW0gIGlucHV0U3RyaW5nICBhIHRleHQgc3RyaW5nCkBwYXJhbSAgbGFuZ3VhZ2UgIGEgbGFuZ3VhZ2UgZGVmaW5pdGlvbiBvYmplY3QKQHJldHVybiAgYW4gYXJyYXkgb2YgdGFnIG9iamVjdHMKKi8KZnVuY3Rpb24gc2hfaGlnaGxpZ2h0U3RyaW5nKGlucHV0U3RyaW5nLCBsYW5ndWFnZSkgewogIGlmICgvS29ucXVlcm9yLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpKSB7CiAgICBpZiAoISBsYW5ndWFnZS5rb25xdWVyZWQpIHsKICAgICAgZm9yICh2YXIgcyA9IDA7IHMgPCBsYW5ndWFnZS5sZW5ndGg7IHMrKykgewogICAgICAgIGZvciAodmFyIHAgPSAwOyBwIDwgbGFuZ3VhZ2Vbc10ubGVuZ3RoOyBwKyspIHsKICAgICAgICAgIHZhciByID0gbGFuZ3VhZ2Vbc11bcF1bMF07CiAgICAgICAgICBpZiAoci5zb3VyY2UgPT09ICckJykgewogICAgICAgICAgICByLmV4ZWMgPSBzaF9rb25xdWVyb3JFeGVjOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBsYW5ndWFnZS5rb25xdWVyZWQgPSB0cnVlOwogICAgfQogIH0KCiAgdmFyIGEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7CiAgdmFyIHNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7CgogIC8vIHRoZSByZXN1bHQKICB2YXIgdGFncyA9IFtdOwogIHZhciBudW1UYWdzID0gMDsKCiAgLy8gZWFjaCBlbGVtZW50IGlzIGEgcGF0dGVybiBvYmplY3QgZnJvbSBsYW5ndWFnZQogIHZhciBwYXR0ZXJuU3RhY2sgPSBbXTsKCiAgLy8gdGhlIGN1cnJlbnQgcG9zaXRpb24gd2l0aGluIGlucHV0U3RyaW5nCiAgdmFyIHBvcyA9IDA7CgogIC8vIHRoZSBuYW1lIG9mIHRoZSBjdXJyZW50IHN0eWxlLCBvciBudWxsIGlmIHRoZXJlIGlzIG5vIGN1cnJlbnQgc3R5bGUKICB2YXIgY3VycmVudFN0eWxlID0gbnVsbDsKCiAgdmFyIG91dHB1dCA9IGZ1bmN0aW9uKHMsIHN0eWxlKSB7CiAgICB2YXIgbGVuZ3RoID0gcy5sZW5ndGg7CiAgICAvLyB0aGlzIGlzIG1vcmUgdGhhbiBqdXN0IGFuIG9wdGltaXphdGlvbiAtIHdlIGRvbid0IHdhbnQgdG8gb3V0cHV0IGVtcHR5IDxzcGFuPjwvc3Bhbj4gZWxlbWVudHMKICAgIGlmIChsZW5ndGggPT09IDApIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgaWYgKCEgc3R5bGUpIHsKICAgICAgdmFyIHN0YWNrTGVuZ3RoID0gcGF0dGVyblN0YWNrLmxlbmd0aDsKICAgICAgaWYgKHN0YWNrTGVuZ3RoICE9PSAwKSB7CiAgICAgICAgdmFyIHBhdHRlcm4gPSBwYXR0ZXJuU3RhY2tbc3RhY2tMZW5ndGggLSAxXTsKICAgICAgICAvLyBjaGVjayB3aGV0aGVyIHRoaXMgaXMgYSBzdGF0ZSBvciBhbiBlbnZpcm9ubWVudAogICAgICAgIGlmICghIHBhdHRlcm5bM10pIHsKICAgICAgICAgIC8vIGl0J3Mgbm90IGEgc3RhdGUgLSBpdCdzIGFuIGVudmlyb25tZW50OyB1c2UgdGhlIHN0eWxlIGZvciB0aGlzIGVudmlyb25tZW50CiAgICAgICAgICBzdHlsZSA9IHBhdHRlcm5bMV07CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZiAoY3VycmVudFN0eWxlICE9PSBzdHlsZSkgewogICAgICBpZiAoY3VycmVudFN0eWxlKSB7CiAgICAgICAgdGFnc1tudW1UYWdzKytdID0ge3BvczogcG9zfTsKICAgICAgICBpZiAoY3VycmVudFN0eWxlID09PSAnc2hfdXJsJykgewogICAgICAgICAgc2hfc2V0SHJlZih0YWdzLCBudW1UYWdzLCBpbnB1dFN0cmluZyk7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmIChzdHlsZSkgewogICAgICAgIHZhciBjbG9uZTsKICAgICAgICBpZiAoc3R5bGUgPT09ICdzaF91cmwnKSB7CiAgICAgICAgICBjbG9uZSA9IGEuY2xvbmVOb2RlKGZhbHNlKTsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICBjbG9uZSA9IHNwYW4uY2xvbmVOb2RlKGZhbHNlKTsKICAgICAgICB9CiAgICAgICAgY2xvbmUuY2xhc3NOYW1lID0gc3R5bGU7CiAgICAgICAgdGFnc1tudW1UYWdzKytdID0ge25vZGU6IGNsb25lLCBwb3M6IHBvc307CiAgICAgIH0KICAgIH0KICAgIHBvcyArPSBsZW5ndGg7CiAgICBjdXJyZW50U3R5bGUgPSBzdHlsZTsKICB9OwoKICB2YXIgZW5kT2ZMaW5lUGF0dGVybiA9IC9cclxufFxyfFxuL2c7CiAgZW5kT2ZMaW5lUGF0dGVybi5sYXN0SW5kZXggPSAwOwogIHZhciBpbnB1dFN0cmluZ0xlbmd0aCA9IGlucHV0U3RyaW5nLmxlbmd0aDsKICB3aGlsZSAocG9zIDwgaW5wdXRTdHJpbmdMZW5ndGgpIHsKICAgIHZhciBzdGFydCA9IHBvczsKICAgIHZhciBlbmQ7CiAgICB2YXIgc3RhcnRPZk5leHRMaW5lOwogICAgdmFyIGVuZE9mTGluZU1hdGNoID0gZW5kT2ZMaW5lUGF0dGVybi5leGVjKGlucHV0U3RyaW5nKTsKICAgIGlmIChlbmRPZkxpbmVNYXRjaCA9PT0gbnVsbCkgewogICAgICBlbmQgPSBpbnB1dFN0cmluZ0xlbmd0aDsKICAgICAgc3RhcnRPZk5leHRMaW5lID0gaW5wdXRTdHJpbmdMZW5ndGg7CiAgICB9CiAgICBlbHNlIHsKICAgICAgZW5kID0gZW5kT2ZMaW5lTWF0Y2guaW5kZXg7CiAgICAgIHN0YXJ0T2ZOZXh0TGluZSA9IGVuZE9mTGluZVBhdHRlcm4ubGFzdEluZGV4OwogICAgfQoKICAgIHZhciBsaW5lID0gaW5wdXRTdHJpbmcuc3Vic3RyaW5nKHN0YXJ0LCBlbmQpOwoKICAgIHZhciBtYXRjaENhY2hlID0gW107CiAgICBmb3IgKDs7KSB7CiAgICAgIHZhciBwb3NXaXRoaW5MaW5lID0gcG9zIC0gc3RhcnQ7CgogICAgICB2YXIgc3RhdGVJbmRleDsKICAgICAgdmFyIHN0YWNrTGVuZ3RoID0gcGF0dGVyblN0YWNrLmxlbmd0aDsKICAgICAgaWYgKHN0YWNrTGVuZ3RoID09PSAwKSB7CiAgICAgICAgc3RhdGVJbmRleCA9IDA7CiAgICAgIH0KICAgICAgZWxzZSB7CiAgICAgICAgLy8gZ2V0IHRoZSBuZXh0IHN0YXRlCiAgICAgICAgc3RhdGVJbmRleCA9IHBhdHRlcm5TdGFja1tzdGFja0xlbmd0aCAtIDFdWzJdOwogICAgICB9CgogICAgICB2YXIgc3RhdGUgPSBsYW5ndWFnZVtzdGF0ZUluZGV4XTsKICAgICAgdmFyIG51bVBhdHRlcm5zID0gc3RhdGUubGVuZ3RoOwogICAgICB2YXIgbWMgPSBtYXRjaENhY2hlW3N0YXRlSW5kZXhdOwogICAgICBpZiAoISBtYykgewogICAgICAgIG1jID0gbWF0Y2hDYWNoZVtzdGF0ZUluZGV4XSA9IFtdOwogICAgICB9CiAgICAgIHZhciBiZXN0TWF0Y2ggPSBudWxsOwogICAgICB2YXIgYmVzdFBhdHRlcm5JbmRleCA9IC0xOwogICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG51bVBhdHRlcm5zOyBpKyspIHsKICAgICAgICB2YXIgbWF0Y2g7CiAgICAgICAgaWYgKGkgPCBtYy5sZW5ndGggJiYgKG1jW2ldID09PSBudWxsIHx8IHBvc1dpdGhpbkxpbmUgPD0gbWNbaV0uaW5kZXgpKSB7CiAgICAgICAgICBtYXRjaCA9IG1jW2ldOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgIHZhciByZWdleCA9IHN0YXRlW2ldWzBdOwogICAgICAgICAgcmVnZXgubGFzdEluZGV4ID0gcG9zV2l0aGluTGluZTsKICAgICAgICAgIG1hdGNoID0gcmVnZXguZXhlYyhsaW5lKTsKICAgICAgICAgIG1jW2ldID0gbWF0Y2g7CiAgICAgICAgfQogICAgICAgIGlmIChtYXRjaCAhPT0gbnVsbCAmJiAoYmVzdE1hdGNoID09PSBudWxsIHx8IG1hdGNoLmluZGV4IDwgYmVzdE1hdGNoLmluZGV4KSkgewogICAgICAgICAgYmVzdE1hdGNoID0gbWF0Y2g7CiAgICAgICAgICBiZXN0UGF0dGVybkluZGV4ID0gaTsKICAgICAgICAgIGlmIChtYXRjaC5pbmRleCA9PT0gcG9zV2l0aGluTGluZSkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KCiAgICAgIGlmIChiZXN0TWF0Y2ggPT09IG51bGwpIHsKICAgICAgICBvdXRwdXQobGluZS5zdWJzdHJpbmcocG9zV2l0aGluTGluZSksIG51bGwpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGVsc2UgewogICAgICAgIC8vIGdvdCBhIG1hdGNoCiAgICAgICAgaWYgKGJlc3RNYXRjaC5pbmRleCA+IHBvc1dpdGhpbkxpbmUpIHsKICAgICAgICAgIG91dHB1dChsaW5lLnN1YnN0cmluZyhwb3NXaXRoaW5MaW5lLCBiZXN0TWF0Y2guaW5kZXgpLCBudWxsKTsKICAgICAgICB9CgogICAgICAgIHZhciBwYXR0ZXJuID0gc3RhdGVbYmVzdFBhdHRlcm5JbmRleF07CgogICAgICAgIHZhciBuZXdTdHlsZSA9IHBhdHRlcm5bMV07CiAgICAgICAgdmFyIG1hdGNoZWRTdHJpbmc7CiAgICAgICAgaWYgKG5ld1N0eWxlIGluc3RhbmNlb2YgQXJyYXkpIHsKICAgICAgICAgIGZvciAodmFyIHN1YmV4cHJlc3Npb24gPSAwOyBzdWJleHByZXNzaW9uIDwgbmV3U3R5bGUubGVuZ3RoOyBzdWJleHByZXNzaW9uKyspIHsKICAgICAgICAgICAgbWF0Y2hlZFN0cmluZyA9IGJlc3RNYXRjaFtzdWJleHByZXNzaW9uICsgMV07CiAgICAgICAgICAgIG91dHB1dChtYXRjaGVkU3RyaW5nLCBuZXdTdHlsZVtzdWJleHByZXNzaW9uXSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgbWF0Y2hlZFN0cmluZyA9IGJlc3RNYXRjaFswXTsKICAgICAgICAgIG91dHB1dChtYXRjaGVkU3RyaW5nLCBuZXdTdHlsZSk7CiAgICAgICAgfQoKICAgICAgICBzd2l0Y2ggKHBhdHRlcm5bMl0pIHsKICAgICAgICBjYXNlIC0xOgogICAgICAgICAgLy8gZG8gbm90aGluZwogICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAtMjoKICAgICAgICAgIC8vIGV4aXQKICAgICAgICAgIHBhdHRlcm5TdGFjay5wb3AoKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgLTM6CiAgICAgICAgICAvLyBleGl0YWxsCiAgICAgICAgICBwYXR0ZXJuU3RhY2subGVuZ3RoID0gMDsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAvLyB0aGlzIHdhcyB0aGUgc3RhcnQgb2YgYSBkZWxpbWl0ZWQgcGF0dGVybiBvciBhIHN0YXRlL2Vudmlyb25tZW50CiAgICAgICAgICBwYXR0ZXJuU3RhY2sucHVzaChwYXR0ZXJuKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgfQoKICAgIC8vIGVuZCBvZiB0aGUgbGluZQogICAgaWYgKGN1cnJlbnRTdHlsZSkgewogICAgICB0YWdzW251bVRhZ3MrK10gPSB7cG9zOiBwb3N9OwogICAgICBpZiAoY3VycmVudFN0eWxlID09PSAnc2hfdXJsJykgewogICAgICAgIHNoX3NldEhyZWYodGFncywgbnVtVGFncywgaW5wdXRTdHJpbmcpOwogICAgICB9CiAgICAgIGN1cnJlbnRTdHlsZSA9IG51bGw7CiAgICB9CiAgICBwb3MgPSBzdGFydE9mTmV4dExpbmU7CiAgfQoKICByZXR1cm4gdGFnczsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gRE9NLWRlcGVuZGVudCBmdW5jdGlvbnMKCmZ1bmN0aW9uIHNoX2dldENsYXNzZXMoZWxlbWVudCkgewogIHZhciByZXN1bHQgPSBbXTsKICB2YXIgaHRtbENsYXNzID0gZWxlbWVudC5jbGFzc05hbWU7CiAgaWYgKGh0bWxDbGFzcyAmJiBodG1sQ2xhc3MubGVuZ3RoID4gMCkgewogICAgdmFyIGh0bWxDbGFzc2VzID0gaHRtbENsYXNzLnNwbGl0KCcgJyk7CiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGh0bWxDbGFzc2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgIGlmIChodG1sQ2xhc3Nlc1tpXS5sZW5ndGggPiAwKSB7CiAgICAgICAgcmVzdWx0LnB1c2goaHRtbENsYXNzZXNbaV0pOwogICAgICB9CiAgICB9CiAgfQogIHJldHVybiByZXN1bHQ7Cn0KCmZ1bmN0aW9uIHNoX2FkZENsYXNzKGVsZW1lbnQsIG5hbWUpIHsKICB2YXIgaHRtbENsYXNzZXMgPSBzaF9nZXRDbGFzc2VzKGVsZW1lbnQpOwogIGZvciAodmFyIGkgPSAwOyBpIDwgaHRtbENsYXNzZXMubGVuZ3RoOyBpKyspIHsKICAgIGlmIChuYW1lLnRvTG93ZXJDYXNlKCkgPT09IGh0bWxDbGFzc2VzW2ldLnRvTG93ZXJDYXNlKCkpIHsKICAgICAgcmV0dXJuOwogICAgfQogIH0KICBodG1sQ2xhc3Nlcy5wdXNoKG5hbWUpOwogIGVsZW1lbnQuY2xhc3NOYW1lID0gaHRtbENsYXNzZXMuam9pbignICcpOwp9CgovKioKRXh0cmFjdHMgdGhlIHRhZ3MgZnJvbSBhbiBIVE1MIERPTSBOb2RlTGlzdC4KQHBhcmFtICBub2RlTGlzdCAgYSBET00gTm9kZUxpc3QKQHBhcmFtICByZXN1bHQgIGFuIG9iamVjdCB3aXRoIHRleHQsIHRhZ3MgYW5kIHBvcyBwcm9wZXJ0aWVzCiovCmZ1bmN0aW9uIHNoX2V4dHJhY3RUYWdzRnJvbU5vZGVMaXN0KG5vZGVMaXN0LCByZXN1bHQpIHsKICB2YXIgbGVuZ3RoID0gbm9kZUxpc3QubGVuZ3RoOwogIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgIHZhciBub2RlID0gbm9kZUxpc3QuaXRlbShpKTsKICAgIHN3aXRjaCAobm9kZS5ub2RlVHlwZSkgewogICAgY2FzZSAxOgogICAgICBpZiAobm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSAnYnInKSB7CiAgICAgICAgdmFyIHRlcm1pbmF0b3I7CiAgICAgICAgaWYgKC9NU0lFLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpKSB7CiAgICAgICAgICB0ZXJtaW5hdG9yID0gJ1xyJzsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICB0ZXJtaW5hdG9yID0gJ1xuJzsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnRleHQucHVzaCh0ZXJtaW5hdG9yKTsKICAgICAgICByZXN1bHQucG9zKys7CiAgICAgIH0KICAgICAgZWxzZSB7CiAgICAgICAgcmVzdWx0LnRhZ3MucHVzaCh7bm9kZTogbm9kZS5jbG9uZU5vZGUoZmFsc2UpLCBwb3M6IHJlc3VsdC5wb3N9KTsKICAgICAgICBzaF9leHRyYWN0VGFnc0Zyb21Ob2RlTGlzdChub2RlLmNoaWxkTm9kZXMsIHJlc3VsdCk7CiAgICAgICAgcmVzdWx0LnRhZ3MucHVzaCh7cG9zOiByZXN1bHQucG9zfSk7CiAgICAgIH0KICAgICAgYnJlYWs7CiAgICBjYXNlIDM6CiAgICBjYXNlIDQ6CiAgICAgIHJlc3VsdC50ZXh0LnB1c2gobm9kZS5kYXRhKTsKICAgICAgcmVzdWx0LnBvcyArPSBub2RlLmxlbmd0aDsKICAgICAgYnJlYWs7CiAgICB9CiAgfQp9CgovKioKRXh0cmFjdHMgdGhlIHRhZ3MgZnJvbSB0aGUgdGV4dCBvZiBhbiBIVE1MIGVsZW1lbnQuIFRoZSBleHRyYWN0ZWQgdGFncyB3aWxsIGJlCnJldHVybmVkIGFzIGFuIGFycmF5IG9mIHRhZyBvYmplY3RzLiBTZWUgc2hfaGlnaGxpZ2h0U3RyaW5nIGZvciB0aGUgZm9ybWF0IG9mCnRoZSB0YWcgb2JqZWN0cy4KQHBhcmFtICBlbGVtZW50ICBhIERPTSBlbGVtZW50CkBwYXJhbSAgdGFncyAgYW4gZW1wdHkgYXJyYXk7IHRoZSBleHRyYWN0ZWQgdGFnIG9iamVjdHMgd2lsbCBiZSByZXR1cm5lZCBpbiBpdApAcmV0dXJuICB0aGUgdGV4dCBvZiB0aGUgZWxlbWVudApAc2VlICBzaF9oaWdobGlnaHRTdHJpbmcKKi8KZnVuY3Rpb24gc2hfZXh0cmFjdFRhZ3MoZWxlbWVudCwgdGFncykgewogIHZhciByZXN1bHQgPSB7fTsKICByZXN1bHQudGV4dCA9IFtdOwogIHJlc3VsdC50YWdzID0gdGFnczsKICByZXN1bHQucG9zID0gMDsKICBzaF9leHRyYWN0VGFnc0Zyb21Ob2RlTGlzdChlbGVtZW50LmNoaWxkTm9kZXMsIHJlc3VsdCk7CiAgcmV0dXJuIHJlc3VsdC50ZXh0LmpvaW4oJycpOwp9CgovKioKTWVyZ2VzIHRoZSBvcmlnaW5hbCB0YWdzIGZyb20gYW4gZWxlbWVudCB3aXRoIHRoZSB0YWdzIHByb2R1Y2VkIGJ5IGhpZ2hsaWdodGluZy4KQHBhcmFtICBvcmlnaW5hbFRhZ3MgIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG9yaWdpbmFsIHRhZ3MKQHBhcmFtICBoaWdobGlnaHRUYWdzICBhbiBhcnJheSBjb250YWluaW5nIHRoZSBoaWdobGlnaHRpbmcgdGFncyAtIHRoZXNlIG11c3Qgbm90IG92ZXJsYXAKQHJlc3VsdCAgYW4gYXJyYXkgY29udGFpbmluZyB0aGUgbWVyZ2VkIHRhZ3MKKi8KZnVuY3Rpb24gc2hfbWVyZ2VUYWdzKG9yaWdpbmFsVGFncywgaGlnaGxpZ2h0VGFncykgewogIHZhciBudW1PcmlnaW5hbFRhZ3MgPSBvcmlnaW5hbFRhZ3MubGVuZ3RoOwogIGlmIChudW1PcmlnaW5hbFRhZ3MgPT09IDApIHsKICAgIHJldHVybiBoaWdobGlnaHRUYWdzOwogIH0KCiAgdmFyIG51bUhpZ2hsaWdodFRhZ3MgPSBoaWdobGlnaHRUYWdzLmxlbmd0aDsKICBpZiAobnVtSGlnaGxpZ2h0VGFncyA9PT0gMCkgewogICAgcmV0dXJuIG9yaWdpbmFsVGFnczsKICB9CgogIHZhciByZXN1bHQgPSBbXTsKICB2YXIgb3JpZ2luYWxJbmRleCA9IDA7CiAgdmFyIGhpZ2hsaWdodEluZGV4ID0gMDsKCiAgd2hpbGUgKG9yaWdpbmFsSW5kZXggPCBudW1PcmlnaW5hbFRhZ3MgJiYgaGlnaGxpZ2h0SW5kZXggPCBudW1IaWdobGlnaHRUYWdzKSB7CiAgICB2YXIgb3JpZ2luYWxUYWcgPSBvcmlnaW5hbFRhZ3Nbb3JpZ2luYWxJbmRleF07CiAgICB2YXIgaGlnaGxpZ2h0VGFnID0gaGlnaGxpZ2h0VGFnc1toaWdobGlnaHRJbmRleF07CgogICAgaWYgKG9yaWdpbmFsVGFnLnBvcyA8PSBoaWdobGlnaHRUYWcucG9zKSB7CiAgICAgIHJlc3VsdC5wdXNoKG9yaWdpbmFsVGFnKTsKICAgICAgb3JpZ2luYWxJbmRleCsrOwogICAgfQogICAgZWxzZSB7CiAgICAgIHJlc3VsdC5wdXNoKGhpZ2hsaWdodFRhZyk7CiAgICAgIGlmIChoaWdobGlnaHRUYWdzW2hpZ2hsaWdodEluZGV4ICsgMV0ucG9zIDw9IG9yaWdpbmFsVGFnLnBvcykgewogICAgICAgIGhpZ2hsaWdodEluZGV4Kys7CiAgICAgICAgcmVzdWx0LnB1c2goaGlnaGxpZ2h0VGFnc1toaWdobGlnaHRJbmRleF0pOwogICAgICAgIGhpZ2hsaWdodEluZGV4Kys7CiAgICAgIH0KICAgICAgZWxzZSB7CiAgICAgICAgLy8gbmV3IGVuZCB0YWcKICAgICAgICByZXN1bHQucHVzaCh7cG9zOiBvcmlnaW5hbFRhZy5wb3N9KTsKCiAgICAgICAgLy8gbmV3IHN0YXJ0IHRhZwogICAgICAgIGhpZ2hsaWdodFRhZ3NbaGlnaGxpZ2h0SW5kZXhdID0ge25vZGU6IGhpZ2hsaWdodFRhZy5ub2RlLmNsb25lTm9kZShmYWxzZSksIHBvczogb3JpZ2luYWxUYWcucG9zfTsKICAgICAgfQogICAgfQogIH0KCiAgd2hpbGUgKG9yaWdpbmFsSW5kZXggPCBudW1PcmlnaW5hbFRhZ3MpIHsKICAgIHJlc3VsdC5wdXNoKG9yaWdpbmFsVGFnc1tvcmlnaW5hbEluZGV4XSk7CiAgICBvcmlnaW5hbEluZGV4Kys7CiAgfQoKICB3aGlsZSAoaGlnaGxpZ2h0SW5kZXggPCBudW1IaWdobGlnaHRUYWdzKSB7CiAgICByZXN1bHQucHVzaChoaWdobGlnaHRUYWdzW2hpZ2hsaWdodEluZGV4XSk7CiAgICBoaWdobGlnaHRJbmRleCsrOwogIH0KCiAgcmV0dXJuIHJlc3VsdDsKfQoKLyoqCkluc2VydHMgdGFncyBpbnRvIHRleHQuCkBwYXJhbSAgdGFncyAgYW4gYXJyYXkgb2YgdGFnIG9iamVjdHMKQHBhcmFtICB0ZXh0ICBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHRleHQKQHJldHVybiAgYSBET00gRG9jdW1lbnRGcmFnbWVudCByZXByZXNlbnRpbmcgdGhlIHJlc3VsdGluZyBIVE1MCiovCmZ1bmN0aW9uIHNoX2luc2VydFRhZ3ModGFncywgdGV4dCkgewogIHZhciBkb2MgPSBkb2N1bWVudDsKCiAgdmFyIHJlc3VsdCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTsKICB2YXIgdGFnSW5kZXggPSAwOwogIHZhciBudW1UYWdzID0gdGFncy5sZW5ndGg7CiAgdmFyIHRleHRQb3MgPSAwOwogIHZhciB0ZXh0TGVuZ3RoID0gdGV4dC5sZW5ndGg7CiAgdmFyIGN1cnJlbnROb2RlID0gcmVzdWx0OwoKICAvLyBvdXRwdXQgb25lIHRhZyBvciB0ZXh0IG5vZGUgZXZlcnkgaXRlcmF0aW9uCiAgd2hpbGUgKHRleHRQb3MgPCB0ZXh0TGVuZ3RoIHx8IHRhZ0luZGV4IDwgbnVtVGFncykgewogICAgdmFyIHRhZzsKICAgIHZhciB0YWdQb3M7CiAgICBpZiAodGFnSW5kZXggPCBudW1UYWdzKSB7CiAgICAgIHRhZyA9IHRhZ3NbdGFnSW5kZXhdOwogICAgICB0YWdQb3MgPSB0YWcucG9zOwogICAgfQogICAgZWxzZSB7CiAgICAgIHRhZ1BvcyA9IHRleHRMZW5ndGg7CiAgICB9CgogICAgaWYgKHRhZ1BvcyA8PSB0ZXh0UG9zKSB7CiAgICAgIC8vIG91dHB1dCB0aGUgdGFnCiAgICAgIGlmICh0YWcubm9kZSkgewogICAgICAgIC8vIHN0YXJ0IHRhZwogICAgICAgIHZhciBuZXdOb2RlID0gdGFnLm5vZGU7CiAgICAgICAgY3VycmVudE5vZGUuYXBwZW5kQ2hpbGQobmV3Tm9kZSk7CiAgICAgICAgY3VycmVudE5vZGUgPSBuZXdOb2RlOwogICAgICB9CiAgICAgIGVsc2UgewogICAgICAgIC8vIGVuZCB0YWcKICAgICAgICBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlLnBhcmVudE5vZGU7CiAgICAgIH0KICAgICAgdGFnSW5kZXgrKzsKICAgIH0KICAgIGVsc2UgewogICAgICAvLyBvdXRwdXQgdGV4dAogICAgICBjdXJyZW50Tm9kZS5hcHBlbmRDaGlsZChkb2MuY3JlYXRlVGV4dE5vZGUodGV4dC5zdWJzdHJpbmcodGV4dFBvcywgdGFnUG9zKSkpOwogICAgICB0ZXh0UG9zID0gdGFnUG9zOwogICAgfQogIH0KCiAgcmV0dXJuIHJlc3VsdDsKfQoKLyoqCkhpZ2hsaWdodHMgYW4gZWxlbWVudCBjb250YWluaW5nIHNvdXJjZSBjb2RlLiAgVXBvbiBjb21wbGV0aW9uIG9mIHRoaXMgZnVuY3Rpb24sCnRoZSBlbGVtZW50IHdpbGwgaGF2ZSBiZWVuIHBsYWNlZCBpbiB0aGUgInNoX3NvdXJjZUNvZGUiIGNsYXNzLgpAcGFyYW0gIGVsZW1lbnQgIGEgRE9NIDxwcmU+IGVsZW1lbnQgY29udGFpbmluZyB0aGUgc291cmNlIGNvZGUgdG8gYmUgaGlnaGxpZ2h0ZWQKQHBhcmFtICBsYW5ndWFnZSAgYSBsYW5ndWFnZSBkZWZpbml0aW9uIG9iamVjdAoqLwpmdW5jdGlvbiBzaF9oaWdobGlnaHRFbGVtZW50KGVsZW1lbnQsIGxhbmd1YWdlKSB7CiAgc2hfYWRkQ2xhc3MoZWxlbWVudCwgJ3NoX3NvdXJjZUNvZGUnKTsKICB2YXIgb3JpZ2luYWxUYWdzID0gW107CiAgdmFyIGlucHV0U3RyaW5nID0gc2hfZXh0cmFjdFRhZ3MoZWxlbWVudCwgb3JpZ2luYWxUYWdzKTsKICB2YXIgaGlnaGxpZ2h0VGFncyA9IHNoX2hpZ2hsaWdodFN0cmluZyhpbnB1dFN0cmluZywgbGFuZ3VhZ2UpOwogIHZhciB0YWdzID0gc2hfbWVyZ2VUYWdzKG9yaWdpbmFsVGFncywgaGlnaGxpZ2h0VGFncyk7CiAgdmFyIGRvY3VtZW50RnJhZ21lbnQgPSBzaF9pbnNlcnRUYWdzKHRhZ3MsIGlucHV0U3RyaW5nKTsKICB3aGlsZSAoZWxlbWVudC5oYXNDaGlsZE5vZGVzKCkpIHsKICAgIGVsZW1lbnQucmVtb3ZlQ2hpbGQoZWxlbWVudC5maXJzdENoaWxkKTsKICB9CiAgZWxlbWVudC5hcHBlbmRDaGlsZChkb2N1bWVudEZyYWdtZW50KTsKfQoKZnVuY3Rpb24gc2hfZ2V0WE1MSHR0cFJlcXVlc3QoKSB7CiAgaWYgKHdpbmRvdy5BY3RpdmVYT2JqZWN0KSB7CiAgICByZXR1cm4gbmV3IEFjdGl2ZVhPYmplY3QoJ01zeG1sMi5YTUxIVFRQJyk7CiAgfQogIGVsc2UgaWYgKHdpbmRvdy5YTUxIdHRwUmVxdWVzdCkgewogICAgcmV0dXJuIG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogIH0KICB0aHJvdyAnTm8gWE1MSHR0cFJlcXVlc3QgaW1wbGVtZW50YXRpb24gYXZhaWxhYmxlJzsKfQoKZnVuY3Rpb24gc2hfbG9hZChsYW5ndWFnZSwgZWxlbWVudCwgcHJlZml4LCBzdWZmaXgpIHsKICBpZiAobGFuZ3VhZ2UgaW4gc2hfcmVxdWVzdHMpIHsKICAgIHNoX3JlcXVlc3RzW2xhbmd1YWdlXS5wdXNoKGVsZW1lbnQpOwogICAgcmV0dXJuOwogIH0KICBzaF9yZXF1ZXN0c1tsYW5ndWFnZV0gPSBbZWxlbWVudF07CiAgdmFyIHJlcXVlc3QgPSBzaF9nZXRYTUxIdHRwUmVxdWVzdCgpOwogIHZhciB1cmwgPSBwcmVmaXggKyAnc2hfJyArIGxhbmd1YWdlICsgc3VmZml4OwogIHJlcXVlc3Qub3BlbignR0VUJywgdXJsLCB0cnVlKTsKICByZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uICgpIHsKICAgIGlmIChyZXF1ZXN0LnJlYWR5U3RhdGUgPT09IDQpIHsKICAgICAgdHJ5IHsKICAgICAgICBpZiAoISByZXF1ZXN0LnN0YXR1cyB8fCByZXF1ZXN0LnN0YXR1cyA9PT0gMjAwKSB7CiAgICAgICAgICBldmFsKHJlcXVlc3QucmVzcG9uc2VUZXh0KTsKICAgICAgICAgIHZhciBlbGVtZW50cyA9IHNoX3JlcXVlc3RzW2xhbmd1YWdlXTsKICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlbWVudHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgc2hfaGlnaGxpZ2h0RWxlbWVudChlbGVtZW50c1tpXSwgc2hfbGFuZ3VhZ2VzW2xhbmd1YWdlXSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgdGhyb3cgJ0hUVFAgZXJyb3I6IHN0YXR1cyAnICsgcmVxdWVzdC5zdGF0dXM7CiAgICAgICAgfQogICAgICB9CiAgICAgIGZpbmFsbHkgewogICAgICAgIHJlcXVlc3QgPSBudWxsOwogICAgICB9CiAgICB9CiAgfTsKICByZXF1ZXN0LnNlbmQobnVsbCk7Cn0KCi8qKgpIaWdobGlnaHRzIGFsbCBlbGVtZW50cyBjb250YWluaW5nIHNvdXJjZSBjb2RlIG9uIHRoZSBjdXJyZW50IHBhZ2UuIEVsZW1lbnRzCmNvbnRhaW5pbmcgc291cmNlIGNvZGUgbXVzdCBiZSAicHJlIiBlbGVtZW50cyB3aXRoIGEgImNsYXNzIiBhdHRyaWJ1dGUgb2YKInNoX0xBTkdVQUdFIiwgd2hlcmUgTEFOR1VBR0UgaXMgYSB2YWxpZCBsYW5ndWFnZSBpZGVudGlmaWVyOyBlLmcuLCAic2hfamF2YSIKaWRlbnRpZmllcyB0aGUgZWxlbWVudCBhcyBjb250YWluaW5nICJqYXZhIiBsYW5ndWFnZSBzb3VyY2UgY29kZS4KKi8KZnVuY3Rpb24gaGlnaGxpZ2h0KHByZWZpeCwgc3VmZml4LCB0YWcpIHsKICB2YXIgbm9kZUxpc3QgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSh0YWcpOwogIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZUxpc3QubGVuZ3RoOyBpKyspIHsKICAgIHZhciBlbGVtZW50ID0gbm9kZUxpc3QuaXRlbShpKTsKICAgIHZhciBodG1sQ2xhc3NlcyA9IHNoX2dldENsYXNzZXMoZWxlbWVudCk7CiAgICB2YXIgaGlnaGxpZ2h0ZWQgPSBmYWxzZTsKICAgIHZhciBkb250aGlnaGxpZ2h0ID0gZmFsc2U7CiAgICBmb3IgKHZhciBqID0gMDsgaiA8IGh0bWxDbGFzc2VzLmxlbmd0aDsgaisrKSB7CiAgICAgIHZhciBodG1sQ2xhc3MgPSBodG1sQ2xhc3Nlc1tqXS50b0xvd2VyQ2FzZSgpOwogICAgICBpZiAoaHRtbENsYXNzID09PSAnc2hfbm9uZScpIHsKICAgICAgICBkb250aGlnaGxpZ2h0ID0gdHJ1ZQogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChodG1sQ2xhc3Muc3Vic3RyKDAsIDMpID09PSAnc2hfJykgewogICAgICAgIHZhciBsYW5ndWFnZSA9IGh0bWxDbGFzcy5zdWJzdHJpbmcoMyk7CiAgICAgICAgaWYgKGxhbmd1YWdlIGluIHNoX2xhbmd1YWdlcykgewogICAgICAgICAgc2hfaGlnaGxpZ2h0RWxlbWVudChlbGVtZW50LCBzaF9sYW5ndWFnZXNbbGFuZ3VhZ2VdKTsKICAgICAgICAgIGhpZ2hsaWdodGVkID0gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgZWxzZSBpZiAodHlwZW9mKHByZWZpeCkgPT09ICdzdHJpbmcnICYmIHR5cGVvZihzdWZmaXgpID09PSAnc3RyaW5nJykgewogICAgICAgICAgc2hfbG9hZChsYW5ndWFnZSwgZWxlbWVudCwgcHJlZml4LCBzdWZmaXgpOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgIHRocm93ICdGb3VuZCA8JyArIHRhZyArICc+IGVsZW1lbnQgd2l0aCBjbGFzcz0iJyArIGh0bWxDbGFzcyArICciLCBidXQgbm8gc3VjaCBsYW5ndWFnZSBleGlzdHMnOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogICAgaWYgKGhpZ2hsaWdodGVkID09PSBmYWxzZSAmJiBkb250aGlnaGxpZ2h0ID09IGZhbHNlKSB7CiAgICAgIHNoX2hpZ2hsaWdodEVsZW1lbnQoZWxlbWVudCwgc2hfbGFuZ3VhZ2VzWyJqYXZhc2NyaXB0Il0pOwogICAgfQogIH0KfQoKCgpmdW5jdGlvbiBzaF9oaWdobGlnaHREb2N1bWVudChwcmVmaXgsIHN1ZmZpeCkgewogIGhpZ2hsaWdodChwcmVmaXgsIHN1ZmZpeCwgJ3R0Jyk7CiAgaGlnaGxpZ2h0KHByZWZpeCwgc3VmZml4LCAnY29kZScpOwogIGhpZ2hsaWdodChwcmVmaXgsIHN1ZmZpeCwgJ3ByZScpOwp9Cg=="></script>
<script src="data:application/javascript;base64,aWYoIXRoaXMuc2hfbGFuZ3VhZ2VzKXt0aGlzLnNoX2xhbmd1YWdlcz17fX1zaF9sYW5ndWFnZXMuamF2YXNjcmlwdD1bW1svXC9cL1wvL2csInNoX2NvbW1lbnQiLDFdLFsvXC9cLy9nLCJzaF9jb21tZW50Iiw3XSxbL1wvXCpcKi9nLCJzaF9jb21tZW50Iiw4XSxbL1wvXCovZywic2hfY29tbWVudCIsOV0sWy9cYig/OmFic3RyYWN0fGJyZWFrfGNhc2V8Y2F0Y2h8Y2xhc3N8Y29uc3R8Y29udGludWV8ZGVidWdnZXJ8ZGVmYXVsdHxkZWxldGV8ZG98ZWxzZXxlbnVtfGV4cG9ydHxleHRlbmRzfGZhbHNlfGZpbmFsfGZpbmFsbHl8Zm9yfGZ1bmN0aW9ufGdvdG98aWZ8aW1wbGVtZW50c3xpbnxpbnN0YW5jZW9mfGludGVyZmFjZXxuYXRpdmV8bmV3fG51bGx8cHJpdmF0ZXxwcm90ZWN0ZWR8cHJvdG90eXBlfHB1YmxpY3xyZXR1cm58c3RhdGljfHN1cGVyfHN3aXRjaHxzeW5jaHJvbml6ZWR8dGhyb3d8dGhyb3dzfHRoaXN8dHJhbnNpZW50fHRydWV8dHJ5fHR5cGVvZnx2YXJ8dm9sYXRpbGV8d2hpbGV8d2l0aClcYi9nLCJzaF9rZXl3b3JkIiwtMV0sWy8oXCtcK3wtLXxcKXxcXSkoXHMqKShcLz0/KD8hWypcL10pKS9nLFsic2hfc3ltYm9sIiwic2hfbm9ybWFsIiwic2hfc3ltYm9sIl0sLTFdLFsvKDB4W0EtRmEtZjAtOV0rfCg/OltcZF0qXC4pP1tcZF0rKD86W2VFXVsrLV0/W1xkXSspPykoXHMqKShcLyg/IVsqXC9dKSkvZyxbInNoX251bWJlciIsInNoX25vcm1hbCIsInNoX3N5bWJvbCJdLC0xXSxbLyhbQS1aYS16JF9dW0EtWmEtejAtOSRfXSpccyopKFwvPT8oPyFbKlwvXSkpL2csWyJzaF9ub3JtYWwiLCJzaF9zeW1ib2wiXSwtMV0sWy9cLyg/OlxcLnxbXipcXFwvXSkoPzpcXC58W15cXFwvXSkqXC9bZ2ltXSovZywic2hfcmVnZXhwIiwtMV0sWy9cYlsrLV0/KD86KD86MHhbQS1GYS1mMC05XSspfCg/Oig/OltcZF0qXC4pP1tcZF0rKD86W2VFXVsrLV0/W1xkXSspPykpdT8oPzooPzppbnQoPzo4fDE2fDMyfDY0KSl8TCk/XGIvZywic2hfbnVtYmVyIiwtMV0sWy8iL2csInNoX3N0cmluZyIsMTBdLFsvJy9nLCJzaF9zdHJpbmciLDExXSxbL358IXwlfFxefFwqfFwofFwpfC18XCt8PXxcW3xcXXxcXHw6fDt8LHxcLnxcL3xcP3wmfDx8PnxcfC9nLCJzaF9zeW1ib2wiLC0xXSxbL1x7fFx9L2csInNoX2NicmFja2V0IiwtMV0sWy9cYig/Ok1hdGh8SW5maW5pdHl8TmFOfHVuZGVmaW5lZHxhcmd1bWVudHMpXGIvZywic2hfcHJlZGVmX3ZhciIsLTFdLFsvXGIoPzpBcnJheXxCb29sZWFufERhdGV8RXJyb3J8RXZhbEVycm9yfEZ1bmN0aW9ufE51bWJlcnxPYmplY3R8UmFuZ2VFcnJvcnxSZWZlcmVuY2VFcnJvcnxSZWdFeHB8U3RyaW5nfFN5bnRheEVycm9yfFR5cGVFcnJvcnxVUklFcnJvcnxkZWNvZGVVUkl8ZGVjb2RlVVJJQ29tcG9uZW50fGVuY29kZVVSSXxlbmNvZGVVUklDb21wb25lbnR8ZXZhbHxpc0Zpbml0ZXxpc05hTnxwYXJzZUZsb2F0fHBhcnNlSW50KVxiL2csInNoX3ByZWRlZl9mdW5jIiwtMV0sWy8oPzpbQS1aYS16XXxfKVtBLVphLXowLTlfXSooPz1bIFx0XSpcKCkvZywic2hfZnVuY3Rpb24iLC0xXV0sW1svJC9nLG51bGwsLTJdLFsvKD86PD8pW0EtWmEtejAtOV9cLlwvXC1ffl0rQFtBLVphLXowLTlfXC5cL1wtX35dKyg/Oj4/KXwoPzo8PylbQS1aYS16MC05X10rOlwvXC9bQS1aYS16MC05X1wuXC9cLV9+XSsoPzo+PykvZywic2hfdXJsIiwtMV0sWy88XD94bWwvZywic2hfcHJlcHJvYyIsMiwxXSxbLzwhRE9DVFlQRS9nLCJzaF9wcmVwcm9jIiw0LDFdLFsvPCEtLS9nLCJzaF9jb21tZW50Iiw1XSxbLzwoPzpcLyk/W0EtWmEtel0oPzpbQS1aYS16MC05XzouLV0qKSg/OlwvKT8+L2csInNoX2tleXdvcmQiLC0xXSxbLzwoPzpcLyk/W0EtWmEtel0oPzpbQS1aYS16MC05XzouLV0qKS9nLCJzaF9rZXl3b3JkIiw2LDFdLFsvJig/OltBLVphLXowLTldKyk7L2csInNoX3ByZXByb2MiLC0xXSxbLzwoPzpcLyk/W0EtWmEtel1bQS1aYS16MC05XSooPzpcLyk/Pi9nLCJzaF9rZXl3b3JkIiwtMV0sWy88KD86XC8pP1tBLVphLXpdW0EtWmEtejAtOV0qL2csInNoX2tleXdvcmQiLDYsMV0sWy9AW0EtWmEtel0rL2csInNoX3R5cGUiLC0xXSxbLyg/OlRPRE98RklYTUV8QlVHKSg/Ols6XT8pL2csInNoX3RvZG8iLC0xXV0sW1svXD8+L2csInNoX3ByZXByb2MiLC0yXSxbLyhbXj0iIFx0Pl0rKShbIFx0XSopKD0/KS9nLFsic2hfdHlwZSIsInNoX25vcm1hbCIsInNoX3N5bWJvbCJdLC0xXSxbLyIvZywic2hfc3RyaW5nIiwzXV0sW1svXFwoPzpcXHwiKS9nLG51bGwsLTFdLFsvIi9nLCJzaF9zdHJpbmciLC0yXV0sW1svPi9nLCJzaF9wcmVwcm9jIiwtMl0sWy8oW149IiBcdD5dKykoWyBcdF0qKSg9PykvZyxbInNoX3R5cGUiLCJzaF9ub3JtYWwiLCJzaF9zeW1ib2wiXSwtMV0sWy8iL2csInNoX3N0cmluZyIsM11dLFtbLy0tPi9nLCJzaF9jb21tZW50IiwtMl0sWy88IS0tL2csInNoX2NvbW1lbnQiLDVdXSxbWy8oPzpcLyk/Pi9nLCJzaF9rZXl3b3JkIiwtMl0sWy8oW149IiBcdD5dKykoWyBcdF0qKSg9PykvZyxbInNoX3R5cGUiLCJzaF9ub3JtYWwiLCJzaF9zeW1ib2wiXSwtMV0sWy8iL2csInNoX3N0cmluZyIsM11dLFtbLyQvZyxudWxsLC0yXV0sW1svXCpcLy9nLCJzaF9jb21tZW50IiwtMl0sWy8oPzo8PylbQS1aYS16MC05X1wuXC9cLV9+XStAW0EtWmEtejAtOV9cLlwvXC1ffl0rKD86Pj8pfCg/Ojw/KVtBLVphLXowLTlfXSs6XC9cL1tBLVphLXowLTlfXC5cL1wtX35dKyg/Oj4/KS9nLCJzaF91cmwiLC0xXSxbLzxcP3htbC9nLCJzaF9wcmVwcm9jIiwyLDFdLFsvPCFET0NUWVBFL2csInNoX3ByZXByb2MiLDQsMV0sWy88IS0tL2csInNoX2NvbW1lbnQiLDVdLFsvPCg/OlwvKT9bQS1aYS16XSg/OltBLVphLXowLTlfOi4tXSopKD86XC8pPz4vZywic2hfa2V5d29yZCIsLTFdLFsvPCg/OlwvKT9bQS1aYS16XSg/OltBLVphLXowLTlfOi4tXSopL2csInNoX2tleXdvcmQiLDYsMV0sWy8mKD86W0EtWmEtejAtOV0rKTsvZywic2hfcHJlcHJvYyIsLTFdLFsvPCg/OlwvKT9bQS1aYS16XVtBLVphLXowLTldKig/OlwvKT8+L2csInNoX2tleXdvcmQiLC0xXSxbLzwoPzpcLyk/W0EtWmEtel1bQS1aYS16MC05XSovZywic2hfa2V5d29yZCIsNiwxXSxbL0BbQS1aYS16XSsvZywic2hfdHlwZSIsLTFdLFsvKD86VE9ET3xGSVhNRXxCVUcpKD86WzpdPykvZywic2hfdG9kbyIsLTFdXSxbWy9cKlwvL2csInNoX2NvbW1lbnQiLC0yXSxbLyg/Ojw/KVtBLVphLXowLTlfXC5cL1wtX35dK0BbQS1aYS16MC05X1wuXC9cLV9+XSsoPzo+Pyl8KD86PD8pW0EtWmEtejAtOV9dKzpcL1wvW0EtWmEtejAtOV9cLlwvXC1ffl0rKD86Pj8pL2csInNoX3VybCIsLTFdLFsvKD86VE9ET3xGSVhNRXxCVUcpKD86WzpdPykvZywic2hfdG9kbyIsLTFdXSxbWy8iL2csInNoX3N0cmluZyIsLTJdLFsvXFwuL2csInNoX3NwZWNpYWxjaGFyIiwtMV1dLFtbLycvZywic2hfc3RyaW5nIiwtMl0sWy9cXC4vZywic2hfc3BlY2lhbGNoYXIiLC0xXV1dOw=="></script>
<script>highlight(undefined, undefined, 'pre');</script>
</body></html>
================================================
FILE: docs-nodejs/assert.html
================================================
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Assert | Node.js v12.10.0 Documentation</title>
<link rel="stylesheet" href="data:text/css;base64,LyogbGF0aW4tZXh0ICovCkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnTGF0byc7CiAgZm9udC1zdHlsZTogaXRhbGljOwogIGZvbnQtd2VpZ2h0OiA0MDA7CiAgc3JjOiBsb2NhbCgnTGF0byBJdGFsaWMnKSwgbG9jYWwoJ0xhdG8tSXRhbGljJyksIHVybChodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tL3MvbGF0by92MTYvUzZ1OHc0Qk1VVFBIanhzQVVpLXFOaVhnN2VVMC53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEl0YWxpYycpLCBsb2NhbCgnTGF0by1JdGFsaWMnKSwgdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9sYXRvL3YxNi9TNnU4dzRCTVVUUEhqeHNBWEMtcU5pWGc3US53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDAwMC0wMEZGLCBVKzAxMzEsIFUrMDE1Mi0wMTUzLCBVKzAyQkItMDJCQywgVSswMkM2LCBVKzAyREEsIFUrMDJEQywgVSsyMDAwLTIwNkYsIFUrMjA3NCwgVSsyMEFDLCBVKzIxMjIsIFUrMjE5MSwgVSsyMTkzLCBVKzIyMTIsIFUrMjIxNSwgVStGRUZGLCBVK0ZGRkQ7Cn0KLyogbGF0aW4tZXh0ICovCkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnTGF0byc7CiAgZm9udC1zdHlsZTogbm9ybWFsOwogIGZvbnQtd2VpZ2h0OiA0MDA7CiAgc3JjOiBsb2NhbCgnTGF0byBSZWd1bGFyJyksIGxvY2FsKCdMYXRvLVJlZ3VsYXInKSwgdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9sYXRvL3YxNi9TNnV5dzRCTVVUUEhqeEF3WGlXdEZDZlE3QS53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBzcmM6IGxvY2FsKCdMYXRvIFJlZ3VsYXInKSwgbG9jYWwoJ0xhdG8tUmVndWxhcicpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dXl3NEJNVVRQSGp4NHdYaVd0RkNjLndvZmYyKSBmb3JtYXQoJ3dvZmYyJyk7CiAgdW5pY29kZS1yYW5nZTogVSswMDAwLTAwRkYsIFUrMDEzMSwgVSswMTUyLTAxNTMsIFUrMDJCQi0wMkJDLCBVKzAyQzYsIFUrMDJEQSwgVSswMkRDLCBVKzIwMDAtMjA2RiwgVSsyMDc0LCBVKzIwQUMsIFUrMjEyMiwgVSsyMTkxLCBVKzIxOTMsIFUrMjIxMiwgVSsyMjE1LCBVK0ZFRkYsIFUrRkZGRDsKfQovKiBsYXRpbi1leHQgKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEJvbGQnKSwgbG9jYWwoJ0xhdG8tQm9sZCcpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dTl3NEJNVVRQSGg2VVZTd2FQR1EzcTVkME43dy53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDEwMC0wMjRGLCBVKzAyNTksIFUrMUUwMC0xRUZGLCBVKzIwMjAsIFUrMjBBMC0yMEFCLCBVKzIwQUQtMjBDRiwgVSsyMTEzLCBVKzJDNjAtMkM3RiwgVStBNzIwLUE3RkY7Cn0KLyogbGF0aW4gKi8KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdMYXRvJzsKICBmb250LXN0eWxlOiBub3JtYWw7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBzcmM6IGxvY2FsKCdMYXRvIEJvbGQnKSwgbG9jYWwoJ0xhdG8tQm9sZCcpLCB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL2xhdG8vdjE2L1M2dTl3NEJNVVRQSGg2VVZTd2lQR1EzcTVkMC53b2ZmMikgZm9ybWF0KCd3b2ZmMicpOwogIHVuaWNvZGUtcmFuZ2U6IFUrMDAwMC0wMEZGLCBVKzAxMzEsIFUrMDE1Mi0wMTUzLCBVKzAyQkItMDJCQywgVSswMkM2LCBVKzAyREEsIFUrMDJEQywgVSsyMDAwLTIwNkYsIFUrMjA3NCwgVSsyMEFDLCBVKzIxMjIsIFUrMjE5MSwgVSsyMTkzLCBVKzIyMTIsIFUrMjIxNSwgVStGRUZGLCBVK0ZGRkQ7Cn0K">
<link rel="stylesheet" href="data:text/css;base64,LyotLS0tLS0tLS0tLS0tLS0tLS0tLS0gTGF5b3V0IGFuZCBUeXBvZ3JhcGh5IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qLwpodG1sIHsKICBmb250LXNpemU6IDFyZW07CiAgb3ZlcmZsb3ctd3JhcDogYnJlYWstd29yZDsKICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDsKICAtbW96LW9zeC1mb250LXNtb290aGluZzogZ3JheXNjYWxlOwogIC13ZWJraXQtZm9udC12YXJpYW50LWxpZ2F0dXJlczogbm9uZTsKICAgICAgICAgIGZvbnQtdmFyaWFudC1saWdhdHVyZXM6IG5vbmU7Cn0KCiogewogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7Cn0KCmJvZHkgewogIGZvbnQtZmFtaWx5OiAiTGF0byIsICJMdWNpZGEgR3JhbmRlIiwgIkx1Y2lkYSBTYW5zIFVuaWNvZGUiLCAiTHVjaWRhIFNhbnMiLCBWZXJkYW5hLCBUYWhvbWEsIHNhbnMtc2VyaWY7CiAgbWFyZ2luOiAwOwogIHBhZGRpbmc6IDA7CiAgY29sb3I6ICMzMzM7CiAgYmFja2dyb3VuZDogI2ZmZjsKfQoKaDEgeyBmb250LXNpemU6IDIuNXJlbSB9CmgyIHsgZm9udC1zaXplOiAycmVtIH0KaDMgeyBmb250LXNpemU6IDEuNzVyZW0gfQpoNCB7IGZvbnQtc2l6ZTogMS41cmVtIH0KaDUgeyBmb250LXNpemU6IDEuMjVyZW0gfQpoNiB7IGZvbnQtc2l6ZTogMXJlbSB9CgpoMSwgaDIsIGgzLCBoNCwgaDUsIGg2IHsKICBtYXJnaW46IDEuNXJlbSAwIDFyZW07CiAgdGV4dC1yZW5kZXJpbmc6IG9wdGltaXplTGVnaWJpbGl0eTsKICBmb250LXdlaWdodDogNzAwOwogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKcHJlLCB0dCwgY29kZSwgLnByZSwgc3Bhbi50eXBlLCBhLnR5cGUgewogIGZvbnQtZmFtaWx5OiBTRk1vbm8tUmVndWxhciwgTWVubG8sIENvbnNvbGFzLCAiTGliZXJhdGlvbiBNb25vIiwgIkNvdXJpZXIgTmV3IiwgbW9ub3NwYWNlOwogIGZvbnQtc2l6ZTogLjllbTsKfQoKI2NvbnRlbnQgewogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKYSwgYTpsaW5rLCBhOmFjdGl2ZSB7CiAgY29sb3I6ICM0Mzg1M2Q7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGJvcmRlci1yYWRpdXM6IDJweDsKICBwYWRkaW5nOiAxcHggM3B4Owp9CgphOmhvdmVyLCBhOmZvY3VzIHsKICBjb2xvcjogI2ZmZjsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjNDM4NTNkOwogIG91dGxpbmU6IG5vbmU7Cn0KCnN0cm9uZyB7CiAgZm9udC13ZWlnaHQ6IDcwMDsKfQoKY29kZSBhOmhvdmVyIHsKICBiYWNrZ3JvdW5kOiBub25lOwp9CgplbSBjb2RlIHsKICBmb250LXN0eWxlOiBub3JtYWw7Cn0KCiNjaGFuZ2Vsb2cgI2d0b2MgewogIGRpc3BsYXk6IG5vbmU7Cn0KCiNndG9jIHsKICBtYXJnaW4tdG9wOiAuNXJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwp9CgojZ3RvYyB1bCB7CiAgbGlzdC1zdHlsZTogbm9uZTsKICBtYXJnaW4tbGVmdDogMDsKICBsaW5lLWhlaWdodDogMS41cmVtOwp9CgojZ3RvYyA+IHVsID4gbGkgewogIGRpc3BsYXk6IGlubGluZTsKICBib3JkZXItcmlnaHQ6IDFweCAjMDAwIHNvbGlkOwogIG1hcmdpbi1yaWdodDogMC40cmVtOwogIHBhZGRpbmctcmlnaHQ6IDAuNHJlbTsKfQoKI2d0b2MgPiB1bCA+IGxpOmxhc3QtY2hpbGQgewogIGJvcmRlci1yaWdodDogbm9uZTsKICBtYXJnaW4tcmlnaHQ6IDA7CiAgcGFkZGluZy1yaWdodDogMDsKfQoKbGkudmVyc2lvbi1waWNrZXIgewogIHBvc2l0aW9uOiByZWxhdGl2ZTsKfQoKbGkudmVyc2lvbi1waWNrZXI6aG92ZXIgPiBhIHsKICBib3JkZXItcmFkaXVzOiAycHggMnB4IDAgMDsKfQoKbGkudmVyc2lvbi1waWNrZXI6aG92ZXIgPiBvbCB7CiAgZGlzcGxheTogYmxvY2s7CiAgei1pbmRleDogMTsKfQoKbGkudmVyc2lvbi1waWNrZXIgYSBzcGFuIHsKICBmb250LXNpemU6IC43cmVtOwp9CgpvbC52ZXJzaW9uLXBpY2tlciB7CiAgYmFja2dyb3VuZDogI2ZmZjsKICBib3JkZXI6IDFweCAjNDM4NTNkIHNvbGlkOwogIGJvcmRlci1yYWRpdXM6IDAgMCAycHggMnB4OwogIGRpc3BsYXk6IG5vbmU7CiAgbGlzdC1zdHlsZTogbm9uZTsKICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgcmlnaHQ6IDA7CiAgdG9wOiAxLjI1cmVtOwogIHdpZHRoOiAxMDAlOwp9CgojZ3RvYyBvbC52ZXJzaW9uLXBpY2tlciBsaSB7CiAgZGlzcGxheTogYmxvY2s7CiAgYm9yZGVyLXJpZ2h0OiAwOwogIG1hcmdpbi1yaWdodDogMDsKfQoKb2wudmVyc2lvbi1waWNrZXIgbGkgYSB7CiAgYm9yZGVyLXJhZGl1czogMDsKICBkaXNwbGF5OiBibG9jazsKICBtYXJnaW46IDA7CiAgcGFkZGluZzogLjFyZW07CiAgcGFkZGluZy1sZWZ0OiAxcmVtOwp9CgpvbC52ZXJzaW9uLXBpY2tlciBsaTpsYXN0LWNoaWxkIGEgewogIGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiAxcHg7CiAgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogMXB4Owp9CgoubGluZSB7CiAgd2lkdGg6IGNhbGMoMTAwJSAtIDFyZW0pOwogIGRpc3BsYXk6IGJsb2NrOwogIHBhZGRpbmctYm90dG9tOiAxcHg7Cn0KCi5hcGlfc3RhYmlsaXR5IHsKICBjb2xvcjogd2hpdGUgIWltcG9ydGFudDsKICBtYXJnaW46IDAgMCAxcmVtIDA7CiAgZm9udC1mYW1pbHk6ICJMYXRvIiwgIkx1Y2lkYSBHcmFuZGUiLCAiTHVjaWRhIFNhbnMgVW5pY29kZSIsICJMdWNpZGEgU2FucyIsIFZlcmRhbmEsIFRhaG9tYSwgc2Fucy1zZXJpZjsKICBwYWRkaW5nOiAxcmVtOwogIGxpbmUtaGVpZ2h0OiAxLjU7Cn0KCi5hcGlfc3RhYmlsaXR5ICogewogIGNvbG9yOiB3aGl0ZSAhaW1wb3J0YW50Owp9CgouYXBpX3N0YWJpbGl0eSBhIHsKICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsKfQoKLmFwaV9zdGFiaWxpdHkgYTpob3ZlciwgLmFwaV9zdGFiaWxpdHkgYTphY3RpdmUsIC5hcGlfc3RhYmlsaXR5IGE6Zm9jdXMgewogIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDI1NSwgLjQpOwp9CgouYXBpX3N0YWJpbGl0eSBhIGNvZGUgewogIGJhY2tncm91bmQ6IG5vbmU7Cn0KCi5hcGlfc3RhYmlsaXR5XzAgewogIGJhY2tncm91bmQtY29sb3I6ICNENjAwMjc7Cn0KCi5hcGlfc3RhYmlsaXR5XzEgewogIGJhY2tncm91bmQtY29sb3I6ICNFQzUzMTU7Cn0KCi5hcGlfc3RhYmlsaXR5XzIgewogIGJhY2tncm91bmQtY29sb3I6ICM0RUJBMEY7Cn0KCi5hcGlfbWV0YWRhdGEgewogIGZvbnQtc2l6ZTogLjg1cmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07Cn0KCi5hcGlfbWV0YWRhdGEgc3BhbiB7CiAgbWFyZ2luLXJpZ2h0OiAxcmVtOwp9CgouYXBpX21ldGFkYXRhIHNwYW46bGFzdC1jaGlsZCB7CiAgbWFyZ2luLXJpZ2h0OiAwcHg7Cn0KCnVsLnBsYWluIHsKICBsaXN0LXN0eWxlOiBub25lOwp9CgphYmJyIHsKICBib3JkZXItYm90dG9tOiAxcHggZG90dGVkICM0NTQ1NDU7Cn0KCnAgewogIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7CiAgbWFyZ2luOiAwIDAgMS4xMjVyZW0gMDsKICBsaW5lLWhlaWdodDogMS41Owp9CgojYXBpY29udGVudCA+ICo6bGFzdC1jaGlsZCB7CiAgbWFyZ2luLWJvdHRvbTogMDsKICBwYWRkaW5nLWJvdHRvbTogMnJlbTsKfQoKdGFibGUgewogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7CiAgbWFyZ2luOiAwIDAgMS41cmVtIDA7Cn0KCnRoLCB0ZCB7CiAgYm9yZGVyOiAxcHggc29saWQgI2FhYTsKICBwYWRkaW5nOiAuNzVyZW0gMXJlbSAuNzVyZW0gMXJlbTsKICB2ZXJ0aWNhbC1hbGlnbjogdG9wOwp9Cgp0aCB7CiAgdGV4dC1hbGlnbjpsZWZ0Owp9CgpvbCwgdWwsIGRsIHsKICBtYXJnaW46IDAgMCAuNnJlbSAwOwogIHBhZGRpbmc6IDA7Cn0KCm9sIHVsLCBvbCBvbCwgb2wgZGwsIHVsIHVsLCB1bCBvbCwgdWwgZGwsIGRsIHVsLCBkbCBvbCwgZGwgZGwgewogIG1hcmdpbi1ib3R0b206IDA7Cn0KCnVsLCBvbCB7CiAgbWFyZ2luLWxlZnQ6IDJyZW07Cn0KCmRsIGR0IHsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgbWFyZ2luOiAxLjVyZW0gMCAwOwp9CgpkbCBkZCB7CiAgcG9zaXRpb246IHJlbGF0aXZlOwogIG1hcmdpbjogMCAxcmVtIDA7Cn0KCmRkICsgZHQucHJlIHsKICBtYXJnaW4tdG9wOiAxLjZyZW07Cn0KCiNhcGljb250ZW50IHsKICBwYWRkaW5nLXRvcDogMXJlbTsKfQoKI2FwaWNvbnRlbnQgLmxpbmUgewogIHdpZHRoOiBjYWxjKDUwJSAtIDFyZW0pOwogIG1hcmdpbjogMXJlbSAxcmVtIC45NXJlbTsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjY2NjOwp9CgpoMiArIGgyIHsKICBtYXJnaW46IDAgMCAuNXJlbTsKfQoKaDMgKyBoMyB7CiAgbWFyZ2luOiAwIDAgLjVyZW07Cn0KCmgyLCBoMywgaDQsIGg1IHsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgcGFkZGluZy1yaWdodDogNDBweDsKfQoKLnNyY2xpbmsgewogIGZsb2F0OiByaWdodDsKICBmb250LXNpemU6IHNtYWxsZXI7Cn0KCmgxIHNwYW4sIGgyIHNwYW4sIGgzIHNwYW4sIGg0IHNwYW4gewogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICBkaXNwbGF5OiBibG9jazsKICB0b3A6IDA7CiAgcmlnaHQ6IDA7Cn0KCmgxIHNwYW46aG92ZXIsIGgyIHNwYW46aG92ZXIsIGgzIHNwYW46aG92ZXIsIGg0IHNwYW46aG92ZXIgewogIG9wYWNpdHk6IDE7Cn0KCmgxIHNwYW4gYSwgaDIgc3BhbiBhLCBoMyBzcGFuIGEsIGg0IHNwYW4gYSB7CiAgY29sb3I6ICMwMDA7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGZvbnQtd2VpZ2h0OiBib2xkOwp9CgpwcmUsIHR0LCBjb2RlIHsKICBsaW5lLWhlaWdodDogMS41cmVtOwogIG1hcmdpbjogMDsgcGFkZGluZzogMDsKfQoKLnByZSB7CiAgbGluZS1oZWlnaHQ6IDEuNXJlbTsKfQoKcHJlIHsKICBwYWRkaW5nOiAxcmVtOwogIHZlcnRpY2FsLWFsaWduOiB0b3A7CiAgYmFja2dyb3VuZDogI2YyZjJmMjsKICBtYXJnaW46IDFyZW07CiAgb3ZlcmZsb3cteDogYXV0bzsKfQoKcHJlID4gY29kZSB7CiAgcGFkZGluZzogMDsKfQoKcHJlICsgaDMgewogIG1hcmdpbi10b3A6IDIuMjI1cmVtOwp9Cgpjb2RlLnByZSB7CiAgd2hpdGUtc3BhY2U6IHByZTsKfQoKI2ludHJvIHsKICBtYXJnaW4tdG9wOiAxLjI1cmVtOwogIG1hcmdpbi1sZWZ0OiAxcmVtOwp9CgojaW50cm8gYSB7CiAgY29sb3I6ICNkZGQ7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmhyIHsKICBiYWNrZ3JvdW5kOiBub25lOwogIGJvcmRlcjogbWVkaXVtIG5vbmU7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM3YTdhN2E7CiAgbWFyZ2luOiAwIDAgMXJlbSAwOwp9CgojdG9jIGgyIHsKICBtYXJnaW4tdG9wOiAwOwogIG1hcmdpbjogMS41cmVtIDA7Cn0KCiN0b2MgcCB7CiAgbWFyZ2luOiAwOwp9CgojdG9jIHVsIGEgewogIHRleHQtZGVjb3JhdGlvbjpub25lOwp9CgojdG9jIHVsIGxpIHsKICBtYXJnaW4tYm90dG9tOiAuNjY2cmVtOwogIGxpc3Qtc3R5bGU6IHNxdWFyZSBvdXRzaWRlOwp9CgojdG9jIGxpID4gdWwgewogIG1hcmdpbi10b3A6IC42NjZyZW07Cn0KCiN0b2MgLnN0YWJpbGl0eV8wOjphZnRlciB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2Q1MDAyNzsKICBjb2xvcjogI2ZmZjsKICBjb250ZW50OiAiZGVwcmVjYXRlZCI7CiAgbWFyZ2luLWxlZnQ6IC4yNXJlbTsKICBwYWRkaW5nOiAxcHggM3B4OwogIGJvcmRlci1yYWRpdXM6IDNweDsKfQoKI2FwaWNvbnRlbnQgbGkgewogIG1hcmdpbi1ib3R0b206IC41cmVtOwp9CgojYXBpY29udGVudCBsaTpsYXN0LWNoaWxkIHsKICBtYXJnaW4tYm90dG9tOiAwOwp9Cgp0dCwgY29kZSB7CiAgY29sb3I6ICMwNDA0MDQ7CiAgYmFja2dyb3VuZC1jb2xvcjogI2YyZjJmMjsKICBib3JkZXItcmFkaXVzOiAycHg7CiAgcGFkZGluZzogMXB4IDNweDsKfQoKLmFwaV9zdGFiaWxpdHkgY29kZSB7CiAgYmFja2dyb3VuZDogcmdiYSgwLCAwLCAwLCAuMSk7Cn0KCmEgY29kZSB7CiAgY29sb3I6IGluaGVyaXQ7CiAgYmFja2dyb3VuZDogaW5oZXJpdDsKICBwYWRkaW5nOiAwOwp9CgoudHlwZSB7CiAgbGluZS1oZWlnaHQ6IDEuNXJlbTsKfQoKI2NvbHVtbjEuaW50ZXJpb3IgewogIG1hcmdpbi1sZWZ0OiAyMzRweDsKICBwYWRkaW5nOiAwIDJyZW07CiAgLXdlYmtpdC1wYWRkaW5nLXN0YXJ0OiAxLjVyZW07Cn0KCiNjb2x1bW4yLmludGVyaW9yIHsKICB3aWR0aDogMjM0cHg7CiAgYmFja2dyb3VuZDogIzMzMzsKICBwb3NpdGlvbjogZml4ZWQ7CiAgbGVmdDogMDsKICB0b3A6IDA7CiAgYm90dG9tOiAwOwogIG92ZXJmbG93LXg6IGhpZGRlbjsKICBvdmVyZmxvdy15OiBzY3JvbGw7Cn0KCiNjb2x1bW4yIHVsIHsKICBsaXN0LXN0eWxlOiBub25lOwogIG1hcmdpbjogLjlyZW0gMCAuNXJlbTsKICBiYWNrZ3JvdW5kOiAjMzMzOwp9CgojY29sdW1uMiA+IDpmaXJzdC1jaGlsZCB7CiAgbWFyZ2luOiAxLjI1cmVtOwogIGZvbnQtc2l6ZTogMS41cmVtOwp9CgojY29sdW1uMiA+IHVsOm50aC1jaGlsZCgyKSB7CiAgbWFyZ2luOiAxLjI1cmVtIDAgLjVyZW07Cn0KCiNjb2x1bW4yID4gdWw6bGFzdC1jaGlsZCB7CiAgbWFyZ2luOiAuOXJlbSAwIDEuMjVyZW07Cn0KCiNjb2x1bW4yIHVsIGxpIHsKICBwYWRkaW5nLWxlZnQ6IDEuMjVyZW07CiAgbWFyZ2luLWJvdHRvbTogLjVyZW07CiAgcGFkZGluZy1ib3R0b206IC41cmVtOwp9CgojY29sdW1uMiAubGluZSB7CiAgbWFyZ2luOiAwIC41cmVtOwogIGJhY2tncm91bmQtY29sb3I6ICM3MDcwNzA7Cn0KCiNjb2x1bW4yIHVsIGxpOmxhc3QtY2hpbGQgewogIG1hcmdpbi1ib3R0b206IDA7Cn0KCiNjb2x1bW4yIHVsIGxpIGEgewogIGNvbG9yOiAjY2NjOwogIGJvcmRlci1yYWRpdXM6IDA7Cn0KCiNjb2x1bW4yIHVsIGxpIGEuYWN0aXZlLCAjY29sdW1uMiB1bCBsaSBhLmFjdGl2ZTpob3ZlciwKI2NvbHVtbjIgdWwgbGkgYS5hY3RpdmU6Zm9jdXMgewogIGNvbG9yOiAjNDM4NTNkOwogIGJvcmRlci1yYWRpdXM6IDA7CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICM0Mzg1M2Q7CiAgYmFja2dyb3VuZDogbm9uZTsKfQoKI2ludHJvIGE6aG92ZXIsICNpbnRybyBhOmZvY3VzLAojY29sdW1uMiB1bCBsaSBhOmhvdmVyLCAjY29sdW1uMiB1bCBsaSBhOmZvY3VzIHsKICBjb2xvcjogI2ZmZjsKICBiYWNrZ3JvdW5kOiBub25lOwp9CgpzcGFuID4gLm1hcmssIHNwYW4gPiAubWFyazp2aXNpdGVkIHsKICBjb2xvcjogIzcwNzA3MDsKICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgdG9wOiAwcHg7CiAgcmlnaHQ6IDBweDsKfQoKc3BhbiA+IC5tYXJrOmhvdmVyLCBzcGFuID4gLm1hcms6Zm9jdXMsIHNwYW4gPiAubWFyazphY3RpdmUgewogIGNvbG9yOiAjNDM4NTNkOwogIGJhY2tncm91bmQ6IG5vbmU7Cn0KCnRoID4gKjpsYXN0LWNoaWxkLCB0ZCA+ICo6bGFzdC1jaGlsZCB7CiAgbWFyZ2luLWJvdHRvbTogMDsKfQoKLmNoYW5nZWxvZyA+IHN1bW1hcnkgewogIG1hcmdpbjogLjVyZW0gMDsKICBwYWRkaW5nOiAuNXJlbSAwOwogIGN1cnNvcjogcG9pbnRlcjsKfQoKLyogc2ltcGxlciBjbGVhcmZpeCAqLwouY2xlYXJmaXg6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKICBkaXNwbGF5OiBibG9jazsKICBoZWlnaHQ6IDA7CiAgY2xlYXI6IGJvdGg7CiAgdmlzaWJpbGl0eTogaGlkZGVuOwp9CgouZ2l0aHViX2ljb24gewogIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7CiAgbWFyZ2luOiAtMnB4IDNweCAwIDA7Cn0KCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogMTAyNHB4KSB7CiAgI2NvbnRlbnQgewogICAgb3ZlcmZsb3c6IHZpc2libGU7CiAgfQogICNjb2x1bW4xLmludGVyaW9yIHsKICAgIG1hcmdpbi1sZWZ0OiAwOwogICAgcGFkZGluZy1sZWZ0OiAuNXJlbTsKICAgIHBhZGRpbmctcmlnaHQ6IC41cmVtOwogICAgd2lkdGg6IGF1dG87CiAgICBvdmVyZmxvdy15OiB2aXNpYmxlOwogIH0KICAjY29sdW1uMiB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KfQoKQG1lZGlhIHByaW50IHsKICBodG1sIHsKICAgIGhlaWdodDogYXV0bzsKICAgIGZvbnQtc2l6ZTogMC43NWVtOwogIH0KICAjY29sdW1uMi5pbnRlcmlvciB7CiAgICBkaXNwbGF5OiBub25lOwogIH0KICAjY29sdW1uMS5pbnRlcmlvciB7CiAgICBtYXJnaW4tbGVmdDogMHB4OwogICAgcGFkZGluZzogMHB4OwogICAgb3ZlcmZsb3cteTogYXV0bzsKICB9CiAgLmFwaV9tZXRhZGF0YSwKICAjdG9jLAogIC5zcmNsaW5rLAogICNndG9jLAogIC5tYXJrIHsKICAgIGRpc3BsYXk6IG5vbmU7CiAgfQogIGgxIHsKICAgIGZvbnQtc2l6ZTogMnJlbTsKICB9CiAgaDIgewogICAgZm9udC1zaXplOiAxLjc1cmVtOwogIH0KICBoMyB7CiAgICBmb250LXNpemU6IDEuNXJlbTsKICB9CiAgaDQgewogICAgZm9udC1zaXplOiAxLjNyZW07CiAgfQogIGg1IHsKICAgIGZvbnQtc2l6ZTogMS4ycmVtOwogIH0KICBoNiB7CiAgICBmb250LXNpemU6IDEuMXJlbTsKICB9CiAgLmFwaV9zdGFiaWxpdHkgewogICAgZGlzcGxheTogaW5saW5lLWJsb2NrOwogIH0KICAuYXBpX3N0YWJpbGl0eSBhIHsKICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICB9CiAgYSB7CiAgICBjb2xvcjogaW5oZXJpdDsKICB9CiAgI2FwaWNvbnRlbnQgewogICAgb3ZlcmZsb3c6IGhpZGRlbjsKICB9Cn0K">
<link rel="stylesheet" href="data:text/css;base64,LnNoX3NvdXJjZUNvZGUgewogIGZvbnQtd2VpZ2h0OiBub3JtYWw7CiAgZm9udC1zdHlsZTogbm9ybWFsOwp9Cgouc2hfc291cmNlQ29kZSAuc2hfc3ltYm9sLAouc2hfc291cmNlQ29kZSAuc2hfY2JyYWNrZXQgewogIGNvbG9yOiAjMzMzOwp9Cgouc2hfc291cmNlQ29kZSAuc2hfa2V5d29yZCB7CiAgY29sb3I6ICMzMzg7Cn0KCi5zaF9zb3VyY2VDb2RlIC5zaF9zdHJpbmcsCi5zaF9zb3VyY2VDb2RlIC5zaF9yZWdleHAsCi5zaF9zb3VyY2VDb2RlIC5zaF9udW1iZXIsCi5zaF9zb3VyY2VDb2RlIC5zaF9zcGVjaWFsY2hhciB7CiAgY29sb3I6ICNFNTQzMDU7Cn0KCi5zaF9zb3VyY2VDb2RlIC5zaF9jb21tZW50IHsKICBjb2xvcjogIzY2NjsKICBmb250LXdlaWdodDogbGlnaHRlcjsKfQo=">
<link rel="canonical" href="https://nodejs.org/api/assert.html">
</head>
<body class="alt apidoc" id="api-section-assert">
<div id="content" class="clearfix">
<div id="column2" class="interior">
<div id="intro" class="interior">
<a href="https://nodejs.org/" title="Go back to the home page">
Node.js
</a>
</div>
<ul>
<li><a href="https://nodejs.org/api/documentation.html" class="nav-documentation">About these Docs</a></li>
<li><a href="https://nodejs.org/api/synopsis.html" class="nav-synopsis">Usage & Example</a></li>
</ul>
<div class="line"></div>
<ul>
<li><a href="https://nodejs.org/api/assert.html" class="nav-assert active">Assertion Testing</a></li>
<li><a href="https://nodejs.org/api/async_hooks.html" class="nav-async_hooks">Async Hooks</a></li>
<li><a href="https://nodejs.org/api/buffer.html" class="nav-buffer">Buffer</a></li>
<li><a href="https://nodejs.org/api/addons.html" class="nav-addons">C++ Addons</a></li>
<li><a href="https://nodejs.org/api/n-api.html" class="nav-n-api">C/C++ Addons - N-API</a></li>
<li><a href="https://nodejs.org/api/child_process.html" class="nav-child_process">Child Processes</a></li>
<li><a href="https://nodejs.org/api/cluster.html" class="nav-cluster">Cluster</a></li>
<li><a href="https://nodejs.org/api/cli.html" class="nav-cli">Command Line Options</a></li>
<li><a href="https://nodejs.org/api/console.html" class="nav-console">Console</a></li>
<li><a href="https://nodejs.org/api/crypto.html" class="nav-crypto">Crypto</a></li>
<li><a href="https://nodejs.org/api/debugger.html" class="nav-debugger">Debugger</a></li>
<li><a href="https://nodejs.org/api/deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
<li><a href="https://nodejs.org/api/dns.html" class="nav-dns">DNS</a></li>
<li><a href="https://nodejs.org/api/domain.html" class="nav-domain">Domain</a></li>
<li><a href="https://nodejs.org/api/esm.html" class="nav-esm">ECMAScript Modules</a></li>
<li><a href="https://nodejs.org/api/errors.html" class="nav-errors">Errors</a></li>
<li><a href="https://nodejs.org/api/events.html" class="nav-events">Events</a></li>
<li><a href="https://nodejs.org/api/fs.html" class="nav-fs">File System</a></li>
<li><a href="https://nodejs.org/api/globals.html" class="nav-globals">Globals</a></li>
<li><a href="https://nodejs.org/api/http.html" class="nav-http">HTTP</a></li>
<li><a href="https://nodejs.org/api/http2.html" class="nav-http2">HTTP/2</a></li>
<li><a href="https://nodejs.org/api/https.html" class="nav-https">HTTPS</a></li>
<li><a href="https://nodejs.org/api/inspector.html" class="nav-inspector">Inspector</a></li>
<li><a href="https://nodejs.org/api/intl.html" class="nav-intl">Internationalization</a></li>
<li><a href="https://nodejs.org/api/modules.html" class="nav-modules">Modules</a></li>
<li><a href="https://nodejs.org/api/net.html" class="nav-net">Net</a></li>
<li><a href="https://nodejs.org/api/os.html" class="nav-os">OS</a></li>
<li><a href="https://nodejs.org/api/path.html" class="nav-path">Path</a></li>
<li><a href="https://nodejs.org/api/perf_hooks.html" class="nav-perf_hooks">Performance Hooks</a></li>
<li><a href="https://nodejs.org/api/policy.html" class="nav-policy">Policies</a></li>
<li><a href="https://nodejs.org/api/process.html" class="nav-process">Process</a></li>
<li><a href="https://nodejs.org/api/punycode.html" class="nav-punycode">Punycode</a></li>
<li><a href="https://nodejs.org/api/querystring.html" class="nav-querystring">Query Strings</a></li>
<li><a href="https://nodejs.org/api/readline.html" class="nav-readline">Readline</a></li>
<li><a href="https://nodejs.org/api/repl.html" class="nav-repl">REPL</a></li>
<li><a href="https://nodejs.org/api/report.html" class="nav-report">Report</a></li>
<li><a href="https://nodejs.org/api/stream.html" class="nav-stream">Stream</a></li>
<li><a href="https://nodejs.org/api/string_decoder.html" class="nav-string_decoder">String Decoder</a></li>
<li><a href="https://nodejs.org/api/timers.html" class="nav-timers">Timers</a></li>
<li><a href="https://nodejs.org/api/tls.html" class="nav-tls">TLS/SSL</a></li>
<li><a href="https://nodejs.org/api/tracing.html" class="nav-tracing">Trace Events</a></li>
<li><a href="https://nodejs.org/api/tty.html" class="nav-tty">TTY</a></li>
<li><a href="https://nodejs.org/api/dgram.html" class="nav-dgram">UDP/Datagram</a></li>
<li><a href="https://nodejs.org/api/url.html" class="nav-url">URL</a></li>
<li><a href="https://nodejs.org/api/util.html" class="nav-util">Utilities</a></li>
<li><a href="https://nodejs.org/api/v8.html" class="nav-v8">V8</a></li>
<li><a href="https://nodejs.org/api/vm.html" class="nav-vm">VM</a></li>
<li><a href="https://nodejs.org/api/worker_threads.html" class="nav-worker_threads">Worker Threads</a></li>
<li><a href="https://nodejs.org/api/zlib.html" class="nav-zlib">Zlib</a></li>
</ul>
<div class="line"></div>
<ul>
<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">GitHub Repo & Issue Tracker</a></li>
</ul>
</div>
<div id="column1" data-id="assert" class="interior">
<header>
<h1>Node.js v12.10.0 Documentation</h1>
<div id="gtoc">
<ul>
<li>
<a href="https://nodejs.org/api/index.html" name="toc">Index</a>
</li>
<li>
<a href="https://nodejs.org/api/all.html">View on single page</a>
</li>
<li>
<a href="https://nodejs.org/api/assert.json">View as JSON</a>
</li>
<li class="version-picker">
<a href="#">View another version <span>▼</span></a>
<ol class="version-picker"><li><a href="https://nodejs.org/docs/latest-v12.x/api/assert.html">12.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v11.x/api/assert.html">11.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v10.x/api/assert.html">10.x <b>LTS</b></a></li>
<li><a href="https://nodejs.org/docs/latest-v9.x/api/assert.html">9.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v8.x/api/assert.html">8.x <b>LTS</b></a></li>
<li><a href="https://nodejs.org/docs/latest-v7.x/api/assert.html">7.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v6.x/api/assert.html">6.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v5.x/api/assert.html">5.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v4.x/api/assert.html">4.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v0.12.x/api/assert.html">0.12.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v0.10.x/api/assert.html">0.10.x</a></li></ol>
</li>
<li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/master/doc/api/assert.md"><span class="github_icon"><svg height="16" width="16" viewBox="0 0 16.1 16.1" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.5 15.6c.4 0 .5-.2.5-.4v-1.5c-2 .4-2.5-.5-2.7-1 0-.1-.5-.9-.8-1-.3-.2-.7-.6 0-.6.6 0 1 .6 1.2.8.7 1.2 1.9 1 2.4.7 0-.5.2-.9.5-1-1.8-.3-3.7-1-3.7-4 0-.9.3-1.6.8-2.2 0-.2-.3-1 .1-2 0 0 .7-.3 2.2.7a7.4 7.4 0 0 1 4 0c1.5-1 2.2-.8 2.2-.8.5 1.1.2 2 .1 2.1.5.6.8 1.3.8 2.2 0 3-1.9 3.7-3.6 4 .3.2.5.7.5 1.4v2.2c0 .2.1.5.5.4A8 8 0 0 0 16 8a8 8 0 0 0-8-8z"></path></svg></span>Edit on GitHub</a></li>
</ul>
</div>
<hr>
</header>
<div id="toc">
<h2>Table of Contents</h2>
<ul>
<li>
<p><span class="stability_2"><a href="#assert_assert">Assert</a></span></p>
<ul>
<li>
<p><a href="#assert_class_assert_assertionerror">Class: assert.AssertionError</a></p>
<ul>
<li><a href="#assert_new_assert_assertionerror_options">new assert.AssertionError(options)</a></li>
</ul>
</li>
<li><a href="#assert_strict_mode">Strict mode</a></li>
<li><a href="#assert_legacy_mode">Legacy mode</a></li>
<li><a href="#assert_assert_value_message">assert(value[, message])</a></li>
<li>
<p><a href="#assert_assert_deepequal_actual_expected_message">assert.deepEqual(actual, expected[, message])</a></p>
<ul>
<li><a href="#assert_comparison_details">Comparison details</a></li>
</ul>
</li>
<li>
<p><a href="#assert_assert_deepstrictequal_actual_expected_message">assert.deepStrictEqual(actual, expected[, message])</a></p>
<ul>
<li><a href="#assert_comparison_details_1">Comparison details</a></li>
</ul>
</li>
<li><a href="#assert_assert_doesnotreject_asyncfn_error_message">assert.doesNotReject(asyncFn[, error][, message])</a></li>
<li><a href="#assert_assert_doesnotthrow_fn_error_message">assert.doesNotThrow(fn[, error][, message])</a></li>
<li><a href="#assert_assert_equal_actual_expected_message">assert.equal(actual, expected[, message])</a></li>
<li><a href="#assert_assert_fail_message">assert.fail([message])</a></li>
<li><span class="stability_0"><a href="#assert_assert_fail_actual_expected_message_operator_stackstartfn">assert.fail(actual, expected[, message[, operator[, stackStartFn]]])</a></span></li>
<li><a href="#assert_assert_iferror_value">assert.ifError(value)</a></li>
<li><a href="#assert_assert_notdeepequal_actual_expected_message">assert.notDeepEqual(actual, expected[, message])</a></li>
<li><a href="#assert_assert_notdeepstrictequal_actual_expected_message">assert.notDeepStrictEqual(actual, expected[, message])</a></li>
<li><a href="#assert_assert_notequal_actual_expected_message">assert.notEqual(actual, expected[, message])</a></li>
<li><a href="#assert_assert_notstrictequal_actual_expected_message">assert.notStrictEqual(actual, expected[, message])</a></li>
<li><a href="#assert_assert_ok_value_message">assert.ok(value[, message])</a></li>
<li><a href="#assert_assert_rejects_asyncfn_error_message">assert.rejects(asyncFn[, error][, message])</a></li>
<li><a href="#assert_assert_strictequal_actual_expected_message">assert.strictEqual(actual, expected[, message])</a></li>
<li><a href="#assert_assert_throws_fn_error_message">assert.throws(fn[, error][, message])</a></li>
</ul>
</li>
</ul>
</div>
<div id="apicontent">
<h1>Assert<span><a class="mark" href="#assert_assert" id="assert_assert">#</a></span></h1>
<p></p><div class="api_stability api_stability_2"><a href="https://nodejs.org/api/documentation.html#documentation_stability_index">Stability: 2</a> - Stable</div><p></p>
<p>The <code>assert</code> module provides a set of assertion functions for verifying
invariants. The module provides a recommended <a href="#assert_strict_mode"><code>strict</code> mode</a> and a more
lenient legacy mode.</p>
<h2>Class: assert.AssertionError<a class="srclink" href="https://github.com/nodejs/node/blob/3a2e75d9a5c31d20e429d505b82dd182e33f459a/lib/assert.js#L135">[src]</a><span><a class="mark" href="#assert_class_assert_assertionerror" id="assert_class_assert_assertionerror">#</a></span></h2>
<ul>
<li>Extends: <a href="https://nodejs.org/api/errors.html#errors_class_error" class="type"><errors.Error></a></li>
</ul>
<p>Indicates the failure of an assertion. All errors thrown by the <code>assert</code> module
will be instances of the <code>AssertionError</code> class.</p>
<h3>new assert.AssertionError(options)<span><a class="mark" href="#assert_new_assert_assertionerror_options" id="assert_new_assert_assertionerror_options">#</a></span></h3>
<div class="api_metadata">
<span>Added in: v0.1.21</span>
</div>
<ul>
<li>
<p><code>options</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object" class="type"><Object></a></p>
<ul>
<li><code>message</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> If provided, the error message is set to this value.</li>
<li><code>actual</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> The <code>actual</code> property on the error instance.</li>
<li><code>expected</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> The <code>expected</code> property on the error instance.</li>
<li><code>operator</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> The <code>operator</code> property on the error instance.</li>
<li><code>stackStartFn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> If provided, the generated stack trace omits
frames before this function.</li>
</ul>
</li>
</ul>
<p>A subclass of <code>Error</code> that indicates the failure of an assertion.</p>
<p>All instances contain the built-in <code>Error</code> properties (<code>message</code> and <code>name</code>)
and:</p>
<ul>
<li><code>actual</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> Set to the <code>actual</code> argument for methods such as
<a href="#assert_assert_strictequal_actual_expected_message"><code>assert.strictEqual()</code></a>.</li>
<li><code>expected</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> Set to the <code>expected</code> value for methods such as
<a href="#assert_assert_strictequal_actual_expected_message"><code>assert.strictEqual()</code></a>.</li>
<li><code>generatedMessage</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type" class="type"><boolean></a> Indicates if the message was auto-generated
(<code>true</code>) or not.</li>
<li><code>code</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> Value is always <code>ERR_ASSERTION</code> to show that the error is an
assertion error.</li>
<li><code>operator</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> Set to the passed in operator value.</li>
</ul>
<pre><code class="language-js">const assert = require('assert');
// Generate an AssertionError to compare the error message later:
const { message } = new assert.AssertionError({
actual: 1,
expected: 2,
operator: 'strictEqual'
});
// Verify error output:
try {
assert.strictEqual(1, 2);
} catch (err) {
assert(err instanceof assert.AssertionError);
assert.strictEqual(err.message, message);
assert.strictEqual(err.name, 'AssertionError');
assert.strictEqual(err.actual, 1);
assert.strictEqual(err.expected, 2);
assert.strictEqual(err.code, 'ERR_ASSERTION');
assert.strictEqual(err.operator, 'strictEqual');
assert.strictEqual(err.generatedMessage, true);
}
</code></pre>
<h2>Strict mode<span><a class="mark" href="#assert_strict_mode" id="assert_strict_mode">#</a></span></h2>
<div class="api_metadata">
<details class="changelog"><summary>History</summary>
<table>
<tbody><tr><th>Version</th><th>Changes</th></tr>
<tr><td>v9.9.0</td>
<td><p>Added error diffs to the strict mode</p></td></tr>
<tr><td>v9.9.0</td>
<td><p>Added strict mode to the assert module.</p></td></tr>
<tr><td>v9.9.0</td>
<td><p><span>Added in: v9.9.0</span></p></td></tr>
</tbody></table>
</details>
</div>
<p>In <code>strict</code> mode, <code>assert</code> functions use the comparison in the corresponding
strict functions. For example, <a href="#assert_assert_deepequal_actual_expected_message"><code>assert.deepEqual()</code></a> will behave like
<a href="#assert_assert_deepstrictequal_actual_expected_message"><code>assert.deepStrictEqual()</code></a>.</p>
<p>In <code>strict</code> mode, error messages for objects display a diff. In legacy mode,
error messages for objects display the objects, often truncated.</p>
<p>To use <code>strict</code> mode:</p>
<pre><code class="language-js">const assert = require('assert').strict;
</code></pre>
<p>Example error diff:</p>
<pre><code class="language-js">const assert = require('assert').strict;
assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
// [
// [
// ...
// 2,
// + 3
// - '3'
// ],
// ...
// 5
// ]
</code></pre>
<p>To deactivate the colors, use the <code>NODE_DISABLE_COLORS</code> environment variable.
This will also deactivate the colors in the REPL.</p>
<h2>Legacy mode<span><a class="mark" href="#assert_legacy_mode" id="assert_legacy_mode">#</a></span></h2>
<p>Legacy mode uses the <a href="https://tc39.github.io/ecma262/#sec-abstract-equality-comparison">Abstract Equality Comparison</a> in:</p>
<ul>
<li><a href="#assert_assert_deepequal_actual_expected_message"><code>assert.deepEqual()</code></a></li>
<li>[<code>assert.equal()</code>][]</li>
<li>[<code>assert.notDeepEqual()</code>][]</li>
<li>[<code>assert.notEqual()</code>][]</li>
</ul>
<p>To use legacy mode:</p>
<pre><code class="language-js">const assert = require('assert');
</code></pre>
<p>Whenever possible, use the <a href="#assert_strict_mode"><code>strict</code> mode</a> instead. Otherwise, the
<a href="https://tc39.github.io/ecma262/#sec-abstract-equality-comparison">Abstract Equality Comparison</a> may cause surprising results. This is
especially true for <a href="#assert_assert_deepequal_actual_expected_message"><code>assert.deepEqual()</code></a>, where the comparison rules are
lax:</p>
<pre><code class="language-js">// WARNING: This does not throw an AssertionError!
assert.deepEqual(/a/gi, new Date());
</code></pre>
<h2>assert(value[, message])<a class="srclink" href="https://github.com/nodejs/node/blob/3a2e75d9a5c31d20e429d505b82dd182e33f459a/lib/assert.js#L76">[src]</a><span><a class="mark" href="#assert_assert_value_message" id="assert_assert_value_message">#</a></span></h2>
<div class="api_metadata">
<span>Added in: v0.5.9</span>
</div>
<ul>
<li><code>value</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> The input that is checked for being truthy.</li>
<li><code>message</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error" class="type"><Error></a></li>
</ul>
<p>An alias of <a href="#assert_assert_ok_value_message"><code>assert.ok()</code></a>.</p>
<h2>assert.deepEqual(actual, expected[, message])<a class="srclink" href="https://github.com/nodejs/node/blob/3a2e75d9a5c31d20e429d505b82dd182e33f459a/lib/assert.js#L421">[src]</a><span><a class="mark" href="#assert_assert_deepequal_actual_expected_message" id="assert_assert_deepequal_actual_expected_message">#</a></span></h2>
<div class="api_metadata">
<details class="changelog"><summary>History</summary>
<table>
<tbody><tr><th>Version</th><th>Changes</th></tr>
<tr><td>v12.0
gitextract_5wp5uvc2/
├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── README.vi.md
├── bin/
│ └── learnyounode
├── docs/
│ ├── bl.html
│ ├── concat-stream.html
│ └── through2-map.html
├── docs-nodejs/
│ ├── addons.html
│ ├── assert.html
│ ├── async_hooks.html
│ ├── buffer.html
│ ├── child_process.html
│ ├── cli.html
│ ├── cluster.html
│ ├── console.html
│ ├── crypto.html
│ ├── debugger.html
│ ├── deprecations.html
│ ├── dgram.html
│ ├── dns.html
│ ├── domain.html
│ ├── errors.html
│ ├── esm.html
│ ├── events.html
│ ├── fs.html
│ ├── globals.html
│ ├── http.html
│ ├── http2.html
│ ├── https.html
│ ├── inspector.html
│ ├── intl.html
│ ├── modules.html
│ ├── n-api.html
│ ├── net.html
│ ├── os.html
│ ├── path.html
│ ├── perf_hooks.html
│ ├── policy.html
│ ├── process.html
│ ├── punycode.html
│ ├── querystring.html
│ ├── readline.html
│ ├── repl.html
│ ├── report.html
│ ├── stream.html
│ ├── string_decoder.html
│ ├── timers.html
│ ├── tls.html
│ ├── tracing.html
│ ├── tty.html
│ ├── url.html
│ ├── util.html
│ ├── v8.html
│ ├── vm.html
│ └── worker_threads.html
├── exercises/
│ ├── baby_steps/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── filtered_ls/
│ │ ├── exercise.js
│ │ ├── file-list.json
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── hello_world/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_pt-br/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_tr/
│ │ │ └── solution.js
│ │ └── solution_vi/
│ │ └── solution.js
│ ├── http_client/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_collect/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_file_server/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_json_api_server/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── http_uppercaserer/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── juggling_async/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ └── solution/
│ │ └── solution.js
│ ├── make_it_modular/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ ├── solution.js
│ │ │ └── solution_filter.js
│ │ ├── verify.js
│ │ └── wrap-requires.js
│ ├── my_first_async_io/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_es/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_uk/
│ │ │ └── solution.js
│ │ ├── solution_vi/
│ │ │ └── solution.js
│ │ ├── solution_zh-cn/
│ │ │ └── solution.js
│ │ └── solution_zh-tw/
│ │ └── solution.js
│ ├── my_first_io/
│ │ ├── exercise.js
│ │ ├── problem.es.md
│ │ ├── problem.fr.md
│ │ ├── problem.it.md
│ │ ├── problem.ja.md
│ │ ├── problem.ko.md
│ │ ├── problem.md
│ │ ├── problem.nb-no.md
│ │ ├── problem.pl.md
│ │ ├── problem.pt-br.md
│ │ ├── problem.ru.md
│ │ ├── problem.tr.md
│ │ ├── problem.uk.md
│ │ ├── problem.vi.md
│ │ ├── problem.zh-cn.md
│ │ ├── problem.zh-tw.md
│ │ ├── solution/
│ │ │ └── solution.js
│ │ ├── solution_fr/
│ │ │ └── solution.js
│ │ ├── solution_it/
│ │ │ └── solution.js
│ │ ├── solution_ja/
│ │ │ └── solution.js
│ │ ├── solution_nb-no/
│ │ │ └── solution.js
│ │ ├── solution_ru/
│ │ │ └── solution.js
│ │ ├── solution_uk/
│ │ │ └── solution.js
│ │ ├── solution_vi/
│ │ │ └── solution.js
│ │ ├── solution_zh-cn/
│ │ │ └── solution.js
│ │ ├── solution_zh-tw/
│ │ │ └── solution.js
│ │ └── wrap.js
│ └── time_server/
│ ├── exercise.js
│ ├── problem.es.md
│ ├── problem.fr.md
│ ├── problem.it.md
│ ├── problem.ja.md
│ ├── problem.ko.md
│ ├── problem.md
│ ├── problem.nb-no.md
│ ├── problem.pl.md
│ ├── problem.pt-br.md
│ ├── problem.ru.md
│ ├── problem.tr.md
│ ├── problem.uk.md
│ ├── problem.vi.md
│ ├── problem.zh-cn.md
│ ├── problem.zh-tw.md
│ └── solution/
│ └── solution.js
├── i18n/
│ ├── credits/
│ │ └── it.txt
│ ├── en.json
│ ├── es.json
│ ├── fr.json
│ ├── it.json
│ ├── ja.json
│ ├── ko.json
│ ├── nb-no.json
│ ├── pl.json
│ ├── pt-br.json
│ ├── ru.json
│ ├── tr.json
│ ├── uk.json
│ ├── vi.json
│ ├── zh-cn.json
│ └── zh-tw.json
├── learnyounode.js
├── lib/
│ ├── rndport.js
│ └── words.js
├── package.json
├── test/
│ ├── baby_steps/
│ │ ├── invalid_01.js
│ │ └── valid_01.js
│ ├── filtered_ls/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ └── valid_01.js
│ ├── hello_world/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ └── valid_01_ja.js
│ ├── http_client/
│ │ └── valid_01.js
│ ├── http_collect/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ ├── valid_02.js
│ │ ├── valid_03.js
│ │ ├── valid_04.js
│ │ └── valid_05.js
│ ├── http_file_server/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ ├── http_json_api_server/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ ├── http_uppercaserer/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ └── valid_01.js
│ ├── juggling_async/
│ │ ├── invalid_01.js
│ │ ├── valid_01.js
│ │ └── valid_02.js
│ ├── make_it_modular/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ ├── invalid_04.js
│ │ ├── invalid_05.js
│ │ ├── invalid_06.js
│ │ ├── invalid_07.js
│ │ ├── invalid_08.js
│ │ ├── invalid_09.js
│ │ ├── invalid_10.js
│ │ ├── invalid_11.js
│ │ ├── invalid_12.js
│ │ ├── invalid_13.js
│ │ ├── invalid_14.js
│ │ ├── invalid_15.js
│ │ ├── module_invalid_01.js
│ │ ├── module_invalid_02.js
│ │ ├── module_invalid_03.js
│ │ ├── module_invalid_04.js
│ │ ├── module_invalid_05.js
│ │ ├── module_invalid_06.js
│ │ ├── module_invalid_07.js
│ │ ├── module_invalid_08.js
│ │ ├── module_invalid_09.js
│ │ ├── module_invalid_10.js
│ │ ├── module_invalid_11.js
│ │ ├── module_invalid_12.js
│ │ ├── module_invalid_13.js
│ │ ├── module_invalid_15.js
│ │ ├── module_valid_01.js
│ │ ├── module_valid_02.js
│ │ ├── valid_01.js
│ │ └── valid_02.js
│ ├── my_first_async_io/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── valid_01.js
│ │ ├── valid_02.js
│ │ └── valid_03.js
│ ├── my_first_io/
│ │ ├── invalid_01.js
│ │ ├── invalid_02.js
│ │ ├── invalid_03.js
│ │ └── valid_01.js
│ └── time_server/
│ ├── invalid_01.js
│ └── valid_01.js
└── tools/
└── download-node-docs.sh
SYMBOL INDEX (37 symbols across 25 files)
FILE: exercises/baby_steps/exercise.js
function rndint (line 6) | function rndint () {
FILE: exercises/http_file_server/exercise.js
function query (line 77) | function query (mode) {
FILE: exercises/http_json_api_server/exercise.js
function normalizeJSON (line 53) | function normalizeJSON (data) {
function query (line 59) | function query (mode) {
FILE: exercises/http_json_api_server/solution/solution.js
function parsetime (line 4) | function parsetime (time) {
function unixtime (line 12) | function unixtime (time) {
FILE: exercises/http_uppercaserer/exercise.js
function query (line 50) | function query (mode) {
FILE: exercises/juggling_async/exercise.js
function writeWords (line 19) | function writeWords (i, delay, res) {
function shuffle (line 34) | function shuffle (array) {
function server (line 51) | function server (i, delay, callback) {
FILE: exercises/juggling_async/solution/solution.js
function printResults (line 7) | function printResults () {
function httpGet (line 13) | function httpGet (index) {
FILE: exercises/make_it_modular/verify.js
function validateModule (line 6) | function validateModule (modFile, callback) {
function requires (line 187) | function requires (exercise) {
function verifyModuleUsed (line 199) | function verifyModuleUsed (callback) {
function verify (line 209) | function verify (callback) {
FILE: exercises/make_it_modular/wrap-requires.js
function finish (line 1) | function finish (ctx) {
FILE: exercises/my_first_io/wrap.js
function wrap (line 5) | function wrap (ctx) {
function wrapFsCalls (line 12) | function wrapFsCalls (ctx, fs, objectName) {
FILE: exercises/time_server/exercise.js
function query (line 51) | function query (mode) {
FILE: exercises/time_server/solution/solution.js
function zeroFill (line 4) | function zeroFill (i) {
function now (line 8) | function now () {
FILE: test/http_client/valid_01.js
function processResponse (line 3) | function processResponse (res) {
FILE: test/juggling_async/invalid_01.js
function printResults (line 4) | function printResults () {
function httpGet (line 10) | function httpGet (index) {
FILE: test/juggling_async/valid_01.js
function printResults (line 4) | function printResults () {
function httpGet (line 10) | function httpGet (index) {
FILE: test/juggling_async/valid_02.js
function allDone (line 6) | function allDone () {
FILE: test/make_it_modular/module_invalid_15.js
function listFiles (line 8) | function listFiles () {
FILE: test/make_it_modular/valid_02.js
function handleOutput (line 10) | function handleOutput (error, list) {
FILE: test/my_first_async_io/invalid_01.js
function countNewLines (line 5) | function countNewLines (text) {
FILE: test/my_first_async_io/invalid_02.js
function countNewLines (line 5) | function countNewLines (_, text) {
FILE: test/my_first_async_io/valid_01.js
function countNewLines (line 5) | function countNewLines (error, text) {
FILE: test/my_first_io/invalid_01.js
function countNewLines (line 5) | function countNewLines (error, text) {
FILE: test/my_first_io/invalid_03.js
function countNewLines (line 5) | function countNewLines (text) {
FILE: test/my_first_io/valid_01.js
function countNewLines (line 5) | function countNewLines (text) {
FILE: test/time_server/valid_01.js
function now (line 1) | function now (d) {
Condensed preview — 408 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,610K chars).
[
{
"path": ".gitignore",
"chars": 31,
"preview": "node_modules\npackage-lock.json\n"
},
{
"path": ".jshintrc",
"chars": 1146,
"preview": "{\n \"predef\": [ ]\n , \"bitwise\": false\n , \"camelcase\": false\n , \"curly\": false\n , \"eqeqeq\": false\n , \"forin\": fals"
},
{
"path": ".npmignore",
"chars": 50,
"preview": ".jshintrc\n.travis.yml\nlearnyounode.png\ntest\ntools\n"
},
{
"path": ".travis.yml",
"chars": 92,
"preview": "language: node_js\nnode_js:\n - node\n - lts/*\nsudo: false\nos:\n - linux\n - osx\n - windows\n"
},
{
"path": "CHANGELOG.md",
"chars": 530,
"preview": "# Change Log\n\nAll notable changes to this project will be documented from version 4.0.0 forward\nin this file.\n\n## 4.0.0 "
},
{
"path": "CONTRIBUTING.md",
"chars": 962,
"preview": "# Contributing\n\nCode contributions are welcome and highly encouraged! For instructions on and help with creating a great"
},
{
"path": "LICENSE.md",
"chars": 1261,
"preview": "The MIT License (MIT)\n=====================\n\nCopyright (c) 2013-2015 learnyounode contributors\n-------------------------"
},
{
"path": "README.md",
"chars": 8934,
"preview": "# Learn You The Node.js For Much Win!\n["
},
{
"path": "README.vi.md",
"chars": 5146,
"preview": "# Cho đời phong phú hơn với Node.js!\n[]"
},
{
"path": "bin/learnyounode",
"chars": 78,
"preview": "#!/usr/bin/env node\n\nrequire('../learnyounode').execute(process.argv.slice(2))"
},
{
"path": "docs/bl.html",
"chars": 27432,
"preview": "<!doctype html>\n<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->\n<html lang=\"en\">\n <head>\n <meta ch"
},
{
"path": "docs/concat-stream.html",
"chars": 8845,
"preview": "<!doctype html>\n<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->\n<html lang=\"en\">\n <head>\n <meta ch"
},
{
"path": "docs/through2-map.html",
"chars": 12366,
"preview": "<!doctype html>\n<!-- Created with GFM2HTML: https://github.com/rvagg/gfm2html -->\n<html lang=\"en\">\n <head>\n <meta ch"
},
{
"path": "docs-nodejs/addons.html",
"chars": 97098,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/assert.html",
"chars": 116822,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/async_hooks.html",
"chars": 86412,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/buffer.html",
"chars": 219460,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/child_process.html",
"chars": 156683,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/cli.html",
"chars": 112883,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/cluster.html",
"chars": 90003,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/console.html",
"chars": 81298,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/crypto.html",
"chars": 290239,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/debugger.html",
"chars": 56925,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/deprecations.html",
"chars": 174223,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/dgram.html",
"chars": 96636,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/dns.html",
"chars": 128474,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/domain.html",
"chars": 69300,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/errors.html",
"chars": 230045,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/esm.html",
"chars": 94725,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/events.html",
"chars": 87005,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/fs.html",
"chars": 415309,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/globals.html",
"chars": 59967,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/http.html",
"chars": 177454,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/http2.html",
"chars": 259100,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/https.html",
"chars": 74050,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/inspector.html",
"chars": 59955,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/intl.html",
"chars": 62638,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/modules.html",
"chars": 94375,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/n-api.html",
"chars": 304425,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/net.html",
"chars": 133956,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/os.html",
"chars": 97706,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/path.html",
"chars": 73950,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/perf_hooks.html",
"chars": 82652,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/policy.html",
"chars": 55495,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/process.html",
"chars": 179706,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/punycode.html",
"chars": 56288,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/querystring.html",
"chars": 58612,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/readline.html",
"chars": 85605,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/repl.html",
"chars": 84414,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/report.html",
"chars": 68292,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/stream.html",
"chars": 202757,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/string_decoder.html",
"chars": 53936,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/timers.html",
"chars": 66483,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/tls.html",
"chars": 171438,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/tracing.html",
"chars": 58774,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/tty.html",
"chars": 66868,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/url.html",
"chars": 122215,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/util.html",
"chars": 174609,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/v8.html",
"chars": 82199,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/vm.html",
"chars": 133102,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "docs-nodejs/worker_threads.html",
"chars": 88212,
"preview": "<!DOCTYPE html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <"
},
{
"path": "exercises/baby_steps/exercise.js",
"chars": 601,
"preview": "'use strict'\nconst exercise = require('workshopper-exercise/basic')\n\n// generate a random positive integer <= 100\n\nfunct"
},
{
"path": "exercises/baby_steps/problem.es.md",
"chars": 1618,
"preview": "Escribe un programa que reciba uno o más números como argumentos de la consola e imprima la suma de dichos números a con"
},
{
"path": "exercises/baby_steps/problem.fr.md",
"chars": 2009,
"preview": "Écrivez un programme qui accepte un ou plusieurs nombres comme arguments de\nla ligne de commande, et affiche la somme de"
},
{
"path": "exercises/baby_steps/problem.it.md",
"chars": 1728,
"preview": "Scrivi un programma che accetta uno o più numeri come argomenti da riga di comando e stampa la somma di tali numeri sull"
},
{
"path": "exercises/baby_steps/problem.ja.md",
"chars": 1053,
"preview": "1つ以上の整数をコマンドライン引数として受け取り、それらを足し合わせた値をコンソール(stdout)に出力するコマンドラインアプリを書いてください。\n\n--------------------------------------------"
},
{
"path": "exercises/baby_steps/problem.ko.md",
"chars": 1050,
"preview": "하나 이상의 숫자를 커맨드 라인 인자로 받아 그 숫자들의 합을 콘솔(stdout)에 출력하는 프로그램을 작성하세요.\n\n------------------------------------------------------"
},
{
"path": "exercises/baby_steps/problem.md",
"chars": 1833,
"preview": "Create a file named `baby-steps.js`.\n\nWrite a program that accepts one or more numbers as command-line arguments and pri"
},
{
"path": "exercises/baby_steps/problem.nb-no.md",
"chars": 1583,
"preview": "Skriv et program som tar imot en eller flere tall som kommandolinje argumenter og sskriver ut summer av disse til skjerm"
},
{
"path": "exercises/baby_steps/problem.pl.md",
"chars": 1772,
"preview": "Napisz program przyjmujący jedną lub więcej liczb jako argumentu linii poleceń i wypisuje ich sumę na konsolę (stdout).\n"
},
{
"path": "exercises/baby_steps/problem.pt-br.md",
"chars": 1840,
"preview": "Escreva um programa que aceita um ou mais números como argumentos de linha de comando e imprime a soma desses números no"
},
{
"path": "exercises/baby_steps/problem.ru.md",
"chars": 1785,
"preview": "Реализуйте программу, которая принимает на вход один или более аргументов и выводит их сумму в консоль (stdout).\n\n------"
},
{
"path": "exercises/baby_steps/problem.tr.md",
"chars": 2149,
"preview": "`bebek-adimlari.js` isimli bir dosya oluşturunuz.\n\nKomut satırından bir veya daha fazla sayıyı argüman olarak alıp, bu s"
},
{
"path": "exercises/baby_steps/problem.uk.md",
"chars": 1785,
"preview": "Напишіть програму, що приймає на вхід один або більше аргументів, та виводить їх суму в консоль (stdout).\n\n-------------"
},
{
"path": "exercises/baby_steps/problem.vi.md",
"chars": 1822,
"preview": "Viết một chương trình nhận một hoặc nhiều số đầu vào qua tham số dòng lệnh và in tổng của chúng ra giao diện dòng lệnh ("
},
{
"path": "exercises/baby_steps/problem.zh-cn.md",
"chars": 923,
"preview": "编写一个简单的程序,使其能接收一个或者多个命令行参数,并且在终端(标准输出 stdout)中打印出这些参数的总和。\n\n-------------------------------------------------------------"
},
{
"path": "exercises/baby_steps/problem.zh-tw.md",
"chars": 1018,
"preview": "撰寫一個可以印出命令列參數總和的程式。\n\n----------------------------------------------------------------------\n## 提示\n\n透過 global 的 `process`"
},
{
"path": "exercises/baby_steps/solution/solution.js",
"chars": 137,
"preview": "'use strict'\n\nlet result = 0\n\nfor (let i = 2; i < process.argv.length; i++) {\n result += Number(process.argv[i])\n}\n\ncon"
},
{
"path": "exercises/filtered_ls/exercise.js",
"chars": 2290,
"preview": "'use strict'\nconst fs = require('fs')\nconst path = require('path')\nconst os = require('os')\nlet exercise = require('work"
},
{
"path": "exercises/filtered_ls/file-list.json",
"chars": 253,
"preview": "[\n \"learnyounode.dat\"\n , \"learnyounode.txt\"\n , \"learnyounode.sql\"\n , \"api.html\"\n , \"README.md\"\n , \"CHANGELOG.md\""
},
{
"path": "exercises/filtered_ls/problem.es.md",
"chars": 1017,
"preview": "Crea un programa que dado un directorio imprima una lista de archivos filtrados por la extensión. El primer argumento se"
},
{
"path": "exercises/filtered_ls/problem.fr.md",
"chars": 1464,
"preview": "Créez un programme qui affiche une liste de fichiers au sein d’un répertoire\ndonné, filtrés en fonction de leur extensio"
},
{
"path": "exercises/filtered_ls/problem.it.md",
"chars": 1280,
"preview": "Scrivi un programma che stampi una lista di file in una data directory, filtrata per l'estensione dei file. Ti verrà for"
},
{
"path": "exercises/filtered_ls/problem.ja.md",
"chars": 742,
"preview": "拡張子によってフィルタしたファイルリストをコンソールに出力するアプリを書いてください。\n\nコマンドライン引数の1つ目は、フォルダのパスです(例えば `/あなた/の/フォルダー/`)。 2つ目は、フィルタする拡張子です。\n\n例: 2つ目の引数"
},
{
"path": "exercises/filtered_ls/problem.ko.md",
"chars": 701,
"preview": "주어진 디렉터리의 파일 목록을 만든 후 확장자로 걸러 출력하는 프로그램을 만드세요. 프로그램의 첫 번째 인자로 디렉터리 이름(예: '/path/to/dir/')을 받고 거를 확장자는 두 번째 인자로 받습니다.\n\n예를"
},
{
"path": "exercises/filtered_ls/problem.md",
"chars": 1505,
"preview": "Create a file named `filtered-ls.js`.\n\nCreate a program that prints a list of files in a given directory, filtered by th"
},
{
"path": "exercises/filtered_ls/problem.nb-no.md",
"chars": 1117,
"preview": "Skriv et program som skriver ut en liste med filenavn fra en gitt katalog filtrert på filetternavn. Programmet skal ta i"
},
{
"path": "exercises/filtered_ls/problem.pl.md",
"chars": 1191,
"preview": "Stwórz program wypisujący listę plików w danym katalogu, przefiltrowaną pod kątem ich rozszerzenia. Jako pierwszy argume"
},
{
"path": "exercises/filtered_ls/problem.pt-br.md",
"chars": 1366,
"preview": "Crie um programa que imprima uma lista de arquivos filtrados por suas extensões em um dado diretório. Você irá receber u"
},
{
"path": "exercises/filtered_ls/problem.ru.md",
"chars": 1258,
"preview": "Реализуйте программу, которая выводит список отфильтрованных по расширению файлов в заданой директории. Имя директории ("
},
{
"path": "exercises/filtered_ls/problem.tr.md",
"chars": 1563,
"preview": "`filtrelenmis-ls.js` isimli bir dosya oluşturunuz.\n\nVerilen dizinde ki dosyaları dosya uzantılarına göre filtreleyip lis"
},
{
"path": "exercises/filtered_ls/problem.uk.md",
"chars": 1266,
"preview": "Напишіть програму, яка виводить список відфільтрованих по розширенню (extension) файлів в заданій директорії. Ім’я дирек"
},
{
"path": "exercises/filtered_ls/problem.vi.md",
"chars": 1203,
"preview": "Tạo một chương trình in ra danh sách các file được lọc theo phần mở rộng trong một thư mục nào đó.\nChương trình của bạn "
},
{
"path": "exercises/filtered_ls/problem.zh-cn.md",
"chars": 641,
"preview": "编写一个程序来打印出指定目录下的文件列表,并且以特定的文件名扩展名来过滤这个列表。这次会有两个参数提供给你,第一个是所给的文件目录路径(如:`path/to/dir`),第二个参数则是需要过滤出来的文件的扩展名。\n\n举个例子:如果第二个参数"
},
{
"path": "exercises/filtered_ls/problem.zh-tw.md",
"chars": 608,
"preview": "撰寫一個以副檔名作為篩選條件,列出指定資料夾內檔案的程式。程式的第一個參數是目錄的路徑,第二個參數則是篩選用的副檔名。\n\n舉例來說,如果第二個參數是「txt」,您將需要篩選出資料夾內 **以 .txt 結尾** 的檔案。注意,第二個參數 _"
},
{
"path": "exercises/filtered_ls/solution/solution.js",
"chars": 324,
"preview": "'use strict'\nconst fs = require('fs')\nconst path = require('path')\n\nconst folder = process.argv[2]\nconst ext = '.' + pro"
},
{
"path": "exercises/hello_world/exercise.js",
"chars": 95,
"preview": "'use strict'\nconst exercise = require('workshopper-exercise/basic')\n\nmodule.exports = exercise\n"
},
{
"path": "exercises/hello_world/problem.es.md",
"chars": 695,
"preview": "Escribe un programa que imprima el texto \"HELLO WORLD\" en consola (stdout).\n\n-------------------------------------------"
},
{
"path": "exercises/hello_world/problem.fr.md",
"chars": 725,
"preview": "Écrivez un programme qui dit « Bonjour, Monde » dans la console (stdout).\n\n---------------------------------------------"
},
{
"path": "exercises/hello_world/problem.it.md",
"chars": 709,
"preview": "Scrivi un programma che scriva la frase \"CIAO MONDO\" sulla console (stdout).\n\n------------------------------------------"
},
{
"path": "exercises/hello_world/problem.ja.md",
"chars": 500,
"preview": "コンソール (stdout) に ```\"こんにちは世界\"``` と出力するアプリを書いてください。\n\n--------------------------------------------------------------------"
},
{
"path": "exercises/hello_world/problem.ko.md",
"chars": 433,
"preview": "콘솔(stdout)에 \"HELLO WORLD\"를 출력하는 프로그램을 작성하세요.\n\n----------------------------------------------------------------------\n## "
},
{
"path": "exercises/hello_world/problem.md",
"chars": 704,
"preview": "Create a file named `hello-world.js`.\n\nWrite a program that prints the text \"HELLO WORLD\" to the console (stdout).\n\n----"
},
{
"path": "exercises/hello_world/problem.nb-no.md",
"chars": 689,
"preview": "Skriv et program som skriver ut teskten \"Hei verden\" til skjermen (stdout).\n\n-------------------------------------------"
},
{
"path": "exercises/hello_world/problem.pl.md",
"chars": 626,
"preview": "Napisz program wypisujący napis \"HELLO WORLD\" na konsolę (stdout).\n\n----------------------------------------------------"
},
{
"path": "exercises/hello_world/problem.pt-br.md",
"chars": 688,
"preview": "Escreva um programa que imprime o texto \"Olá, Mundo\" no console (stdout).\n\n---------------------------------------------"
},
{
"path": "exercises/hello_world/problem.ru.md",
"chars": 716,
"preview": "Реализуйте программу которая выводит текст \"Привет, мир!\" в консоль (stdout).\n\n-----------------------------------------"
},
{
"path": "exercises/hello_world/problem.tr.md",
"chars": 726,
"preview": "`merhaba-dunya.js` isimli bir dosya oluşturunuz.\n\nKonsol(stdout)a \"MERHABA DÜNYA\" yazan bir program yazınız.\n\n----------"
},
{
"path": "exercises/hello_world/problem.uk.md",
"chars": 683,
"preview": "Напишіть програму, що виводить текст \"HELLO WORLD\" в консоль (stdout).\n\n------------------------------------------------"
},
{
"path": "exercises/hello_world/problem.vi.md",
"chars": 657,
"preview": "Viết một chương trình in \"Chào Thế Giới\" ra giao diện dòng lệnh (stdout).\n\n---------------------------------------------"
},
{
"path": "exercises/hello_world/problem.zh-cn.md",
"chars": 429,
"preview": "编写一个程序,在终端(标准输出 stdout)打印出 \"HELLO WORLD\"。\n\n----------------------------------------------------------------------\n## 提示\n"
},
{
"path": "exercises/hello_world/problem.zh-tw.md",
"chars": 448,
"preview": "撰寫一個印出「HELLO WORLD」字串到終端機的程式\n\n----------------------------------------------------------------------\n## 提示\n\n要撰寫一個 Node.j"
},
{
"path": "exercises/hello_world/solution/solution.js",
"chars": 27,
"preview": "console.log('HELLO WORLD')\n"
},
{
"path": "exercises/hello_world/solution_fr/solution.js",
"chars": 30,
"preview": "console.log('Bonjour, Monde')\n"
},
{
"path": "exercises/hello_world/solution_it/solution.js",
"chars": 26,
"preview": "console.log('CIAO MONDO')\n"
},
{
"path": "exercises/hello_world/solution_ja/solution.js",
"chars": 23,
"preview": "console.log('こんにちは世界')\n"
},
{
"path": "exercises/hello_world/solution_nb-no/solution.js",
"chars": 26,
"preview": "console.log('Hei verden')\n"
},
{
"path": "exercises/hello_world/solution_pt-br/solution.js",
"chars": 26,
"preview": "console.log('Olá, Mundo')\n"
},
{
"path": "exercises/hello_world/solution_ru/solution.js",
"chars": 28,
"preview": "console.log('Привет, мир!')\n"
},
{
"path": "exercises/hello_world/solution_tr/solution.js",
"chars": 29,
"preview": "console.log('MERHABA DÜNYA')\n"
},
{
"path": "exercises/hello_world/solution_vi/solution.js",
"chars": 29,
"preview": "console.log('Chào Thế Giới')\n"
},
{
"path": "exercises/http_client/exercise.js",
"chars": 1101,
"preview": "'use strict'\nconst http = require('http')\nconst exercise = require('workshopper-exercise/basic')\n\nconst words = require("
},
{
"path": "exercises/http_client/problem.es.md",
"chars": 1545,
"preview": "Escribe un programa que reciba como argumento una URL y realice una petición HTTP GET a la misma. Luego, deberá imprimir"
},
{
"path": "exercises/http_client/problem.fr.md",
"chars": 1655,
"preview": "Écrivez un programme qui fait une requête HTTP GET sur une URL fournie\ncomme premier argument de la ligne de commande. "
},
{
"path": "exercises/http_client/problem.it.md",
"chars": 1627,
"preview": "Scrivi un programma che effettui una richiesta HTTP GET ad un URL fornito come primo argomento da riga di comando. Scriv"
},
{
"path": "exercises/http_client/problem.ja.md",
"chars": 1097,
"preview": "1つ目の引数として指定された URL に、 HTTP で GET を送信する (※)アプリを書いてください。\n\nそのリクエストに対するレスポンスを`\"data\"`イベントで受け取り、受け取った全ての文字列を**1つずつ**改行で区切ってコン"
},
{
"path": "exercises/http_client/problem.ko.md",
"chars": 939,
"preview": "첫 번째 인자로 넘긴 URL에 HTTP GET 요청을 수행하는 프로그램을 작성하세요. 응답에서 문자열인 \"data\" 이벤트 내용을 콘솔(stdout)에 **각각** 새 줄로 적으세요.\n\n----------------"
},
{
"path": "exercises/http_client/problem.md",
"chars": 1651,
"preview": "Create a file named `http-client.js`.\n\nWrite a program that performs an HTTP GET request to a URL provided to you as the"
},
{
"path": "exercises/http_client/problem.nb-no.md",
"chars": 1486,
"preview": "Skriv et program som utfører en HTTP GET forespørsel til en URL som gis til deg som det første kommandolinje argumentet."
},
{
"path": "exercises/http_client/problem.pl.md",
"chars": 1566,
"preview": "Napisz program wysyłający żądanie HTTP GET na URL przekazany jako pierwszy argument wiersza poleceń. Wypisz zawartość te"
},
{
"path": "exercises/http_client/problem.pt-br.md",
"chars": 1565,
"preview": "Escreva um programa que realize uma requisição HTTP GET a uma URL fornecida por você como primeiro argumento na linha de"
},
{
"path": "exercises/http_client/problem.ru.md",
"chars": 1543,
"preview": "Реализуйте программу, которая посылает HTTP GET запрос на URL, который вы получите в качестве первого аргумента командно"
},
{
"path": "exercises/http_client/problem.tr.md",
"chars": 1853,
"preview": "`http-istemcisi.js` isimli bir dosya oluşturunuz.\n\nİlk argüman olarak bir URL kabul eden ve verilen bu URL'e HTTP GET is"
},
{
"path": "exercises/http_client/problem.uk.md",
"chars": 1581,
"preview": "Напишіть програму, яка надсилає HTTP GET запит на URL, який Ви отримаєте в якості першого аргументу командного рядка. Ви"
},
{
"path": "exercises/http_client/problem.vi.md",
"chars": 1708,
"preview": "Viết một chương trình nhận một URL qua tham số đầu tiên và lấy nội dung của URL đó thông qua HTTP GET request. Sau đó hã"
},
{
"path": "exercises/http_client/problem.zh-cn.md",
"chars": 885,
"preview": "编写一个程序来发起一个 HTTP GET 请求,所请求的 URL 为命令行参数的第一个。然后将**每一个** \"data\" 事件所得的数据,以字符串形式在终端(标准输出 stdout)的新的一行打印出来。\n\n----------------"
},
{
"path": "exercises/http_client/problem.zh-tw.md",
"chars": 889,
"preview": "撰寫一個會對第一個參數所提供之URL(網址)發起 HTTP GET 請求(request)的程式。這個程式會把 **每個** 來自回應「data」事件的字串內容以新的一行顯示在終端機(標準輸出,stdout)上。\n\n------------"
},
{
"path": "exercises/http_client/solution/solution.js",
"chars": 225,
"preview": "'use strict'\nconst http = require('http')\n\nhttp.get(process.argv[2], function (response) {\n response.setEncoding('utf8'"
},
{
"path": "exercises/http_collect/exercise.js",
"chars": 1441,
"preview": "'use strict'\nconst http = require('http')\nconst exercise = require('workshopper-exercise/basic')\n\nconst words = require("
},
{
"path": "exercises/http_collect/problem.es.md",
"chars": 2155,
"preview": "Escribe un programa que realice una petición HTTP GET a una URL provista como primer argumento del programa.\nAlmacena **"
},
{
"path": "exercises/http_collect/problem.fr.md",
"chars": 2611,
"preview": "Écrivez un programme qui fait une requête HTTP GET sur une URL fournie en\npremier argument de la ligne de commande. Réc"
},
{
"path": "exercises/http_collect/problem.it.md",
"chars": 2692,
"preview": "Scrivi un programma che effettui una richiesta HTTP GET ad un URL fornito come primo argomento da riga di comando. Racco"
},
{
"path": "exercises/http_collect/problem.ja.md",
"chars": 1463,
"preview": "1つ目のコマンドライン引数は URL 文字列です。 そのURL文字列を使ってHTTP のデータをロード (※)するアプリを書いてください。\n\nサーバから**全て**(最初のイベントだけではなく)のデータを集め、次の2行をコンソールに出力して"
},
{
"path": "exercises/http_collect/problem.ko.md",
"chars": 1511,
"preview": "첫 번째 커맨드 라인 인자로 넘긴 URL로 HTTP GET 요청을 수행하는 프로그램을 작성하세요. 서버에서 **모든** 데이터(첫 번째 \"data\" 이벤트만 하지 말고)를 수집하고 콘솔(stdout)에 두 줄을 적으"
},
{
"path": "exercises/http_collect/problem.md",
"chars": 2612,
"preview": "Create a file named `http-collect.js`.\n\nWrite a program that performs an HTTP GET request to a URL provided to you as th"
},
{
"path": "exercises/http_collect/problem.nb-no.md",
"chars": 2367,
"preview": "Skriv et program som utfører en HTTP GET forespørsel til en URL som gis til deg som det første kommandolinje argumentet."
},
{
"path": "exercises/http_collect/problem.pl.md",
"chars": 2824,
"preview": "Napisz program wysyłający żądanie HTTP GET na URL podany jako pierwszy argument wiersza poleceń. Zbierz **wszystkie** da"
},
{
"path": "exercises/http_collect/problem.pt-br.md",
"chars": 2610,
"preview": "Escreva um programa que realize uma requisição HTTP GET em uma URL fornecida por você como o primeiro argumento na linha"
},
{
"path": "exercises/http_collect/problem.ru.md",
"chars": 2403,
"preview": "Реализуйте программу, которая посылает HTTP GET запрос на URL, который вы получите в качестве первого аргумента командно"
},
{
"path": "exercises/http_collect/problem.tr.md",
"chars": 2618,
"preview": "`http-topla.js` isimli bir dosya oluşturunuz.\n\nİlk argüman olarak bir URL kabul eden ve verilen bu URL'e HTTP GET isteği"
},
{
"path": "exercises/http_collect/problem.uk.md",
"chars": 2375,
"preview": "Реалізуйте програму, котра надсилає HTTP GET запит на URL, який Ви отримаєте в якості першого аргументу командного рядка"
},
{
"path": "exercises/http_collect/problem.vi.md",
"chars": 2682,
"preview": "Viết một chương trình nhận một URL qua tham số đầu tiên và thực hiện một HTTP GET request. Tập kết **tất cả** dữ liệu từ"
},
{
"path": "exercises/http_collect/problem.zh-cn.md",
"chars": 1449,
"preview": "编写一个程序,发起一个 HTTP GET 请求,请求的 URL 为所提供给你的命令行参数的第一个。收集**所有**服务器所返回的数据(不仅仅包括 \"data\" 事件)然后在终端(标准输出 stdout)用两行打印出来。\n\n你所打印的内容,第"
},
{
"path": "exercises/http_collect/problem.zh-tw.md",
"chars": 1342,
"preview": "撰寫一個會對第一個參數所提供之URL(網址)發起 HTTP GET 請求(request)的程式。從伺服器收集 **所有** 的資料,並且在終端機(標準輸出,stdout)上顯示兩行以呈現這些數據。\n\n第一行是從伺服器收到的字元(chara"
},
{
"path": "exercises/http_collect/solution/solution.js",
"chars": 298,
"preview": "'use strict'\nconst http = require('http')\nconst bl = require('bl')\n\nhttp.get(process.argv[2], function (response) {\n re"
},
{
"path": "exercises/http_file_server/exercise.js",
"chars": 3584,
"preview": "'use strict'\nconst fs = require('fs')\nconst path = require('path')\nconst os = require('os')\nconst through2 = require('th"
},
{
"path": "exercises/http_file_server/problem.es.md",
"chars": 2066,
"preview": "Escribe un **servidor** HTTP que sirva un mismo archivo de texto para todas las peticiones que reciba.\n\nEl servidor debe"
},
{
"path": "exercises/http_file_server/problem.fr.md",
"chars": 2542,
"preview": "Écrivez un **serveur** HTTP qui servira le même fichier texte pour toute\nrequête reçue.\n\nVotre serveur devrait écouter s"
},
{
"path": "exercises/http_file_server/problem.it.md",
"chars": 2456,
"preview": "Scrivi un **server** HTTP che restituisca lo stesso file di testo per ciascuna richiesta ricevuta.\n\nIl tuo server deve a"
},
{
"path": "exercises/http_file_server/problem.ja.md",
"chars": 1415,
"preview": "常に同じテキストファイルを返す、HTTP の**サーバ**を書いてください。\n\n1つ目のコマンドライン引数で供給されているポートでサーバを 起動 します。\n\n2つ目の引数は、返すテキストファイルのパスです。ファイルを返すためは `fs.cr"
},
{
"path": "exercises/http_file_server/problem.ko.md",
"chars": 1452,
"preview": "받은 요청과 같은 텍스트 파일를 제공하는 HTTP **서버**를 작성합니다.\n\n서버는 프로그램에 첫 번째 인자에서 주어진 포트로 수신해야 합니다.\n\n제공할 파일의 위치는 두 번째 커맨드 라인 인자로 넘겨야 합니다. "
},
{
"path": "exercises/http_file_server/problem.md",
"chars": 2398,
"preview": "Create a file named `http-file-server.js`.\n\nWrite an HTTP **server** that serves the same text file for each request it "
},
{
"path": "exercises/http_file_server/problem.nb-no.md",
"chars": 2157,
"preview": "Du skal nå skrive en HTTP **server** som for hver forespørsel returnerer en tekstfil.\n\nServeren skal lytte på porten som"
},
{
"path": "exercises/http_file_server/problem.pl.md",
"chars": 2408,
"preview": "Napisz **serwer** HTTP, który serwuje ten sam plik tekstowy w odpowiedzi na każde otrzymane żądanie.\n\nTwój serwer powini"
},
{
"path": "exercises/http_file_server/problem.pt-br.md",
"chars": 2364,
"preview": "Escreva um **servidor** HTTP que entregue o mesmo arquivo de texto para cada solicitação recebida.\n\nO servidor deve esc"
},
{
"path": "exercises/http_file_server/problem.ru.md",
"chars": 2283,
"preview": "Реализуйте HTTP сервер, который отдает одинаковый файл для всех входящих запросов.\n\nСервер должен слушать порт, который "
},
{
"path": "exercises/http_file_server/problem.tr.md",
"chars": 2596,
"preview": "`http-dosya-sunucusu.js` isimli bir dosya oluşturunuz.\n\nAldığı her isteğe aynı dosyayı cevap olarak veren bir HTTP sunuc"
},
{
"path": "exercises/http_file_server/problem.uk.md",
"chars": 2362,
"preview": "Реалізуйте HTTP **сервер**, котрий віддає однаковий файл для всіх вхідних запитів.\n\nСервер має слухати порт, котрий буде"
},
{
"path": "exercises/http_file_server/problem.vi.md",
"chars": 2221,
"preview": "Viết một **máy chủ** HTTP trả về cùng một file text giống nhau cho mỗi request nó nhận được.\n\nMáy chủ của bạn sẽ lắng ng"
},
{
"path": "exercises/http_file_server/problem.zh-cn.md",
"chars": 1295,
"preview": "编写一个 HTTP 文件 **服务器**,它用于将每次所请求的文件返回给客户端。\n\n你的服务器需要监听所提供给你的第一个命令行参数所制定的端口。\n\n同时,第二个会提供给你的程序的参数则是所需要响应的文本文件的位置。在这一题中,你**必须**"
},
{
"path": "exercises/http_file_server/problem.zh-tw.md",
"chars": 1254,
"preview": "撰寫一個 HTTP **伺服器** ,可以提供它收到的 text 檔案給所有收到的請求。\n\n第一個參數是 port ,您的伺服器應該監聽在第一個參數所給予的 port 上。\n\n第二個參數是提供的檔案。您 **必須** 使用 `fs.crea"
},
{
"path": "exercises/http_file_server/solution/solution.js",
"chars": 271,
"preview": "'use strict'\nconst http = require('http')\nconst fs = require('fs')\n\nconst server = http.createServer(function (req, res)"
},
{
"path": "exercises/http_json_api_server/exercise.js",
"chars": 2696,
"preview": "const through2 = require('through2')\nconst hyperquest = require('hyperquest')\nconst bl = require('bl')\nlet exercise = re"
},
{
"path": "exercises/http_json_api_server/problem.es.md",
"chars": 1885,
"preview": "Escribe un **servidor** de HTTP que sirva datos en formato JSON cuando reciba una petición GET con la ruta (endpoint) '/"
},
{
"path": "exercises/http_json_api_server/problem.fr.md",
"chars": 2207,
"preview": "Écrivez un **serveur** HTTP qui sert des données JSON lorsqu’il reçoit une\nrequête GET sur le chemin '/api/parsetime'. "
},
{
"path": "exercises/http_json_api_server/problem.it.md",
"chars": 2031,
"preview": "Scrivi un **server** HTTP che serva dati JSON quando riceve una richiesta GET al percorso '/api/parsetime'. Aspettati u"
},
{
"path": "exercises/http_json_api_server/problem.ja.md",
"chars": 1388,
"preview": "'/api/parsetime' への GET リクエスト時に JSON のデータを返す **HTTP サーバ** を書いてください。\n\nリクエストのクエリには 'iso' と言う ISO 形式のタイムスタンプパラメータが渡されるものとしま"
},
{
"path": "exercises/http_json_api_server/problem.ko.md",
"chars": 1297,
"preview": "'/api/parsetime' 경로로 받은 GET 요청에 대해 JSON 데이터를 제공하는 HTTP **서버**를 작성하세요. 요청에 포함된 쿼리 문자열은 'iso' 키에 ISO 시간 형식의 값이어야 합니다.\n\n예를 "
},
{
"path": "exercises/http_json_api_server/problem.md",
"chars": 2046,
"preview": "Create a file named `http-json-api-server.js`.\n\nWrite an HTTP **server** that serves JSON data when it receives a GET re"
},
{
"path": "exercises/http_json_api_server/problem.nb-no.md",
"chars": 1943,
"preview": "I denne opgpaven skal du lage en HTTP **server** som leverer ut data i JSON format når den mottar en GET request på URLe"
},
{
"path": "exercises/http_json_api_server/problem.pl.md",
"chars": 2478,
"preview": "Napisz **serwer** HTTP, który serwuje dane w formacie JSON w odpowiedzi na żądanie GET do ścieżki `/api/parsetime`. Ocze"
},
{
"path": "exercises/http_json_api_server/problem.pt-br.md",
"chars": 1971,
"preview": "Escreva um **servidor** HTTP que serve dados JSON quando recebe uma requisição GET no caminho `/api/parsetime`. Expere q"
},
{
"path": "exercises/http_json_api_server/problem.ru.md",
"chars": 1938,
"preview": "Реализуйте HTTP **сервер**, который возвращает JSON объект на GET запрос по адресу `/api/parsetime`. Запрос должен содер"
},
{
"path": "exercises/http_json_api_server/problem.tr.md",
"chars": 2622,
"preview": "`http-json-api-sunucusu.js` isimli bir dosya oluşturunuz.\n\n'/api/parsetime' adresi üzerinden HTTP GET isteği alan bir HT"
},
{
"path": "exercises/http_json_api_server/problem.uk.md",
"chars": 1903,
"preview": "Реалізуйте HTTP **сервер**, котрий повертає JSON-дані у відповідь на GET-запит за адресою '/api/parsetime'. Запит має мі"
},
{
"path": "exercises/http_json_api_server/problem.vi.md",
"chars": 2126,
"preview": "Viết một **máy chủ** HTTP trả về dữ liệu JSON khi nhận được một request GET qua đường dẫn '/api/parsetime'. Request này "
},
{
"path": "exercises/http_json_api_server/problem.zh-cn.md",
"chars": 1219,
"preview": "编写一个 HTTP **服务器**,每当接收到一个路径为 '/api/parsetime' 的 GET 请求的时候,响应一些 JSON 数据。我们期望请求会包含一个查询参数(query string),key 是 \"iso\",值是 ISO "
},
{
"path": "exercises/http_json_api_server/problem.zh-tw.md",
"chars": 1200,
"preview": "撰寫一個 HTTP **伺服器** ,當伺服器收到路徑「/api/parsetime」的 GET 請求時,要回應 JSON 格式的資料。這個請求會包含一個 query , key 是「iso」,值是 ISO 格式的時間。\n\n如下例:\n\n "
},
{
"path": "exercises/http_json_api_server/solution/solution.js",
"chars": 795,
"preview": "'use strict'\nconst http = require('http')\n\nfunction parsetime (time) {\n return {\n hour: time.getHours(),\n minute:"
},
{
"path": "exercises/http_uppercaserer/exercise.js",
"chars": 2444,
"preview": "const through2 = require('through2')\nconst hyperquest = require('hyperquest')\nlet exercise = require('workshopper-exerci"
},
{
"path": "exercises/http_uppercaserer/problem.es.md",
"chars": 1645,
"preview": "Escribe un **servidor** HTTP que reciba sólo peticiones POST y convierta los caracteres del cuerpo de la petición a mayú"
},
{
"path": "exercises/http_uppercaserer/problem.fr.md",
"chars": 2122,
"preview": "Écrivez un **serveur** HTTP qui reçoit uniquement des requêtes POST et\nconvertit le texte du corps de requête entrante e"
},
{
"path": "exercises/http_uppercaserer/problem.it.md",
"chars": 2030,
"preview": "Scrivi un **server** HTTP che riceva solo richieste POST e converta i caratteri nel corpo delle richieste POST in maiusc"
},
{
"path": "exercises/http_uppercaserer/problem.ja.md",
"chars": 1009,
"preview": "POSTリクエストで渡される文字列を大文字に書き換えて返す **HTTP サーバ** を書いてください。\n\nサーバは、1つ目のコマンドライン引数で与えられたポートで 起動 します。\n\n----------------------------"
},
{
"path": "exercises/http_uppercaserer/problem.ko.md",
"chars": 1102,
"preview": "POST 요청만 받아 들어온 POST 몸통의 문자를 대문자로 변환해 클라이언트에 반환하는 HTTP 서버를 작성하세요.\n\n서버는 프로그램에 첫 번째 인자에서 주어진 포트로 수신해야 합니다.\n\n--------------"
},
{
"path": "exercises/http_uppercaserer/problem.md",
"chars": 1990,
"preview": "Create a file named `http-uppercaserer.js`.\n\nWrite an HTTP **server** that receives only POST requests and converts inco"
},
{
"path": "exercises/http_uppercaserer/problem.nb-no.md",
"chars": 1851,
"preview": "\nSkriv en HTTP **server** som kun tar imot POST forespørsler og konverterer all tekst som ligger i body på forespørselen"
},
{
"path": "exercises/http_uppercaserer/problem.pl.md",
"chars": 2554,
"preview": "Napisz **serwer** HTTP, odpowiadający wyłącznie na żądania POST, przekształcający znaki treści żądań post na wielkie lit"
},
{
"path": "exercises/http_uppercaserer/problem.pt-br.md",
"chars": 1981,
"preview": "Escreva um **servidor** HTTP que recebe apenas requisições de POST e converte os caracteres no corpo da requisição para "
},
{
"path": "exercises/http_uppercaserer/problem.ru.md",
"chars": 1855,
"preview": "Реализуйте HTTP **сервер** который принимает только POST запросы и конвертирует все символы тела запроса в верхний регис"
}
]
// ... and 208 more files (download for full content)
About this extraction
This page contains the full source code of the workshopper/learnyounode GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 408 files (6.1 MB), approximately 1.6M tokens, and a symbol index with 37 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.