진재영

node_modules updated

Showing 587 changed files with 5108 additions and 0 deletions
1 +../mime/cli.js
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +1.3.8 / 2022-02-02
2 +==================
3 +
4 + * deps: mime-types@~2.1.34
5 + - deps: mime-db@~1.51.0
6 + * deps: negotiator@0.6.3
7 +
8 +1.3.7 / 2019-04-29
9 +==================
10 +
11 + * deps: negotiator@0.6.2
12 + - Fix sorting charset, encoding, and language with extra parameters
13 +
14 +1.3.6 / 2019-04-28
15 +==================
16 +
17 + * deps: mime-types@~2.1.24
18 + - deps: mime-db@~1.40.0
19 +
20 +1.3.5 / 2018-02-28
21 +==================
22 +
23 + * deps: mime-types@~2.1.18
24 + - deps: mime-db@~1.33.0
25 +
26 +1.3.4 / 2017-08-22
27 +==================
28 +
29 + * deps: mime-types@~2.1.16
30 + - deps: mime-db@~1.29.0
31 +
32 +1.3.3 / 2016-05-02
33 +==================
34 +
35 + * deps: mime-types@~2.1.11
36 + - deps: mime-db@~1.23.0
37 + * deps: negotiator@0.6.1
38 + - perf: improve `Accept` parsing speed
39 + - perf: improve `Accept-Charset` parsing speed
40 + - perf: improve `Accept-Encoding` parsing speed
41 + - perf: improve `Accept-Language` parsing speed
42 +
43 +1.3.2 / 2016-03-08
44 +==================
45 +
46 + * deps: mime-types@~2.1.10
47 + - Fix extension of `application/dash+xml`
48 + - Update primary extension for `audio/mp4`
49 + - deps: mime-db@~1.22.0
50 +
51 +1.3.1 / 2016-01-19
52 +==================
53 +
54 + * deps: mime-types@~2.1.9
55 + - deps: mime-db@~1.21.0
56 +
57 +1.3.0 / 2015-09-29
58 +==================
59 +
60 + * deps: mime-types@~2.1.7
61 + - deps: mime-db@~1.19.0
62 + * deps: negotiator@0.6.0
63 + - Fix including type extensions in parameters in `Accept` parsing
64 + - Fix parsing `Accept` parameters with quoted equals
65 + - Fix parsing `Accept` parameters with quoted semicolons
66 + - Lazy-load modules from main entry point
67 + - perf: delay type concatenation until needed
68 + - perf: enable strict mode
69 + - perf: hoist regular expressions
70 + - perf: remove closures getting spec properties
71 + - perf: remove a closure from media type parsing
72 + - perf: remove property delete from media type parsing
73 +
74 +1.2.13 / 2015-09-06
75 +===================
76 +
77 + * deps: mime-types@~2.1.6
78 + - deps: mime-db@~1.18.0
79 +
80 +1.2.12 / 2015-07-30
81 +===================
82 +
83 + * deps: mime-types@~2.1.4
84 + - deps: mime-db@~1.16.0
85 +
86 +1.2.11 / 2015-07-16
87 +===================
88 +
89 + * deps: mime-types@~2.1.3
90 + - deps: mime-db@~1.15.0
91 +
92 +1.2.10 / 2015-07-01
93 +===================
94 +
95 + * deps: mime-types@~2.1.2
96 + - deps: mime-db@~1.14.0
97 +
98 +1.2.9 / 2015-06-08
99 +==================
100 +
101 + * deps: mime-types@~2.1.1
102 + - perf: fix deopt during mapping
103 +
104 +1.2.8 / 2015-06-07
105 +==================
106 +
107 + * deps: mime-types@~2.1.0
108 + - deps: mime-db@~1.13.0
109 + * perf: avoid argument reassignment & argument slice
110 + * perf: avoid negotiator recursive construction
111 + * perf: enable strict mode
112 + * perf: remove unnecessary bitwise operator
113 +
114 +1.2.7 / 2015-05-10
115 +==================
116 +
117 + * deps: negotiator@0.5.3
118 + - Fix media type parameter matching to be case-insensitive
119 +
120 +1.2.6 / 2015-05-07
121 +==================
122 +
123 + * deps: mime-types@~2.0.11
124 + - deps: mime-db@~1.9.1
125 + * deps: negotiator@0.5.2
126 + - Fix comparing media types with quoted values
127 + - Fix splitting media types with quoted commas
128 +
129 +1.2.5 / 2015-03-13
130 +==================
131 +
132 + * deps: mime-types@~2.0.10
133 + - deps: mime-db@~1.8.0
134 +
135 +1.2.4 / 2015-02-14
136 +==================
137 +
138 + * Support Node.js 0.6
139 + * deps: mime-types@~2.0.9
140 + - deps: mime-db@~1.7.0
141 + * deps: negotiator@0.5.1
142 + - Fix preference sorting to be stable for long acceptable lists
143 +
144 +1.2.3 / 2015-01-31
145 +==================
146 +
147 + * deps: mime-types@~2.0.8
148 + - deps: mime-db@~1.6.0
149 +
150 +1.2.2 / 2014-12-30
151 +==================
152 +
153 + * deps: mime-types@~2.0.7
154 + - deps: mime-db@~1.5.0
155 +
156 +1.2.1 / 2014-12-30
157 +==================
158 +
159 + * deps: mime-types@~2.0.5
160 + - deps: mime-db@~1.3.1
161 +
162 +1.2.0 / 2014-12-19
163 +==================
164 +
165 + * deps: negotiator@0.5.0
166 + - Fix list return order when large accepted list
167 + - Fix missing identity encoding when q=0 exists
168 + - Remove dynamic building of Negotiator class
169 +
170 +1.1.4 / 2014-12-10
171 +==================
172 +
173 + * deps: mime-types@~2.0.4
174 + - deps: mime-db@~1.3.0
175 +
176 +1.1.3 / 2014-11-09
177 +==================
178 +
179 + * deps: mime-types@~2.0.3
180 + - deps: mime-db@~1.2.0
181 +
182 +1.1.2 / 2014-10-14
183 +==================
184 +
185 + * deps: negotiator@0.4.9
186 + - Fix error when media type has invalid parameter
187 +
188 +1.1.1 / 2014-09-28
189 +==================
190 +
191 + * deps: mime-types@~2.0.2
192 + - deps: mime-db@~1.1.0
193 + * deps: negotiator@0.4.8
194 + - Fix all negotiations to be case-insensitive
195 + - Stable sort preferences of same quality according to client order
196 +
197 +1.1.0 / 2014-09-02
198 +==================
199 +
200 + * update `mime-types`
201 +
202 +1.0.7 / 2014-07-04
203 +==================
204 +
205 + * Fix wrong type returned from `type` when match after unknown extension
206 +
207 +1.0.6 / 2014-06-24
208 +==================
209 +
210 + * deps: negotiator@0.4.7
211 +
212 +1.0.5 / 2014-06-20
213 +==================
214 +
215 + * fix crash when unknown extension given
216 +
217 +1.0.4 / 2014-06-19
218 +==================
219 +
220 + * use `mime-types`
221 +
222 +1.0.3 / 2014-06-11
223 +==================
224 +
225 + * deps: negotiator@0.4.6
226 + - Order by specificity when quality is the same
227 +
228 +1.0.2 / 2014-05-29
229 +==================
230 +
231 + * Fix interpretation when header not in request
232 + * deps: pin negotiator@0.4.5
233 +
234 +1.0.1 / 2014-01-18
235 +==================
236 +
237 + * Identity encoding isn't always acceptable
238 + * deps: negotiator@~0.4.0
239 +
240 +1.0.0 / 2013-12-27
241 +==================
242 +
243 + * Genesis
1 +(The MIT License)
2 +
3 +Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
4 +Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
5 +
6 +Permission is hereby granted, free of charge, to any person obtaining
7 +a copy of this software and associated documentation files (the
8 +'Software'), to deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify, merge, publish,
10 +distribute, sublicense, and/or sell copies of the Software, and to
11 +permit persons to whom the Software is furnished to do so, subject to
12 +the following conditions:
13 +
14 +The above copyright notice and this permission notice shall be
15 +included in all copies or substantial portions of the Software.
16 +
17 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +# accepts
2 +
3 +[![NPM Version][npm-version-image]][npm-url]
4 +[![NPM Downloads][npm-downloads-image]][npm-url]
5 +[![Node.js Version][node-version-image]][node-version-url]
6 +[![Build Status][github-actions-ci-image]][github-actions-ci-url]
7 +[![Test Coverage][coveralls-image]][coveralls-url]
8 +
9 +Higher level content negotiation based on [negotiator](https://www.npmjs.com/package/negotiator).
10 +Extracted from [koa](https://www.npmjs.com/package/koa) for general use.
11 +
12 +In addition to negotiator, it allows:
13 +
14 +- Allows types as an array or arguments list, ie `(['text/html', 'application/json'])`
15 + as well as `('text/html', 'application/json')`.
16 +- Allows type shorthands such as `json`.
17 +- Returns `false` when no types match
18 +- Treats non-existent headers as `*`
19 +
20 +## Installation
21 +
22 +This is a [Node.js](https://nodejs.org/en/) module available through the
23 +[npm registry](https://www.npmjs.com/). Installation is done using the
24 +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
25 +
26 +```sh
27 +$ npm install accepts
28 +```
29 +
30 +## API
31 +
32 +```js
33 +var accepts = require('accepts')
34 +```
35 +
36 +### accepts(req)
37 +
38 +Create a new `Accepts` object for the given `req`.
39 +
40 +#### .charset(charsets)
41 +
42 +Return the first accepted charset. If nothing in `charsets` is accepted,
43 +then `false` is returned.
44 +
45 +#### .charsets()
46 +
47 +Return the charsets that the request accepts, in the order of the client's
48 +preference (most preferred first).
49 +
50 +#### .encoding(encodings)
51 +
52 +Return the first accepted encoding. If nothing in `encodings` is accepted,
53 +then `false` is returned.
54 +
55 +#### .encodings()
56 +
57 +Return the encodings that the request accepts, in the order of the client's
58 +preference (most preferred first).
59 +
60 +#### .language(languages)
61 +
62 +Return the first accepted language. If nothing in `languages` is accepted,
63 +then `false` is returned.
64 +
65 +#### .languages()
66 +
67 +Return the languages that the request accepts, in the order of the client's
68 +preference (most preferred first).
69 +
70 +#### .type(types)
71 +
72 +Return the first accepted type (and it is returned as the same text as what
73 +appears in the `types` array). If nothing in `types` is accepted, then `false`
74 +is returned.
75 +
76 +The `types` array can contain full MIME types or file extensions. Any value
77 +that is not a full MIME types is passed to `require('mime-types').lookup`.
78 +
79 +#### .types()
80 +
81 +Return the types that the request accepts, in the order of the client's
82 +preference (most preferred first).
83 +
84 +## Examples
85 +
86 +### Simple type negotiation
87 +
88 +This simple example shows how to use `accepts` to return a different typed
89 +respond body based on what the client wants to accept. The server lists it's
90 +preferences in order and will get back the best match between the client and
91 +server.
92 +
93 +```js
94 +var accepts = require('accepts')
95 +var http = require('http')
96 +
97 +function app (req, res) {
98 + var accept = accepts(req)
99 +
100 + // the order of this list is significant; should be server preferred order
101 + switch (accept.type(['json', 'html'])) {
102 + case 'json':
103 + res.setHeader('Content-Type', 'application/json')
104 + res.write('{"hello":"world!"}')
105 + break
106 + case 'html':
107 + res.setHeader('Content-Type', 'text/html')
108 + res.write('<b>hello, world!</b>')
109 + break
110 + default:
111 + // the fallback is text/plain, so no need to specify it above
112 + res.setHeader('Content-Type', 'text/plain')
113 + res.write('hello, world!')
114 + break
115 + }
116 +
117 + res.end()
118 +}
119 +
120 +http.createServer(app).listen(3000)
121 +```
122 +
123 +You can test this out with the cURL program:
124 +```sh
125 +curl -I -H'Accept: text/html' http://localhost:3000/
126 +```
127 +
128 +## License
129 +
130 +[MIT](LICENSE)
131 +
132 +[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/accepts/master
133 +[coveralls-url]: https://coveralls.io/r/jshttp/accepts?branch=master
134 +[github-actions-ci-image]: https://badgen.net/github/checks/jshttp/accepts/master?label=ci
135 +[github-actions-ci-url]: https://github.com/jshttp/accepts/actions/workflows/ci.yml
136 +[node-version-image]: https://badgen.net/npm/node/accepts
137 +[node-version-url]: https://nodejs.org/en/download
138 +[npm-downloads-image]: https://badgen.net/npm/dm/accepts
139 +[npm-url]: https://npmjs.org/package/accepts
140 +[npm-version-image]: https://badgen.net/npm/v/accepts
1 +/*!
2 + * accepts
3 + * Copyright(c) 2014 Jonathan Ong
4 + * Copyright(c) 2015 Douglas Christopher Wilson
5 + * MIT Licensed
6 + */
7 +
8 +'use strict'
9 +
10 +/**
11 + * Module dependencies.
12 + * @private
13 + */
14 +
15 +var Negotiator = require('negotiator')
16 +var mime = require('mime-types')
17 +
18 +/**
19 + * Module exports.
20 + * @public
21 + */
22 +
23 +module.exports = Accepts
24 +
25 +/**
26 + * Create a new Accepts object for the given req.
27 + *
28 + * @param {object} req
29 + * @public
30 + */
31 +
32 +function Accepts (req) {
33 + if (!(this instanceof Accepts)) {
34 + return new Accepts(req)
35 + }
36 +
37 + this.headers = req.headers
38 + this.negotiator = new Negotiator(req)
39 +}
40 +
41 +/**
42 + * Check if the given `type(s)` is acceptable, returning
43 + * the best match when true, otherwise `undefined`, in which
44 + * case you should respond with 406 "Not Acceptable".
45 + *
46 + * The `type` value may be a single mime type string
47 + * such as "application/json", the extension name
48 + * such as "json" or an array `["json", "html", "text/plain"]`. When a list
49 + * or array is given the _best_ match, if any is returned.
50 + *
51 + * Examples:
52 + *
53 + * // Accept: text/html
54 + * this.types('html');
55 + * // => "html"
56 + *
57 + * // Accept: text/*, application/json
58 + * this.types('html');
59 + * // => "html"
60 + * this.types('text/html');
61 + * // => "text/html"
62 + * this.types('json', 'text');
63 + * // => "json"
64 + * this.types('application/json');
65 + * // => "application/json"
66 + *
67 + * // Accept: text/*, application/json
68 + * this.types('image/png');
69 + * this.types('png');
70 + * // => undefined
71 + *
72 + * // Accept: text/*;q=.5, application/json
73 + * this.types(['html', 'json']);
74 + * this.types('html', 'json');
75 + * // => "json"
76 + *
77 + * @param {String|Array} types...
78 + * @return {String|Array|Boolean}
79 + * @public
80 + */
81 +
82 +Accepts.prototype.type =
83 +Accepts.prototype.types = function (types_) {
84 + var types = types_
85 +
86 + // support flattened arguments
87 + if (types && !Array.isArray(types)) {
88 + types = new Array(arguments.length)
89 + for (var i = 0; i < types.length; i++) {
90 + types[i] = arguments[i]
91 + }
92 + }
93 +
94 + // no types, return all requested types
95 + if (!types || types.length === 0) {
96 + return this.negotiator.mediaTypes()
97 + }
98 +
99 + // no accept header, return first given type
100 + if (!this.headers.accept) {
101 + return types[0]
102 + }
103 +
104 + var mimes = types.map(extToMime)
105 + var accepts = this.negotiator.mediaTypes(mimes.filter(validMime))
106 + var first = accepts[0]
107 +
108 + return first
109 + ? types[mimes.indexOf(first)]
110 + : false
111 +}
112 +
113 +/**
114 + * Return accepted encodings or best fit based on `encodings`.
115 + *
116 + * Given `Accept-Encoding: gzip, deflate`
117 + * an array sorted by quality is returned:
118 + *
119 + * ['gzip', 'deflate']
120 + *
121 + * @param {String|Array} encodings...
122 + * @return {String|Array}
123 + * @public
124 + */
125 +
126 +Accepts.prototype.encoding =
127 +Accepts.prototype.encodings = function (encodings_) {
128 + var encodings = encodings_
129 +
130 + // support flattened arguments
131 + if (encodings && !Array.isArray(encodings)) {
132 + encodings = new Array(arguments.length)
133 + for (var i = 0; i < encodings.length; i++) {
134 + encodings[i] = arguments[i]
135 + }
136 + }
137 +
138 + // no encodings, return all requested encodings
139 + if (!encodings || encodings.length === 0) {
140 + return this.negotiator.encodings()
141 + }
142 +
143 + return this.negotiator.encodings(encodings)[0] || false
144 +}
145 +
146 +/**
147 + * Return accepted charsets or best fit based on `charsets`.
148 + *
149 + * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
150 + * an array sorted by quality is returned:
151 + *
152 + * ['utf-8', 'utf-7', 'iso-8859-1']
153 + *
154 + * @param {String|Array} charsets...
155 + * @return {String|Array}
156 + * @public
157 + */
158 +
159 +Accepts.prototype.charset =
160 +Accepts.prototype.charsets = function (charsets_) {
161 + var charsets = charsets_
162 +
163 + // support flattened arguments
164 + if (charsets && !Array.isArray(charsets)) {
165 + charsets = new Array(arguments.length)
166 + for (var i = 0; i < charsets.length; i++) {
167 + charsets[i] = arguments[i]
168 + }
169 + }
170 +
171 + // no charsets, return all requested charsets
172 + if (!charsets || charsets.length === 0) {
173 + return this.negotiator.charsets()
174 + }
175 +
176 + return this.negotiator.charsets(charsets)[0] || false
177 +}
178 +
179 +/**
180 + * Return accepted languages or best fit based on `langs`.
181 + *
182 + * Given `Accept-Language: en;q=0.8, es, pt`
183 + * an array sorted by quality is returned:
184 + *
185 + * ['es', 'pt', 'en']
186 + *
187 + * @param {String|Array} langs...
188 + * @return {Array|String}
189 + * @public
190 + */
191 +
192 +Accepts.prototype.lang =
193 +Accepts.prototype.langs =
194 +Accepts.prototype.language =
195 +Accepts.prototype.languages = function (languages_) {
196 + var languages = languages_
197 +
198 + // support flattened arguments
199 + if (languages && !Array.isArray(languages)) {
200 + languages = new Array(arguments.length)
201 + for (var i = 0; i < languages.length; i++) {
202 + languages[i] = arguments[i]
203 + }
204 + }
205 +
206 + // no languages, return all requested languages
207 + if (!languages || languages.length === 0) {
208 + return this.negotiator.languages()
209 + }
210 +
211 + return this.negotiator.languages(languages)[0] || false
212 +}
213 +
214 +/**
215 + * Convert extnames to mime.
216 + *
217 + * @param {String} type
218 + * @return {String}
219 + * @private
220 + */
221 +
222 +function extToMime (type) {
223 + return type.indexOf('/') === -1
224 + ? mime.lookup(type)
225 + : type
226 +}
227 +
228 +/**
229 + * Check if mime is valid.
230 + *
231 + * @param {String} type
232 + * @return {String}
233 + * @private
234 + */
235 +
236 +function validMime (type) {
237 + return typeof type === 'string'
238 +}
1 +{
2 + "name": "accepts",
3 + "description": "Higher-level content negotiation",
4 + "version": "1.3.8",
5 + "contributors": [
6 + "Douglas Christopher Wilson <doug@somethingdoug.com>",
7 + "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
8 + ],
9 + "license": "MIT",
10 + "repository": "jshttp/accepts",
11 + "dependencies": {
12 + "mime-types": "~2.1.34",
13 + "negotiator": "0.6.3"
14 + },
15 + "devDependencies": {
16 + "deep-equal": "1.0.1",
17 + "eslint": "7.32.0",
18 + "eslint-config-standard": "14.1.1",
19 + "eslint-plugin-import": "2.25.4",
20 + "eslint-plugin-markdown": "2.2.1",
21 + "eslint-plugin-node": "11.1.0",
22 + "eslint-plugin-promise": "4.3.1",
23 + "eslint-plugin-standard": "4.1.0",
24 + "mocha": "9.2.0",
25 + "nyc": "15.1.0"
26 + },
27 + "files": [
28 + "LICENSE",
29 + "HISTORY.md",
30 + "index.js"
31 + ],
32 + "engines": {
33 + "node": ">= 0.6"
34 + },
35 + "scripts": {
36 + "lint": "eslint .",
37 + "test": "mocha --reporter spec --check-leaks --bail test/",
38 + "test-ci": "nyc --reporter=lcov --reporter=text npm test",
39 + "test-cov": "nyc --reporter=html --reporter=text npm test"
40 + },
41 + "keywords": [
42 + "content",
43 + "negotiation",
44 + "accept",
45 + "accepts"
46 + ]
47 +}
1 +The MIT License (MIT)
2 +
3 +Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in
13 +all copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 +THE SOFTWARE.
1 +# Array Flatten
2 +
3 +[![NPM version][npm-image]][npm-url]
4 +[![NPM downloads][downloads-image]][downloads-url]
5 +[![Build status][travis-image]][travis-url]
6 +[![Test coverage][coveralls-image]][coveralls-url]
7 +
8 +> Flatten an array of nested arrays into a single flat array. Accepts an optional depth.
9 +
10 +## Installation
11 +
12 +```
13 +npm install array-flatten --save
14 +```
15 +
16 +## Usage
17 +
18 +```javascript
19 +var flatten = require('array-flatten')
20 +
21 +flatten([1, [2, [3, [4, [5], 6], 7], 8], 9])
22 +//=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
23 +
24 +flatten([1, [2, [3, [4, [5], 6], 7], 8], 9], 2)
25 +//=> [1, 2, 3, [4, [5], 6], 7, 8, 9]
26 +
27 +(function () {
28 + flatten(arguments) //=> [1, 2, 3]
29 +})(1, [2, 3])
30 +```
31 +
32 +## License
33 +
34 +MIT
35 +
36 +[npm-image]: https://img.shields.io/npm/v/array-flatten.svg?style=flat
37 +[npm-url]: https://npmjs.org/package/array-flatten
38 +[downloads-image]: https://img.shields.io/npm/dm/array-flatten.svg?style=flat
39 +[downloads-url]: https://npmjs.org/package/array-flatten
40 +[travis-image]: https://img.shields.io/travis/blakeembrey/array-flatten.svg?style=flat
41 +[travis-url]: https://travis-ci.org/blakeembrey/array-flatten
42 +[coveralls-image]: https://img.shields.io/coveralls/blakeembrey/array-flatten.svg?style=flat
43 +[coveralls-url]: https://coveralls.io/r/blakeembrey/array-flatten?branch=master
1 +'use strict'
2 +
3 +/**
4 + * Expose `arrayFlatten`.
5 + */
6 +module.exports = arrayFlatten
7 +
8 +/**
9 + * Recursive flatten function with depth.
10 + *
11 + * @param {Array} array
12 + * @param {Array} result
13 + * @param {Number} depth
14 + * @return {Array}
15 + */
16 +function flattenWithDepth (array, result, depth) {
17 + for (var i = 0; i < array.length; i++) {
18 + var value = array[i]
19 +
20 + if (depth > 0 && Array.isArray(value)) {
21 + flattenWithDepth(value, result, depth - 1)
22 + } else {
23 + result.push(value)
24 + }
25 + }
26 +
27 + return result
28 +}
29 +
30 +/**
31 + * Recursive flatten function. Omitting depth is slightly faster.
32 + *
33 + * @param {Array} array
34 + * @param {Array} result
35 + * @return {Array}
36 + */
37 +function flattenForever (array, result) {
38 + for (var i = 0; i < array.length; i++) {
39 + var value = array[i]
40 +
41 + if (Array.isArray(value)) {
42 + flattenForever(value, result)
43 + } else {
44 + result.push(value)
45 + }
46 + }
47 +
48 + return result
49 +}
50 +
51 +/**
52 + * Flatten an array, with the ability to define a depth.
53 + *
54 + * @param {Array} array
55 + * @param {Number} depth
56 + * @return {Array}
57 + */
58 +function arrayFlatten (array, depth) {
59 + if (depth == null) {
60 + return flattenForever(array, [])
61 + }
62 +
63 + return flattenWithDepth(array, [], depth)
64 +}
1 +{
2 + "name": "array-flatten",
3 + "version": "1.1.1",
4 + "description": "Flatten an array of nested arrays into a single flat array",
5 + "main": "array-flatten.js",
6 + "files": [
7 + "array-flatten.js",
8 + "LICENSE"
9 + ],
10 + "scripts": {
11 + "test": "istanbul cover _mocha -- -R spec"
12 + },
13 + "repository": {
14 + "type": "git",
15 + "url": "git://github.com/blakeembrey/array-flatten.git"
16 + },
17 + "keywords": [
18 + "array",
19 + "flatten",
20 + "arguments",
21 + "depth"
22 + ],
23 + "author": {
24 + "name": "Blake Embrey",
25 + "email": "hello@blakeembrey.com",
26 + "url": "http://blakeembrey.me"
27 + },
28 + "license": "MIT",
29 + "bugs": {
30 + "url": "https://github.com/blakeembrey/array-flatten/issues"
31 + },
32 + "homepage": "https://github.com/blakeembrey/array-flatten",
33 + "devDependencies": {
34 + "istanbul": "^0.3.13",
35 + "mocha": "^2.2.4",
36 + "pre-commit": "^1.0.7",
37 + "standard": "^3.7.3"
38 + }
39 +}
1 +module.exports = {
2 + 'env': {
3 + 'browser': false,
4 + 'commonjs': true,
5 + 'es6': true,
6 + 'node': true
7 + },
8 + 'extends': 'eslint:recommended',
9 + 'rules': {
10 + 'indent': [
11 + 'error',
12 + 2
13 + ],
14 + 'linebreak-style': [
15 + 'error',
16 + 'unix'
17 + ],
18 + 'quotes': [
19 + 'error',
20 + 'single'
21 + ],
22 + 'semi': [
23 + 'error',
24 + 'always'
25 + ]
26 + }
27 +};
1 +MIT License
2 +
3 +Copyright (c) 2017 Fedor Indutny
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +# ASN1.js
2 +
3 +ASN.1 DER Encoder/Decoder and DSL.
4 +
5 +## Example
6 +
7 +Define model:
8 +
9 +```javascript
10 +var asn = require('asn1.js');
11 +
12 +var Human = asn.define('Human', function() {
13 + this.seq().obj(
14 + this.key('firstName').octstr(),
15 + this.key('lastName').octstr(),
16 + this.key('age').int(),
17 + this.key('gender').enum({ 0: 'male', 1: 'female' }),
18 + this.key('bio').seqof(Bio)
19 + );
20 +});
21 +
22 +var Bio = asn.define('Bio', function() {
23 + this.seq().obj(
24 + this.key('time').gentime(),
25 + this.key('description').octstr()
26 + );
27 +});
28 +```
29 +
30 +Encode data:
31 +
32 +```javascript
33 +var output = Human.encode({
34 + firstName: 'Thomas',
35 + lastName: 'Anderson',
36 + age: 28,
37 + gender: 'male',
38 + bio: [
39 + {
40 + time: +new Date('31 March 1999'),
41 + description: 'freedom of mind'
42 + }
43 + ]
44 +}, 'der');
45 +```
46 +
47 +Decode data:
48 +
49 +```javascript
50 +var human = Human.decode(output, 'der');
51 +console.log(human);
52 +/*
53 +{ firstName: <Buffer 54 68 6f 6d 61 73>,
54 + lastName: <Buffer 41 6e 64 65 72 73 6f 6e>,
55 + age: 28,
56 + gender: 'male',
57 + bio:
58 + [ { time: 922820400000,
59 + description: <Buffer 66 72 65 65 64 6f 6d 20 6f 66 20 6d 69 6e 64> } ] }
60 +*/
61 +```
62 +
63 +### Partial decode
64 +
65 +Its possible to parse data without stopping on first error. In order to do it,
66 +you should call:
67 +
68 +```javascript
69 +var human = Human.decode(output, 'der', { partial: true });
70 +console.log(human);
71 +/*
72 +{ result: { ... },
73 + errors: [ ... ] }
74 +*/
75 +```
76 +
77 +#### LICENSE
78 +
79 +This software is licensed under the MIT License.
80 +
81 +Copyright Fedor Indutny, 2017.
82 +
83 +Permission is hereby granted, free of charge, to any person obtaining a
84 +copy of this software and associated documentation files (the
85 +"Software"), to deal in the Software without restriction, including
86 +without limitation the rights to use, copy, modify, merge, publish,
87 +distribute, sublicense, and/or sell copies of the Software, and to permit
88 +persons to whom the Software is furnished to do so, subject to the
89 +following conditions:
90 +
91 +The above copyright notice and this permission notice shall be included
92 +in all copies or substantial portions of the Software.
93 +
94 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
95 +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
96 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
97 +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
98 +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
99 +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
100 +USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +'use strict';
2 +
3 +const asn1 = exports;
4 +
5 +asn1.bignum = require('bn.js');
6 +
7 +asn1.define = require('./asn1/api').define;
8 +asn1.base = require('./asn1/base');
9 +asn1.constants = require('./asn1/constants');
10 +asn1.decoders = require('./asn1/decoders');
11 +asn1.encoders = require('./asn1/encoders');
1 +'use strict';
2 +
3 +const encoders = require('./encoders');
4 +const decoders = require('./decoders');
5 +const inherits = require('inherits');
6 +
7 +const api = exports;
8 +
9 +api.define = function define(name, body) {
10 + return new Entity(name, body);
11 +};
12 +
13 +function Entity(name, body) {
14 + this.name = name;
15 + this.body = body;
16 +
17 + this.decoders = {};
18 + this.encoders = {};
19 +}
20 +
21 +Entity.prototype._createNamed = function createNamed(Base) {
22 + const name = this.name;
23 +
24 + function Generated(entity) {
25 + this._initNamed(entity, name);
26 + }
27 + inherits(Generated, Base);
28 + Generated.prototype._initNamed = function _initNamed(entity, name) {
29 + Base.call(this, entity, name);
30 + };
31 +
32 + return new Generated(this);
33 +};
34 +
35 +Entity.prototype._getDecoder = function _getDecoder(enc) {
36 + enc = enc || 'der';
37 + // Lazily create decoder
38 + if (!this.decoders.hasOwnProperty(enc))
39 + this.decoders[enc] = this._createNamed(decoders[enc]);
40 + return this.decoders[enc];
41 +};
42 +
43 +Entity.prototype.decode = function decode(data, enc, options) {
44 + return this._getDecoder(enc).decode(data, options);
45 +};
46 +
47 +Entity.prototype._getEncoder = function _getEncoder(enc) {
48 + enc = enc || 'der';
49 + // Lazily create encoder
50 + if (!this.encoders.hasOwnProperty(enc))
51 + this.encoders[enc] = this._createNamed(encoders[enc]);
52 + return this.encoders[enc];
53 +};
54 +
55 +Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) {
56 + return this._getEncoder(enc).encode(data, reporter);
57 +};
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +const Reporter = require('../base/reporter').Reporter;
5 +const Buffer = require('safer-buffer').Buffer;
6 +
7 +function DecoderBuffer(base, options) {
8 + Reporter.call(this, options);
9 + if (!Buffer.isBuffer(base)) {
10 + this.error('Input not Buffer');
11 + return;
12 + }
13 +
14 + this.base = base;
15 + this.offset = 0;
16 + this.length = base.length;
17 +}
18 +inherits(DecoderBuffer, Reporter);
19 +exports.DecoderBuffer = DecoderBuffer;
20 +
21 +DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) {
22 + if (data instanceof DecoderBuffer) {
23 + return true;
24 + }
25 +
26 + // Or accept compatible API
27 + const isCompatible = typeof data === 'object' &&
28 + Buffer.isBuffer(data.base) &&
29 + data.constructor.name === 'DecoderBuffer' &&
30 + typeof data.offset === 'number' &&
31 + typeof data.length === 'number' &&
32 + typeof data.save === 'function' &&
33 + typeof data.restore === 'function' &&
34 + typeof data.isEmpty === 'function' &&
35 + typeof data.readUInt8 === 'function' &&
36 + typeof data.skip === 'function' &&
37 + typeof data.raw === 'function';
38 +
39 + return isCompatible;
40 +};
41 +
42 +DecoderBuffer.prototype.save = function save() {
43 + return { offset: this.offset, reporter: Reporter.prototype.save.call(this) };
44 +};
45 +
46 +DecoderBuffer.prototype.restore = function restore(save) {
47 + // Return skipped data
48 + const res = new DecoderBuffer(this.base);
49 + res.offset = save.offset;
50 + res.length = this.offset;
51 +
52 + this.offset = save.offset;
53 + Reporter.prototype.restore.call(this, save.reporter);
54 +
55 + return res;
56 +};
57 +
58 +DecoderBuffer.prototype.isEmpty = function isEmpty() {
59 + return this.offset === this.length;
60 +};
61 +
62 +DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) {
63 + if (this.offset + 1 <= this.length)
64 + return this.base.readUInt8(this.offset++, true);
65 + else
66 + return this.error(fail || 'DecoderBuffer overrun');
67 +};
68 +
69 +DecoderBuffer.prototype.skip = function skip(bytes, fail) {
70 + if (!(this.offset + bytes <= this.length))
71 + return this.error(fail || 'DecoderBuffer overrun');
72 +
73 + const res = new DecoderBuffer(this.base);
74 +
75 + // Share reporter state
76 + res._reporterState = this._reporterState;
77 +
78 + res.offset = this.offset;
79 + res.length = this.offset + bytes;
80 + this.offset += bytes;
81 + return res;
82 +};
83 +
84 +DecoderBuffer.prototype.raw = function raw(save) {
85 + return this.base.slice(save ? save.offset : this.offset, this.length);
86 +};
87 +
88 +function EncoderBuffer(value, reporter) {
89 + if (Array.isArray(value)) {
90 + this.length = 0;
91 + this.value = value.map(function(item) {
92 + if (!EncoderBuffer.isEncoderBuffer(item))
93 + item = new EncoderBuffer(item, reporter);
94 + this.length += item.length;
95 + return item;
96 + }, this);
97 + } else if (typeof value === 'number') {
98 + if (!(0 <= value && value <= 0xff))
99 + return reporter.error('non-byte EncoderBuffer value');
100 + this.value = value;
101 + this.length = 1;
102 + } else if (typeof value === 'string') {
103 + this.value = value;
104 + this.length = Buffer.byteLength(value);
105 + } else if (Buffer.isBuffer(value)) {
106 + this.value = value;
107 + this.length = value.length;
108 + } else {
109 + return reporter.error('Unsupported type: ' + typeof value);
110 + }
111 +}
112 +exports.EncoderBuffer = EncoderBuffer;
113 +
114 +EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) {
115 + if (data instanceof EncoderBuffer) {
116 + return true;
117 + }
118 +
119 + // Or accept compatible API
120 + const isCompatible = typeof data === 'object' &&
121 + data.constructor.name === 'EncoderBuffer' &&
122 + typeof data.length === 'number' &&
123 + typeof data.join === 'function';
124 +
125 + return isCompatible;
126 +};
127 +
128 +EncoderBuffer.prototype.join = function join(out, offset) {
129 + if (!out)
130 + out = Buffer.alloc(this.length);
131 + if (!offset)
132 + offset = 0;
133 +
134 + if (this.length === 0)
135 + return out;
136 +
137 + if (Array.isArray(this.value)) {
138 + this.value.forEach(function(item) {
139 + item.join(out, offset);
140 + offset += item.length;
141 + });
142 + } else {
143 + if (typeof this.value === 'number')
144 + out[offset] = this.value;
145 + else if (typeof this.value === 'string')
146 + out.write(this.value, offset);
147 + else if (Buffer.isBuffer(this.value))
148 + this.value.copy(out, offset);
149 + offset += this.length;
150 + }
151 +
152 + return out;
153 +};
1 +'use strict';
2 +
3 +const base = exports;
4 +
5 +base.Reporter = require('./reporter').Reporter;
6 +base.DecoderBuffer = require('./buffer').DecoderBuffer;
7 +base.EncoderBuffer = require('./buffer').EncoderBuffer;
8 +base.Node = require('./node');
This diff is collapsed. Click to expand it.
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +
5 +function Reporter(options) {
6 + this._reporterState = {
7 + obj: null,
8 + path: [],
9 + options: options || {},
10 + errors: []
11 + };
12 +}
13 +exports.Reporter = Reporter;
14 +
15 +Reporter.prototype.isError = function isError(obj) {
16 + return obj instanceof ReporterError;
17 +};
18 +
19 +Reporter.prototype.save = function save() {
20 + const state = this._reporterState;
21 +
22 + return { obj: state.obj, pathLen: state.path.length };
23 +};
24 +
25 +Reporter.prototype.restore = function restore(data) {
26 + const state = this._reporterState;
27 +
28 + state.obj = data.obj;
29 + state.path = state.path.slice(0, data.pathLen);
30 +};
31 +
32 +Reporter.prototype.enterKey = function enterKey(key) {
33 + return this._reporterState.path.push(key);
34 +};
35 +
36 +Reporter.prototype.exitKey = function exitKey(index) {
37 + const state = this._reporterState;
38 +
39 + state.path = state.path.slice(0, index - 1);
40 +};
41 +
42 +Reporter.prototype.leaveKey = function leaveKey(index, key, value) {
43 + const state = this._reporterState;
44 +
45 + this.exitKey(index);
46 + if (state.obj !== null)
47 + state.obj[key] = value;
48 +};
49 +
50 +Reporter.prototype.path = function path() {
51 + return this._reporterState.path.join('/');
52 +};
53 +
54 +Reporter.prototype.enterObject = function enterObject() {
55 + const state = this._reporterState;
56 +
57 + const prev = state.obj;
58 + state.obj = {};
59 + return prev;
60 +};
61 +
62 +Reporter.prototype.leaveObject = function leaveObject(prev) {
63 + const state = this._reporterState;
64 +
65 + const now = state.obj;
66 + state.obj = prev;
67 + return now;
68 +};
69 +
70 +Reporter.prototype.error = function error(msg) {
71 + let err;
72 + const state = this._reporterState;
73 +
74 + const inherited = msg instanceof ReporterError;
75 + if (inherited) {
76 + err = msg;
77 + } else {
78 + err = new ReporterError(state.path.map(function(elem) {
79 + return '[' + JSON.stringify(elem) + ']';
80 + }).join(''), msg.message || msg, msg.stack);
81 + }
82 +
83 + if (!state.options.partial)
84 + throw err;
85 +
86 + if (!inherited)
87 + state.errors.push(err);
88 +
89 + return err;
90 +};
91 +
92 +Reporter.prototype.wrapResult = function wrapResult(result) {
93 + const state = this._reporterState;
94 + if (!state.options.partial)
95 + return result;
96 +
97 + return {
98 + result: this.isError(result) ? null : result,
99 + errors: state.errors
100 + };
101 +};
102 +
103 +function ReporterError(path, msg) {
104 + this.path = path;
105 + this.rethrow(msg);
106 +}
107 +inherits(ReporterError, Error);
108 +
109 +ReporterError.prototype.rethrow = function rethrow(msg) {
110 + this.message = msg + ' at: ' + (this.path || '(shallow)');
111 + if (Error.captureStackTrace)
112 + Error.captureStackTrace(this, ReporterError);
113 +
114 + if (!this.stack) {
115 + try {
116 + // IE only adds stack when thrown
117 + throw new Error(this.message);
118 + } catch (e) {
119 + this.stack = e.stack;
120 + }
121 + }
122 + return this;
123 +};
1 +'use strict';
2 +
3 +// Helper
4 +function reverse(map) {
5 + const res = {};
6 +
7 + Object.keys(map).forEach(function(key) {
8 + // Convert key to integer if it is stringified
9 + if ((key | 0) == key)
10 + key = key | 0;
11 +
12 + const value = map[key];
13 + res[value] = key;
14 + });
15 +
16 + return res;
17 +}
18 +
19 +exports.tagClass = {
20 + 0: 'universal',
21 + 1: 'application',
22 + 2: 'context',
23 + 3: 'private'
24 +};
25 +exports.tagClassByName = reverse(exports.tagClass);
26 +
27 +exports.tag = {
28 + 0x00: 'end',
29 + 0x01: 'bool',
30 + 0x02: 'int',
31 + 0x03: 'bitstr',
32 + 0x04: 'octstr',
33 + 0x05: 'null_',
34 + 0x06: 'objid',
35 + 0x07: 'objDesc',
36 + 0x08: 'external',
37 + 0x09: 'real',
38 + 0x0a: 'enum',
39 + 0x0b: 'embed',
40 + 0x0c: 'utf8str',
41 + 0x0d: 'relativeOid',
42 + 0x10: 'seq',
43 + 0x11: 'set',
44 + 0x12: 'numstr',
45 + 0x13: 'printstr',
46 + 0x14: 't61str',
47 + 0x15: 'videostr',
48 + 0x16: 'ia5str',
49 + 0x17: 'utctime',
50 + 0x18: 'gentime',
51 + 0x19: 'graphstr',
52 + 0x1a: 'iso646str',
53 + 0x1b: 'genstr',
54 + 0x1c: 'unistr',
55 + 0x1d: 'charstr',
56 + 0x1e: 'bmpstr'
57 +};
58 +exports.tagByName = reverse(exports.tag);
1 +'use strict';
2 +
3 +const constants = exports;
4 +
5 +// Helper
6 +constants._reverse = function reverse(map) {
7 + const res = {};
8 +
9 + Object.keys(map).forEach(function(key) {
10 + // Convert key to integer if it is stringified
11 + if ((key | 0) == key)
12 + key = key | 0;
13 +
14 + const value = map[key];
15 + res[value] = key;
16 + });
17 +
18 + return res;
19 +};
20 +
21 +constants.der = require('./der');
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +
5 +const bignum = require('bn.js');
6 +const DecoderBuffer = require('../base/buffer').DecoderBuffer;
7 +const Node = require('../base/node');
8 +
9 +// Import DER constants
10 +const der = require('../constants/der');
11 +
12 +function DERDecoder(entity) {
13 + this.enc = 'der';
14 + this.name = entity.name;
15 + this.entity = entity;
16 +
17 + // Construct base tree
18 + this.tree = new DERNode();
19 + this.tree._init(entity.body);
20 +}
21 +module.exports = DERDecoder;
22 +
23 +DERDecoder.prototype.decode = function decode(data, options) {
24 + if (!DecoderBuffer.isDecoderBuffer(data)) {
25 + data = new DecoderBuffer(data, options);
26 + }
27 +
28 + return this.tree._decode(data, options);
29 +};
30 +
31 +// Tree methods
32 +
33 +function DERNode(parent) {
34 + Node.call(this, 'der', parent);
35 +}
36 +inherits(DERNode, Node);
37 +
38 +DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {
39 + if (buffer.isEmpty())
40 + return false;
41 +
42 + const state = buffer.save();
43 + const decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');
44 + if (buffer.isError(decodedTag))
45 + return decodedTag;
46 +
47 + buffer.restore(state);
48 +
49 + return decodedTag.tag === tag || decodedTag.tagStr === tag ||
50 + (decodedTag.tagStr + 'of') === tag || any;
51 +};
52 +
53 +DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {
54 + const decodedTag = derDecodeTag(buffer,
55 + 'Failed to decode tag of "' + tag + '"');
56 + if (buffer.isError(decodedTag))
57 + return decodedTag;
58 +
59 + let len = derDecodeLen(buffer,
60 + decodedTag.primitive,
61 + 'Failed to get length of "' + tag + '"');
62 +
63 + // Failure
64 + if (buffer.isError(len))
65 + return len;
66 +
67 + if (!any &&
68 + decodedTag.tag !== tag &&
69 + decodedTag.tagStr !== tag &&
70 + decodedTag.tagStr + 'of' !== tag) {
71 + return buffer.error('Failed to match tag: "' + tag + '"');
72 + }
73 +
74 + if (decodedTag.primitive || len !== null)
75 + return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
76 +
77 + // Indefinite length... find END tag
78 + const state = buffer.save();
79 + const res = this._skipUntilEnd(
80 + buffer,
81 + 'Failed to skip indefinite length body: "' + this.tag + '"');
82 + if (buffer.isError(res))
83 + return res;
84 +
85 + len = buffer.offset - state.offset;
86 + buffer.restore(state);
87 + return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
88 +};
89 +
90 +DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {
91 + for (;;) {
92 + const tag = derDecodeTag(buffer, fail);
93 + if (buffer.isError(tag))
94 + return tag;
95 + const len = derDecodeLen(buffer, tag.primitive, fail);
96 + if (buffer.isError(len))
97 + return len;
98 +
99 + let res;
100 + if (tag.primitive || len !== null)
101 + res = buffer.skip(len);
102 + else
103 + res = this._skipUntilEnd(buffer, fail);
104 +
105 + // Failure
106 + if (buffer.isError(res))
107 + return res;
108 +
109 + if (tag.tagStr === 'end')
110 + break;
111 + }
112 +};
113 +
114 +DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,
115 + options) {
116 + const result = [];
117 + while (!buffer.isEmpty()) {
118 + const possibleEnd = this._peekTag(buffer, 'end');
119 + if (buffer.isError(possibleEnd))
120 + return possibleEnd;
121 +
122 + const res = decoder.decode(buffer, 'der', options);
123 + if (buffer.isError(res) && possibleEnd)
124 + break;
125 + result.push(res);
126 + }
127 + return result;
128 +};
129 +
130 +DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {
131 + if (tag === 'bitstr') {
132 + const unused = buffer.readUInt8();
133 + if (buffer.isError(unused))
134 + return unused;
135 + return { unused: unused, data: buffer.raw() };
136 + } else if (tag === 'bmpstr') {
137 + const raw = buffer.raw();
138 + if (raw.length % 2 === 1)
139 + return buffer.error('Decoding of string type: bmpstr length mismatch');
140 +
141 + let str = '';
142 + for (let i = 0; i < raw.length / 2; i++) {
143 + str += String.fromCharCode(raw.readUInt16BE(i * 2));
144 + }
145 + return str;
146 + } else if (tag === 'numstr') {
147 + const numstr = buffer.raw().toString('ascii');
148 + if (!this._isNumstr(numstr)) {
149 + return buffer.error('Decoding of string type: ' +
150 + 'numstr unsupported characters');
151 + }
152 + return numstr;
153 + } else if (tag === 'octstr') {
154 + return buffer.raw();
155 + } else if (tag === 'objDesc') {
156 + return buffer.raw();
157 + } else if (tag === 'printstr') {
158 + const printstr = buffer.raw().toString('ascii');
159 + if (!this._isPrintstr(printstr)) {
160 + return buffer.error('Decoding of string type: ' +
161 + 'printstr unsupported characters');
162 + }
163 + return printstr;
164 + } else if (/str$/.test(tag)) {
165 + return buffer.raw().toString();
166 + } else {
167 + return buffer.error('Decoding of string type: ' + tag + ' unsupported');
168 + }
169 +};
170 +
171 +DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {
172 + let result;
173 + const identifiers = [];
174 + let ident = 0;
175 + let subident = 0;
176 + while (!buffer.isEmpty()) {
177 + subident = buffer.readUInt8();
178 + ident <<= 7;
179 + ident |= subident & 0x7f;
180 + if ((subident & 0x80) === 0) {
181 + identifiers.push(ident);
182 + ident = 0;
183 + }
184 + }
185 + if (subident & 0x80)
186 + identifiers.push(ident);
187 +
188 + const first = (identifiers[0] / 40) | 0;
189 + const second = identifiers[0] % 40;
190 +
191 + if (relative)
192 + result = identifiers;
193 + else
194 + result = [first, second].concat(identifiers.slice(1));
195 +
196 + if (values) {
197 + let tmp = values[result.join(' ')];
198 + if (tmp === undefined)
199 + tmp = values[result.join('.')];
200 + if (tmp !== undefined)
201 + result = tmp;
202 + }
203 +
204 + return result;
205 +};
206 +
207 +DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {
208 + const str = buffer.raw().toString();
209 +
210 + let year;
211 + let mon;
212 + let day;
213 + let hour;
214 + let min;
215 + let sec;
216 + if (tag === 'gentime') {
217 + year = str.slice(0, 4) | 0;
218 + mon = str.slice(4, 6) | 0;
219 + day = str.slice(6, 8) | 0;
220 + hour = str.slice(8, 10) | 0;
221 + min = str.slice(10, 12) | 0;
222 + sec = str.slice(12, 14) | 0;
223 + } else if (tag === 'utctime') {
224 + year = str.slice(0, 2) | 0;
225 + mon = str.slice(2, 4) | 0;
226 + day = str.slice(4, 6) | 0;
227 + hour = str.slice(6, 8) | 0;
228 + min = str.slice(8, 10) | 0;
229 + sec = str.slice(10, 12) | 0;
230 + if (year < 70)
231 + year = 2000 + year;
232 + else
233 + year = 1900 + year;
234 + } else {
235 + return buffer.error('Decoding ' + tag + ' time is not supported yet');
236 + }
237 +
238 + return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
239 +};
240 +
241 +DERNode.prototype._decodeNull = function decodeNull() {
242 + return null;
243 +};
244 +
245 +DERNode.prototype._decodeBool = function decodeBool(buffer) {
246 + const res = buffer.readUInt8();
247 + if (buffer.isError(res))
248 + return res;
249 + else
250 + return res !== 0;
251 +};
252 +
253 +DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
254 + // Bigint, return as it is (assume big endian)
255 + const raw = buffer.raw();
256 + let res = new bignum(raw);
257 +
258 + if (values)
259 + res = values[res.toString(10)] || res;
260 +
261 + return res;
262 +};
263 +
264 +DERNode.prototype._use = function use(entity, obj) {
265 + if (typeof entity === 'function')
266 + entity = entity(obj);
267 + return entity._getDecoder('der').tree;
268 +};
269 +
270 +// Utility methods
271 +
272 +function derDecodeTag(buf, fail) {
273 + let tag = buf.readUInt8(fail);
274 + if (buf.isError(tag))
275 + return tag;
276 +
277 + const cls = der.tagClass[tag >> 6];
278 + const primitive = (tag & 0x20) === 0;
279 +
280 + // Multi-octet tag - load
281 + if ((tag & 0x1f) === 0x1f) {
282 + let oct = tag;
283 + tag = 0;
284 + while ((oct & 0x80) === 0x80) {
285 + oct = buf.readUInt8(fail);
286 + if (buf.isError(oct))
287 + return oct;
288 +
289 + tag <<= 7;
290 + tag |= oct & 0x7f;
291 + }
292 + } else {
293 + tag &= 0x1f;
294 + }
295 + const tagStr = der.tag[tag];
296 +
297 + return {
298 + cls: cls,
299 + primitive: primitive,
300 + tag: tag,
301 + tagStr: tagStr
302 + };
303 +}
304 +
305 +function derDecodeLen(buf, primitive, fail) {
306 + let len = buf.readUInt8(fail);
307 + if (buf.isError(len))
308 + return len;
309 +
310 + // Indefinite form
311 + if (!primitive && len === 0x80)
312 + return null;
313 +
314 + // Definite form
315 + if ((len & 0x80) === 0) {
316 + // Short form
317 + return len;
318 + }
319 +
320 + // Long form
321 + const num = len & 0x7f;
322 + if (num > 4)
323 + return buf.error('length octect is too long');
324 +
325 + len = 0;
326 + for (let i = 0; i < num; i++) {
327 + len <<= 8;
328 + const j = buf.readUInt8(fail);
329 + if (buf.isError(j))
330 + return j;
331 + len |= j;
332 + }
333 +
334 + return len;
335 +}
1 +'use strict';
2 +
3 +const decoders = exports;
4 +
5 +decoders.der = require('./der');
6 +decoders.pem = require('./pem');
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +const Buffer = require('safer-buffer').Buffer;
5 +
6 +const DERDecoder = require('./der');
7 +
8 +function PEMDecoder(entity) {
9 + DERDecoder.call(this, entity);
10 + this.enc = 'pem';
11 +}
12 +inherits(PEMDecoder, DERDecoder);
13 +module.exports = PEMDecoder;
14 +
15 +PEMDecoder.prototype.decode = function decode(data, options) {
16 + const lines = data.toString().split(/[\r\n]+/g);
17 +
18 + const label = options.label.toUpperCase();
19 +
20 + const re = /^-----(BEGIN|END) ([^-]+)-----$/;
21 + let start = -1;
22 + let end = -1;
23 + for (let i = 0; i < lines.length; i++) {
24 + const match = lines[i].match(re);
25 + if (match === null)
26 + continue;
27 +
28 + if (match[2] !== label)
29 + continue;
30 +
31 + if (start === -1) {
32 + if (match[1] !== 'BEGIN')
33 + break;
34 + start = i;
35 + } else {
36 + if (match[1] !== 'END')
37 + break;
38 + end = i;
39 + break;
40 + }
41 + }
42 + if (start === -1 || end === -1)
43 + throw new Error('PEM section not found for: ' + label);
44 +
45 + const base64 = lines.slice(start + 1, end).join('');
46 + // Remove excessive symbols
47 + base64.replace(/[^a-z0-9+/=]+/gi, '');
48 +
49 + const input = Buffer.from(base64, 'base64');
50 + return DERDecoder.prototype.decode.call(this, input, options);
51 +};
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +const Buffer = require('safer-buffer').Buffer;
5 +const Node = require('../base/node');
6 +
7 +// Import DER constants
8 +const der = require('../constants/der');
9 +
10 +function DEREncoder(entity) {
11 + this.enc = 'der';
12 + this.name = entity.name;
13 + this.entity = entity;
14 +
15 + // Construct base tree
16 + this.tree = new DERNode();
17 + this.tree._init(entity.body);
18 +}
19 +module.exports = DEREncoder;
20 +
21 +DEREncoder.prototype.encode = function encode(data, reporter) {
22 + return this.tree._encode(data, reporter).join();
23 +};
24 +
25 +// Tree methods
26 +
27 +function DERNode(parent) {
28 + Node.call(this, 'der', parent);
29 +}
30 +inherits(DERNode, Node);
31 +
32 +DERNode.prototype._encodeComposite = function encodeComposite(tag,
33 + primitive,
34 + cls,
35 + content) {
36 + const encodedTag = encodeTag(tag, primitive, cls, this.reporter);
37 +
38 + // Short form
39 + if (content.length < 0x80) {
40 + const header = Buffer.alloc(2);
41 + header[0] = encodedTag;
42 + header[1] = content.length;
43 + return this._createEncoderBuffer([ header, content ]);
44 + }
45 +
46 + // Long form
47 + // Count octets required to store length
48 + let lenOctets = 1;
49 + for (let i = content.length; i >= 0x100; i >>= 8)
50 + lenOctets++;
51 +
52 + const header = Buffer.alloc(1 + 1 + lenOctets);
53 + header[0] = encodedTag;
54 + header[1] = 0x80 | lenOctets;
55 +
56 + for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8)
57 + header[i] = j & 0xff;
58 +
59 + return this._createEncoderBuffer([ header, content ]);
60 +};
61 +
62 +DERNode.prototype._encodeStr = function encodeStr(str, tag) {
63 + if (tag === 'bitstr') {
64 + return this._createEncoderBuffer([ str.unused | 0, str.data ]);
65 + } else if (tag === 'bmpstr') {
66 + const buf = Buffer.alloc(str.length * 2);
67 + for (let i = 0; i < str.length; i++) {
68 + buf.writeUInt16BE(str.charCodeAt(i), i * 2);
69 + }
70 + return this._createEncoderBuffer(buf);
71 + } else if (tag === 'numstr') {
72 + if (!this._isNumstr(str)) {
73 + return this.reporter.error('Encoding of string type: numstr supports ' +
74 + 'only digits and space');
75 + }
76 + return this._createEncoderBuffer(str);
77 + } else if (tag === 'printstr') {
78 + if (!this._isPrintstr(str)) {
79 + return this.reporter.error('Encoding of string type: printstr supports ' +
80 + 'only latin upper and lower case letters, ' +
81 + 'digits, space, apostrophe, left and rigth ' +
82 + 'parenthesis, plus sign, comma, hyphen, ' +
83 + 'dot, slash, colon, equal sign, ' +
84 + 'question mark');
85 + }
86 + return this._createEncoderBuffer(str);
87 + } else if (/str$/.test(tag)) {
88 + return this._createEncoderBuffer(str);
89 + } else if (tag === 'objDesc') {
90 + return this._createEncoderBuffer(str);
91 + } else {
92 + return this.reporter.error('Encoding of string type: ' + tag +
93 + ' unsupported');
94 + }
95 +};
96 +
97 +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) {
98 + if (typeof id === 'string') {
99 + if (!values)
100 + return this.reporter.error('string objid given, but no values map found');
101 + if (!values.hasOwnProperty(id))
102 + return this.reporter.error('objid not found in values map');
103 + id = values[id].split(/[\s.]+/g);
104 + for (let i = 0; i < id.length; i++)
105 + id[i] |= 0;
106 + } else if (Array.isArray(id)) {
107 + id = id.slice();
108 + for (let i = 0; i < id.length; i++)
109 + id[i] |= 0;
110 + }
111 +
112 + if (!Array.isArray(id)) {
113 + return this.reporter.error('objid() should be either array or string, ' +
114 + 'got: ' + JSON.stringify(id));
115 + }
116 +
117 + if (!relative) {
118 + if (id[1] >= 40)
119 + return this.reporter.error('Second objid identifier OOB');
120 + id.splice(0, 2, id[0] * 40 + id[1]);
121 + }
122 +
123 + // Count number of octets
124 + let size = 0;
125 + for (let i = 0; i < id.length; i++) {
126 + let ident = id[i];
127 + for (size++; ident >= 0x80; ident >>= 7)
128 + size++;
129 + }
130 +
131 + const objid = Buffer.alloc(size);
132 + let offset = objid.length - 1;
133 + for (let i = id.length - 1; i >= 0; i--) {
134 + let ident = id[i];
135 + objid[offset--] = ident & 0x7f;
136 + while ((ident >>= 7) > 0)
137 + objid[offset--] = 0x80 | (ident & 0x7f);
138 + }
139 +
140 + return this._createEncoderBuffer(objid);
141 +};
142 +
143 +function two(num) {
144 + if (num < 10)
145 + return '0' + num;
146 + else
147 + return num;
148 +}
149 +
150 +DERNode.prototype._encodeTime = function encodeTime(time, tag) {
151 + let str;
152 + const date = new Date(time);
153 +
154 + if (tag === 'gentime') {
155 + str = [
156 + two(date.getUTCFullYear()),
157 + two(date.getUTCMonth() + 1),
158 + two(date.getUTCDate()),
159 + two(date.getUTCHours()),
160 + two(date.getUTCMinutes()),
161 + two(date.getUTCSeconds()),
162 + 'Z'
163 + ].join('');
164 + } else if (tag === 'utctime') {
165 + str = [
166 + two(date.getUTCFullYear() % 100),
167 + two(date.getUTCMonth() + 1),
168 + two(date.getUTCDate()),
169 + two(date.getUTCHours()),
170 + two(date.getUTCMinutes()),
171 + two(date.getUTCSeconds()),
172 + 'Z'
173 + ].join('');
174 + } else {
175 + this.reporter.error('Encoding ' + tag + ' time is not supported yet');
176 + }
177 +
178 + return this._encodeStr(str, 'octstr');
179 +};
180 +
181 +DERNode.prototype._encodeNull = function encodeNull() {
182 + return this._createEncoderBuffer('');
183 +};
184 +
185 +DERNode.prototype._encodeInt = function encodeInt(num, values) {
186 + if (typeof num === 'string') {
187 + if (!values)
188 + return this.reporter.error('String int or enum given, but no values map');
189 + if (!values.hasOwnProperty(num)) {
190 + return this.reporter.error('Values map doesn\'t contain: ' +
191 + JSON.stringify(num));
192 + }
193 + num = values[num];
194 + }
195 +
196 + // Bignum, assume big endian
197 + if (typeof num !== 'number' && !Buffer.isBuffer(num)) {
198 + const numArray = num.toArray();
199 + if (!num.sign && numArray[0] & 0x80) {
200 + numArray.unshift(0);
201 + }
202 + num = Buffer.from(numArray);
203 + }
204 +
205 + if (Buffer.isBuffer(num)) {
206 + let size = num.length;
207 + if (num.length === 0)
208 + size++;
209 +
210 + const out = Buffer.alloc(size);
211 + num.copy(out);
212 + if (num.length === 0)
213 + out[0] = 0;
214 + return this._createEncoderBuffer(out);
215 + }
216 +
217 + if (num < 0x80)
218 + return this._createEncoderBuffer(num);
219 +
220 + if (num < 0x100)
221 + return this._createEncoderBuffer([0, num]);
222 +
223 + let size = 1;
224 + for (let i = num; i >= 0x100; i >>= 8)
225 + size++;
226 +
227 + const out = new Array(size);
228 + for (let i = out.length - 1; i >= 0; i--) {
229 + out[i] = num & 0xff;
230 + num >>= 8;
231 + }
232 + if(out[0] & 0x80) {
233 + out.unshift(0);
234 + }
235 +
236 + return this._createEncoderBuffer(Buffer.from(out));
237 +};
238 +
239 +DERNode.prototype._encodeBool = function encodeBool(value) {
240 + return this._createEncoderBuffer(value ? 0xff : 0);
241 +};
242 +
243 +DERNode.prototype._use = function use(entity, obj) {
244 + if (typeof entity === 'function')
245 + entity = entity(obj);
246 + return entity._getEncoder('der').tree;
247 +};
248 +
249 +DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) {
250 + const state = this._baseState;
251 + let i;
252 + if (state['default'] === null)
253 + return false;
254 +
255 + const data = dataBuffer.join();
256 + if (state.defaultBuffer === undefined)
257 + state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join();
258 +
259 + if (data.length !== state.defaultBuffer.length)
260 + return false;
261 +
262 + for (i=0; i < data.length; i++)
263 + if (data[i] !== state.defaultBuffer[i])
264 + return false;
265 +
266 + return true;
267 +};
268 +
269 +// Utility methods
270 +
271 +function encodeTag(tag, primitive, cls, reporter) {
272 + let res;
273 +
274 + if (tag === 'seqof')
275 + tag = 'seq';
276 + else if (tag === 'setof')
277 + tag = 'set';
278 +
279 + if (der.tagByName.hasOwnProperty(tag))
280 + res = der.tagByName[tag];
281 + else if (typeof tag === 'number' && (tag | 0) === tag)
282 + res = tag;
283 + else
284 + return reporter.error('Unknown tag: ' + tag);
285 +
286 + if (res >= 0x1f)
287 + return reporter.error('Multi-octet tag encoding unsupported');
288 +
289 + if (!primitive)
290 + res |= 0x20;
291 +
292 + res |= (der.tagClassByName[cls || 'universal'] << 6);
293 +
294 + return res;
295 +}
1 +'use strict';
2 +
3 +const encoders = exports;
4 +
5 +encoders.der = require('./der');
6 +encoders.pem = require('./pem');
1 +'use strict';
2 +
3 +const inherits = require('inherits');
4 +
5 +const DEREncoder = require('./der');
6 +
7 +function PEMEncoder(entity) {
8 + DEREncoder.call(this, entity);
9 + this.enc = 'pem';
10 +}
11 +inherits(PEMEncoder, DEREncoder);
12 +module.exports = PEMEncoder;
13 +
14 +PEMEncoder.prototype.encode = function encode(data, options) {
15 + const buf = DEREncoder.prototype.encode.call(this, data);
16 +
17 + const p = buf.toString('base64');
18 + const out = [ '-----BEGIN ' + options.label + '-----' ];
19 + for (let i = 0; i < p.length; i += 64)
20 + out.push(p.slice(i, i + 64));
21 + out.push('-----END ' + options.label + '-----');
22 + return out.join('\n');
23 +};
1 +{
2 + "name": "asn1.js",
3 + "version": "5.4.1",
4 + "description": "ASN.1 encoder and decoder",
5 + "main": "lib/asn1.js",
6 + "scripts": {
7 + "lint-2560": "eslint --fix rfc/2560/*.js rfc/2560/test/*.js",
8 + "lint-5280": "eslint --fix rfc/5280/*.js rfc/5280/test/*.js",
9 + "lint": "eslint --fix lib/*.js lib/**/*.js lib/**/**/*.js && npm run lint-2560 && npm run lint-5280",
10 + "test": "mocha --reporter spec test/*-test.js && cd rfc/2560 && npm i && npm test && cd ../../rfc/5280 && npm i && npm test && cd ../../ && npm run lint"
11 + },
12 + "repository": {
13 + "type": "git",
14 + "url": "git@github.com:indutny/asn1.js"
15 + },
16 + "keywords": [
17 + "asn.1",
18 + "der"
19 + ],
20 + "author": "Fedor Indutny",
21 + "license": "MIT",
22 + "bugs": {
23 + "url": "https://github.com/indutny/asn1.js/issues"
24 + },
25 + "homepage": "https://github.com/indutny/asn1.js",
26 + "devDependencies": {
27 + "eslint": "^4.10.0",
28 + "mocha": "^7.0.0"
29 + },
30 + "dependencies": {
31 + "bn.js": "^4.0.0",
32 + "inherits": "^2.0.1",
33 + "minimalistic-assert": "^1.0.0",
34 + "safer-buffer": "^2.1.0"
35 + }
36 +}
1 +{
2 + "predef": [
3 + "document",
4 + "module",
5 + "require",
6 + "__dirname",
7 + "process",
8 + "console",
9 + "it",
10 + "xit",
11 + "describe",
12 + "xdescribe",
13 + "before",
14 + "beforeEach",
15 + "after",
16 + "afterEach"
17 + ],
18 + "node": true,
19 + "es5": true,
20 + "bitwise": true,
21 + "curly": true,
22 + "eqeqeq": true,
23 + "forin": false,
24 + "immed": true,
25 + "latedef": true,
26 + "newcap": true,
27 + "noarg": true,
28 + "noempty": true,
29 + "nonew": true,
30 + "plusplus": false,
31 + "undef": true,
32 + "strict": false,
33 + "trailing": false,
34 + "globalstrict": true,
35 + "nonstandard": true,
36 + "white": true,
37 + "indent": 2,
38 + "expr": true,
39 + "multistr": true,
40 + "onevar": false,
41 + "unused": "vars",
42 + "swindent": false
43 +}
1 +lib-cov
2 +*.seed
3 +*.log
4 +*.csv
5 +*.dat
6 +*.out
7 +*.pid
8 +*.gz
9 +
10 +pids
11 +logs
12 +results
13 +
14 +node_modules
15 +npm-debug.log
16 +coverage.html
1 +language: node_js
2 +node_js:
3 + - "0.8"
4 + - "0.10"
1 +Copyright (c) 2012 Jackson Tian
2 +http://weibo.com/shyvo
3 +
4 +The MIT License
5 +
6 +Permission is hereby granted, free of charge, to any person obtaining
7 +a copy of this software and associated documentation files (the
8 +"Software"), to deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify, merge, publish,
10 +distribute, sublicense, and/or sell copies of the Software, and to
11 +permit persons to whom the Software is furnished to do so, subject to
12 +the following conditions:
13 +
14 +The above copyright notice and this permission notice shall be
15 +included in all copies or substantial portions of the Software.
16 +
17 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +TESTS = test/*.test.js
2 +REPORTER = spec
3 +TIMEOUT = 2000
4 +JSCOVERAGE = ./node_modules/.bin/jscover
5 +
6 +test:
7 + @NODE_ENV=test ./node_modules/mocha/bin/mocha \
8 + --reporter $(REPORTER) \
9 + --timeout $(TIMEOUT) \
10 + $(MOCHA_OPTS) \
11 + $(TESTS)
12 +
13 +test-cov:
14 + @$(MAKE) test REPORTER=dot
15 + @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=html-cov > coverage.html
16 + @$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=travis-cov
17 +
18 +test-all: test test-cov
19 +
20 +clean:
21 + @rm -rf node_modules
22 +
23 +.PHONY: test test-cov test-all clean
1 +Bagpipe [中文](https://github.com/JacksonTian/bagpipe/blob/master/README_CN.md)
2 +=======
3 +You are the bagpiper.
4 +
5 +## Introduction
6 +It is convenient for us to use asynchronism or concurrent to promote our business speed in Node. While, if the amount of concurrent is too large, our server may not support, such that we need to limit the amount of concurrent. Though, the http module contains [http.Agent](http://nodejs.org/docs/latest/api/http.html#http_class_http_agent) to control the amount of sockets, usually, our asynchronous API has packaged in advance. It is not realistic to change the inner API agent, let’s realize it on our own logical layer.
7 +
8 +## Installation
9 +```
10 +npm install bagpipe
11 +```
12 +
13 +## API
14 +The APIs exposed by Bagpipe only include constructor and instance methods `push`.
15 +
16 +Under original status, we may execute concurrent like this, forming 100 concurrent asynchronous invokes.
17 +
18 +```
19 +for (var i = 0; i < 100; i++) {
20 +  async(function () {
21 +    // Asynchronous call
22 +  });
23 +}
24 +```
25 +If need to limit concurrency, what is your solution?
26 +Solution from Bagpipe as follows:
27 +
28 +```
29 +var Bagpipe = require('bagpipe');
30 +// Sets the max concurrency as 100
31 +var bagpipe = new Bagpipe(10);
32 +for (var i = 0; i < 100; i++) {
33 + bagpipe.push(async, function () {
34 + // execute asynchronous callback
35 + });
36 +}
37 +```
38 +
39 +Yes, invoke method only splits method、parameter and callback, then delivery it to bagpipe through `push`.
40 +
41 +How does it like compared with your anticipated solution?
42 +
43 +### Options
44 +
45 +- `refuse`, when queue is fulled, bagpipe will refuse the new async call and execute the callback with a `TooMuchAsyncCallError` exception. default `false`.
46 +- `timeout`, setting global ansyn call timeout. If async call doesn't complete in time, will execute the callback with `BagpipeTimeoutError` exception. default `null`.
47 +
48 +## Principles
49 +Bagpipe delivers invoke into inner queue through `push`. If active invoke amount is less than max concurrent, it will be popped and executed directly, or it will stay in the queue. When an asynchronous invoke ends, a invoke in the head of the queue will be popped and executed, such that assures active asynchronous invoke amount no larger than restricted value.
50 +
51 +When the queue length is larger than 1, Bagpipe object will fire its `full` event, which delivers the queue length value. The value helps to assess business performance. For example:
52 +
53 +```
54 +bagpipe.on('full', function (length) {
55 + console.warn('Button system cannot deal on time, queue jam, current queue length is:’+ length);
56 +});
57 +```
58 +
59 +If queue length more than limit, you can set the `refuse` option to decide continue in queue or refuse call. The `refuse` default `false`. If set as `true`, the `TooMuchAsyncCallError` exception will pass to callback directly:
60 +
61 +```
62 +var bagpipe = new BagPipe(10, {
63 + refuse: true
64 +});
65 +```
66 +
67 +If complete the async call is unexpected, the queue will not balanced. Set the timeout, let the callback executed with the `BagpipeTimeoutError` exception:
68 +
69 +```
70 +var bagpipe = new BagPipe(10, {
71 + timeout: 1000
72 +});
73 +```
74 +
75 +## Module status
76 +The unit testing status: [![Build Status](https://secure.travis-ci.org/JacksonTian/bagpipe.png)](http://travis-ci.org/JacksonTian/bagpipe). Unit test coverage [100%](http://html5ify.com/bagpipe/coverage.html).
77 +
78 +## Best Practices
79 +- Ensure that the last parameter of the asynchronous invoke is callback.
80 +- Listen to the `full` event, adding your business performance assessment.
81 +- Current asynchronous method has not supported context yet. Ensure that there is no `this` reference in asynchronous method. If there is `this` reference in asynchronous method, please use `bind` pass into correct context.
82 +- Asynchronous invoke should process method to deal with timeout, it should ensure the invoke will return in a certain time no matter whether the business has been finished or not.
83 +
84 +## Real case
85 +When you want to traverse file directories, asynchrony can ensure `full` use of IO. You can invoke thousands of file reading easily. But, system file descriptors are limited. If disobedient, read this article again when occurring errors as follows.
86 +
87 +```
88 +Error: EMFILE, too many open files
89 +```
90 +
91 +Someone may consider dealing it with synchronous method. But, when synchronous, CPU and IO cannot be used concurrently, performance is an indefeasible index under certain condition. You can enjoy concurrent easily, as well as limit concurrent with Bagpipe.
92 +
93 +```
94 +var bagpipe = new Bagpipe(10);
95 +
96 +var files = ['Here are many files'];
97 +for (var i = 0; i < files.length; i++) {
98 + // fs.readFile(files[i], 'utf-8', function (err, data) {
99 + bagpipe.push(fs.readFile, files[i], 'utf-8', function (err, data) {
100 + // won’t occur error because of too many file descriptors
101 + // well done
102 + });
103 +}
104 +```
105 +
106 +## License
107 +Released under the license of [MIT](https://github.com/JacksonTian/bagpipe/blob/master/MIT-License), welcome to enjoy open source.
1 +Bagpipe(风笛) [English](https://github.com/JacksonTian/bagpipe/blob/master/README.md)
2 +=======
3 +You are the bagpiper.
4 +
5 +## 起源
6 +在Node中我们可以十分方便利用异步和并行来提升我们的业务速度。但是,如果并发量过大,我们的服务器却可能吃不消,我们需要限制并发量。尽管`http`模块自身有[http.Agent](http://nodejs.org/docs/latest/api/http.html#http_class_http_agent)这样的玩意,用于控制socket的数量,但是通常我们的异步API早就封装好了。改动API的内部agent是不现实的,那么我们自己在逻辑层实现吧。
7 +
8 +## 安装
9 +```
10 +npm install bagpipe
11 +```
12 +
13 +## API
14 +`Bagpipe`暴露的API只有构造器和实例方法`push`
15 +
16 +在原始状态下,我们执行并发可能是如下这样的,这会形成100个并发异步调用。
17 +
18 +```
19 +for (var i = 0; i < 100; i++) {
20 + async(function () {
21 + // 异步调用
22 + });
23 +}
24 +```
25 +如果需要限制并发,你的方案会是怎样?
26 +
27 +`Bagpipe`的方案是如下这样的:
28 +
29 +```
30 +var Bagpipe = require('bagpipe');
31 +// 设定最大并发数为10
32 +var bagpipe = new Bagpipe(10);
33 +for (var i = 0; i < 100; i++) {
34 + bagpipe.push(async, function () {
35 + // 异步回调执行
36 + });
37 +}
38 +```
39 +
40 +是的,调用方式仅仅是将方法、参数、回调分拆一下通过`push`交给`bagpipe`即可。
41 +
42 +这个方案与你预想的方案相比,如何?
43 +
44 +### 选项
45 +
46 +- `refuse`,当队列填满时,拒绝新到来的异步调用。执行异步调用的回调函数,传递一个`TooMuchAsyncCallError`异常。默认为`false`
47 +- `timeout`,设置全局异步调用超时时间,经过`push`后执行的异步调用,如果在超时时间内没有返回执行,将会执行异步调用的回调函数,传递一个`BagpipeTimeoutError`异常。默认为`null`不开启。
48 +
49 +## 原理
50 +`Bagpipe`通过`push`将调用传入内部队列。如果活跃调用小于最大并发数,将会被取出直接执行,反之则继续呆在队列中。当一个异步调用结束的时候,会从队列前取出调用执行。以此来保证异步调用的活跃量不高于限定值。
51 +当队列的长度大于1时,Bagpipe对象将会触发它的`full`事件,该事件传递队列长度值。该值有助于评估业务性能参数。示例如下:
52 +
53 +```
54 +bagpipe.on('full', function (length) {
55 + console.warn('底层系统处理不能及时完成,排队中,目前队列长度为:' + length);
56 +});
57 +```
58 +
59 +如果队列的长度也超过限制值,这里可以通过`refuse`选项控制,是直接传递异常拒绝服务还是继续排队。默认情况`refuse``false`。如果设置为`true`,新的异步调用将会得到`TooMuchAsyncCallError`异常,而被拒绝服务。
60 +
61 +```
62 +var bagpipe = new BagPipe(10, {
63 + refuse: true
64 +});
65 +```
66 +
67 +如果异步调用的超时不可预期,可能存在等待队列不均衡的情况,为此可以全局设置一个超时时间,对于过长的响应时间,提前返回超时状态。
68 +
69 +```
70 +var bagpipe = new BagPipe(10, {
71 + timeout: 1000
72 +});
73 +```
74 +
75 +## 模块状态
76 +单元测试通过状态:[![Build Status](https://secure.travis-ci.org/JacksonTian/bagpipe.png)](http://travis-ci.org/JacksonTian/bagpipe)。单元测试覆盖率[100%](http://html5ify.com/bagpipe/coverage.html)
77 +
78 +## 最佳实践
79 +- 确保异步调用的最后一个参数为回调参数
80 +- 监听`full`事件,以增加你对业务性能的评估
81 +- 目前异步方法未支持上下文。确保异步方法内部没有`this`引用。如果存在`this`引用,请用`bind`方法传递正确的`this`上下文
82 +- 异步调用应当具备timeout的业务处理,无论业务是否完成,总在一定的时间内保证返回
83 +
84 +## 实际案例
85 +当你需要遍历文件目录的时候,异步可以确保充分利用IO。你可以轻松发起成千上万个文件的读取。但是,系统文件描述符是有限的。不服的话,遇见下面这个错误再来重读此文。
86 +
87 +```
88 +Error: EMFILE, too many open files
89 +```
90 +也有人会考虑用同步方法来进行处理。但是,同步时,CPU与IO并不能并行利用,一定情况下,性能是不可弃的一项指标。用上`Bagpipe`,可以轻松享受并发,也能限制并发。
91 +
92 +```
93 +var bagpipe = new Bagpipe(10);
94 +
95 +var files = ['这里有很多很多文件'];
96 +for (var i = 0; i < files.length; i++) {
97 + // fs.readFile(files[i], 'utf-8', function (err, data) {
98 + bagpipe.push(fs.readFile, files[i], 'utf-8', function (err, data) {
99 + // 不会因为文件描述符过多出错
100 + // 妥妥的
101 + });
102 +}
103 +```
104 +
105 +## License
106 +[MIT](https://github.com/JacksonTian/bagpipe/blob/master/MIT-License)许可证下发布,欢迎享受开源
107 +
1 +module.exports = require('./lib/bagpipe');
1 +var util = require("util");
2 +var events = require("events");
3 +
4 +/**
5 + * 构造器,传入限流值,设置异步调用最大并发数
6 + * Examples:
7 + * ```
8 + * var bagpipe = new Bagpipe(100);
9 + * bagpipe.push(fs.readFile, 'path', 'utf-8', function (err, data) {
10 + * // TODO
11 + * });
12 + * ```
13 + * Events:
14 + * - `full`, 当活动异步达到限制值时,后续异步调用将被暂存于队列中。当队列的长度大于限制值的2倍或100的时候时候,触发`full`事件。事件传递队列长度值。
15 + * - `outdated`, 超时后的异步调用异常返回。
16 + * Options:
17 + * - `disabled`, 禁用限流,测试时用
18 + * - `refuse`, 拒绝模式,排队超过限制值时,新来的调用将会得到`TooMuchAsyncCallError`异常
19 + * - `timeout`, 设置异步调用的时间上线,保证异步调用能够恒定的结束,不至于花费太长时间
20 + * @param {Number} limit 并发数限制值
21 + * @param {Object} options Options
22 + */
23 +var Bagpipe = function (limit, options) {
24 + events.EventEmitter.call(this);
25 + this.limit = limit;
26 + this.active = 0;
27 + this.queue = [];
28 + this.options = {
29 + disabled: false,
30 + refuse: false,
31 + ratio: 1,
32 + timeout: null
33 + };
34 + if (typeof options === 'boolean') {
35 + options = {
36 + disabled: options
37 + };
38 + }
39 + options = options || {};
40 + for (var key in this.options) {
41 + if (options.hasOwnProperty(key)) {
42 + this.options[key] = options[key];
43 + }
44 + }
45 + // queue length
46 + this.queueLength = Math.round(this.limit * (this.options.ratio || 1));
47 +};
48 +util.inherits(Bagpipe, events.EventEmitter);
49 +
50 +/**
51 + * 推入方法,参数。最后一个参数为回调函数
52 + * @param {Function} method 异步方法
53 + * @param {Mix} args 参数列表,最后一个参数为回调函数。
54 + */
55 +Bagpipe.prototype.push = function (method) {
56 + var args = [].slice.call(arguments, 1);
57 + var callback = args[args.length - 1];
58 + if (typeof callback !== 'function') {
59 + args.push(function () {});
60 + }
61 + if (this.options.disabled || this.limit < 1) {
62 + method.apply(null, args);
63 + return this;
64 + }
65 +
66 + // 队列长度也超过限制值时
67 + if (this.queue.length < this.queueLength || !this.options.refuse) {
68 + this.queue.push({
69 + method: method,
70 + args: args
71 + });
72 + } else {
73 + var err = new Error('Too much async call in queue');
74 + err.name = 'TooMuchAsyncCallError';
75 + callback(err);
76 + }
77 +
78 + if (this.queue.length > 1) {
79 + this.emit('full', this.queue.length);
80 + }
81 +
82 + this.next();
83 + return this;
84 +};
85 +
86 +/*!
87 + * 继续执行队列中的后续动作
88 + */
89 +Bagpipe.prototype.next = function () {
90 + var that = this;
91 + if (that.active < that.limit && that.queue.length) {
92 + var req = that.queue.shift();
93 + that.run(req.method, req.args);
94 + }
95 +};
96 +
97 +Bagpipe.prototype._next = function () {
98 + this.active--;
99 + this.next();
100 +};
101 +
102 +/*!
103 + * 执行队列中的方法
104 + */
105 +Bagpipe.prototype.run = function (method, args) {
106 + var that = this;
107 + that.active++;
108 + var callback = args[args.length - 1];
109 + var timer = null;
110 + var called = false;
111 +
112 + // inject logic
113 + args[args.length - 1] = function (err) {
114 + // anyway, clear the timer
115 + if (timer) {
116 + clearTimeout(timer);
117 + timer = null;
118 + }
119 + // if timeout, don't execute
120 + if (!called) {
121 + that._next();
122 + callback.apply(null, arguments);
123 + } else {
124 + // pass the outdated error
125 + if (err) {
126 + that.emit('outdated', err);
127 + }
128 + }
129 + };
130 +
131 + var timeout = that.options.timeout;
132 + if (timeout) {
133 + timer = setTimeout(function () {
134 + // set called as true
135 + called = true;
136 + that._next();
137 + // pass the exception
138 + var err = new Error(timeout + 'ms timeout');
139 + err.name = 'BagpipeTimeoutError';
140 + err.data = {
141 + name: method.name,
142 + method: method.toString(),
143 + args: args.slice(0, -1)
144 + };
145 + callback(err);
146 + }, timeout);
147 + }
148 + method.apply(null, args);
149 +};
150 +
151 +module.exports = Bagpipe;
1 +{
2 + "name": "bagpipe",
3 + "version": "0.3.5",
4 + "description": "Concurrency limit",
5 + "keywords": [
6 + "limiter",
7 + "concurrency limit",
8 + "parallel limit"
9 + ],
10 + "main": "index.js",
11 + "scripts": {
12 + "test": "make test-all",
13 + "blanket": {
14 + "pattern": "bagpipe/lib"
15 + },
16 + "travis-cov": {
17 + "threshold": 99
18 + }
19 + },
20 + "author": "Jackson Tian",
21 + "license": "MIT",
22 + "readmeFilename": "README.md",
23 + "gitHead": "75269c60fdbb897be14575e70a2b86cf43999500",
24 + "directories": {
25 + "doc": "doc",
26 + "test": "test"
27 + },
28 + "devDependencies": {
29 + "pedding": "*",
30 + "should": "*",
31 + "blanket": "*",
32 + "mocha": "*",
33 + "travis-cov": "*"
34 + },
35 + "repository": {
36 + "type": "git",
37 + "url": "git://github.com/JacksonTian/bagpipe.git"
38 + },
39 + "bugs": {
40 + "url": "https://github.com/JacksonTian/bagpipe/issues"
41 + }
42 +}
1 +var should = require('should');
2 +var pedding = require('pedding');
3 +var Bagpipe = require('../');
4 +
5 +describe('bagpipe', function () {
6 + var async = function (ms, callback) {
7 + setTimeout(function () {
8 + callback(null, {});
9 + }, ms);
10 + };
11 +
12 + it('constructor', function () {
13 + var bagpipe = new Bagpipe(10);
14 + bagpipe.limit.should.be.equal(10);
15 + bagpipe.queue.should.have.length(0);
16 + bagpipe.active.should.be.equal(0);
17 + bagpipe.options.disabled.should.be.equal(false);
18 + });
19 +
20 + it('constructor disabled', function () {
21 + var bagpipe = new Bagpipe(10, true);
22 + bagpipe.limit.should.be.equal(10);
23 + bagpipe.queue.should.have.length(0);
24 + bagpipe.active.should.be.equal(0);
25 + bagpipe.options.disabled.should.be.equal(true);
26 + });
27 +
28 + it('constructor limit less than 1', function (done) {
29 + var bagpipe = new Bagpipe(0);
30 + bagpipe.push(async, 10, function () {
31 + bagpipe.active.should.be.equal(0);
32 + done();
33 + });
34 + bagpipe.active.should.be.equal(0);
35 + });
36 +
37 + it('constructor limit less than 1 for nextTick', function (done) {
38 + var bagpipe = new Bagpipe(0);
39 + bagpipe.push(process.nextTick, function () {
40 + bagpipe.active.should.be.equal(0);
41 + done();
42 + });
43 + bagpipe.active.should.be.equal(0);
44 + });
45 +
46 + it('constructor disabled is true', function (done) {
47 + var bagpipe = new Bagpipe(10, true);
48 + bagpipe.push(async, 10, function () {
49 + bagpipe.active.should.be.equal(0);
50 + done();
51 + });
52 + bagpipe.active.should.be.equal(0);
53 + });
54 +
55 + it('push', function (done) {
56 + var bagpipe = new Bagpipe(5);
57 + bagpipe.limit.should.be.equal(5);
58 + bagpipe.queue.should.have.length(0);
59 + bagpipe.active.should.be.equal(0);
60 + bagpipe.push(async, 10, function () {
61 + bagpipe.active.should.be.equal(0);
62 + done();
63 + });
64 + bagpipe.active.should.be.equal(1);
65 + });
66 +
67 + it('push, async with this', function (done) {
68 + var bagpipe = new Bagpipe(5);
69 + bagpipe.limit.should.be.equal(5);
70 + bagpipe.queue.should.have.length(0);
71 + bagpipe.active.should.be.equal(0);
72 + var context = {value: 10};
73 + context.async = function (callback) {
74 + this.value--;
75 + var that = this;
76 + process.nextTick(function() {
77 + callback(that.value);
78 + });
79 + };
80 +
81 + bagpipe.push(context.async.bind(context), function () {
82 + bagpipe.active.should.be.equal(0);
83 + done();
84 + });
85 + bagpipe.active.should.be.equal(1);
86 + });
87 +
88 + it('push, active should not be above limit', function (done) {
89 + var limit = 5;
90 + var bagpipe = new Bagpipe(limit);
91 + bagpipe.limit.should.be.equal(limit);
92 + bagpipe.queue.should.have.length(0);
93 + bagpipe.active.should.be.equal(0);
94 + var counter = 10;
95 + for (var i = 0; i < counter; i++) {
96 + bagpipe.push(async, 1 + Math.round(Math.random() * 10), function () {
97 + bagpipe.active.should.not.be.above(limit);
98 + counter--;
99 + if (counter === 0) {
100 + done();
101 + }
102 + });
103 + bagpipe.active.should.not.be.above(limit);
104 + }
105 + });
106 +
107 + it('push, disabled, active should not be above limit', function (done) {
108 + var limit = 5;
109 + var bagpipe = new Bagpipe(limit, true);
110 + bagpipe.limit.should.be.equal(limit);
111 + bagpipe.queue.should.have.length(0);
112 + bagpipe.active.should.be.equal(0);
113 + var counter = 10;
114 + for (var i = 0; i < counter; i++) {
115 + bagpipe.push(async, 10 + Math.round(Math.random() * 10), function () {
116 + bagpipe.active.should.be.equal(0);
117 + counter--;
118 + if (counter === 0) {
119 + done();
120 + }
121 + });
122 + bagpipe.active.should.be.equal(0);
123 + }
124 + });
125 +
126 + it('full event should fired when above limit', function (done) {
127 + var limit = 5;
128 + var bagpipe = new Bagpipe(limit);
129 + bagpipe.limit.should.be.equal(limit);
130 + bagpipe.queue.should.have.length(0);
131 + bagpipe.active.should.be.equal(0);
132 + var counter = 0;
133 + bagpipe.on('full', function (length) {
134 + length.should.above(1);
135 + counter++;
136 + });
137 +
138 + var noop = function () {};
139 + for (var i = 0; i < 100; i++) {
140 + bagpipe.push(async, 10, noop);
141 + }
142 + counter.should.above(0);
143 + done();
144 + });
145 +
146 + it('should support without callback', function (done) {
147 + var limit = 5;
148 + var bagpipe = new Bagpipe(limit);
149 + bagpipe.limit.should.be.equal(limit);
150 + bagpipe.queue.should.have.length(0);
151 + bagpipe.active.should.be.equal(0);
152 + bagpipe.push(async, 10);
153 + bagpipe.active.should.be.equal(1);
154 + done();
155 + });
156 +
157 + it('should get TooMuchAsyncCallError', function (done) {
158 + done = pedding(5, done);
159 + var limit = 2;
160 + var bagpipe = new Bagpipe(limit, {
161 + refuse: true
162 + });
163 + bagpipe.limit.should.be.equal(limit);
164 + bagpipe.queue.should.have.length(0);
165 + bagpipe.active.should.be.equal(0);
166 + for (var i = 0; i < 4; i++) {
167 + bagpipe.push(async, 10, function (err) {
168 + should.not.exist(err);
169 + done();
170 + });
171 + }
172 + bagpipe.push(async, 10, function (err) {
173 + should.exist(err);
174 + done();
175 + });
176 + bagpipe.active.should.be.equal(2);
177 + });
178 +
179 + it('should get TooMuchAsyncCallError with ratio', function (done) {
180 + done = pedding(7, done);
181 + var limit = 2;
182 + var bagpipe = new Bagpipe(limit, {
183 + refuse: true,
184 + ratio: 2
185 + });
186 + bagpipe.limit.should.be.equal(limit);
187 + bagpipe.queue.should.have.length(0);
188 + bagpipe.active.should.be.equal(0);
189 + for (var i = 0; i < 2; i++) {
190 + bagpipe.push(async, 10, function (err) {
191 + should.not.exist(err);
192 + done();
193 + });
194 + }
195 + bagpipe.queue.should.have.length(0);
196 + for (i = 0; i < 4; i++) {
197 + bagpipe.push(async, 10, function (err) {
198 + should.not.exist(err);
199 + done();
200 + });
201 + }
202 + bagpipe.queue.should.have.length(4);
203 + bagpipe.push(async, 10, function (err) {
204 + should.exist(err);
205 + done();
206 + });
207 + bagpipe.active.should.be.equal(2);
208 + bagpipe.queue.should.have.length(4);
209 + });
210 +
211 + it('should get BagpipeTimeoutError', function (done) {
212 + done = pedding(3, done);
213 + var _async = function _async(ms, callback) {
214 + setTimeout(function () {
215 + callback(null, {ms: ms});
216 + }, ms);
217 + };
218 + var _async2 = function _async(ms, callback) {
219 + setTimeout(function () {
220 + callback(new Error('Timeout'));
221 + }, ms);
222 + };
223 + var bagpipe = new Bagpipe(10, {
224 + timeout: 10
225 + });
226 + bagpipe.on('outdated', function (err) {
227 + should.exist(err);
228 + done();
229 + });
230 +
231 + bagpipe.push(_async, 5, function (err, data) {
232 + should.not.exist(err);
233 + should.exist(data);
234 + data.should.have.property('ms', 5);
235 + done();
236 + });
237 +
238 + bagpipe.push(_async2, 15, function (err) {
239 + should.exist(err);
240 + err.name.should.eql('BagpipeTimeoutError');
241 + err.message.should.eql('10ms timeout');
242 + err.data.should.have.property('name', '_async');
243 + err.data.should.have.property('method');
244 + err.data.args.should.eql([15]);
245 + done();
246 + });
247 + });
248 +});
1 +Copyright Fedor Indutny, 2015.
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy
4 +of this software and associated documentation files (the "Software"), to deal
5 +in the Software without restriction, including without limitation the rights
6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +copies of the Software, and to permit persons to whom the Software is
8 +furnished to do so, subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in all
11 +copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 +SOFTWARE.
1 +# <img src="./logo.png" alt="bn.js" width="160" height="160" />
2 +
3 +> BigNum in pure javascript
4 +
5 +[![Build Status](https://secure.travis-ci.org/indutny/bn.js.png)](http://travis-ci.org/indutny/bn.js)
6 +
7 +## Install
8 +`npm install --save bn.js`
9 +
10 +## Usage
11 +
12 +```js
13 +const BN = require('bn.js');
14 +
15 +var a = new BN('dead', 16);
16 +var b = new BN('101010', 2);
17 +
18 +var res = a.add(b);
19 +console.log(res.toString(10)); // 57047
20 +```
21 +
22 +**Note**: decimals are not supported in this library.
23 +
24 +## Notation
25 +
26 +### Prefixes
27 +
28 +There are several prefixes to instructions that affect the way the work. Here
29 +is the list of them in the order of appearance in the function name:
30 +
31 +* `i` - perform operation in-place, storing the result in the host object (on
32 + which the method was invoked). Might be used to avoid number allocation costs
33 +* `u` - unsigned, ignore the sign of operands when performing operation, or
34 + always return positive value. Second case applies to reduction operations
35 + like `mod()`. In such cases if the result will be negative - modulo will be
36 + added to the result to make it positive
37 +
38 +### Postfixes
39 +
40 +The only available postfix at the moment is:
41 +
42 +* `n` - which means that the argument of the function must be a plain JavaScript
43 + Number. Decimals are not supported.
44 +
45 +### Examples
46 +
47 +* `a.iadd(b)` - perform addition on `a` and `b`, storing the result in `a`
48 +* `a.umod(b)` - reduce `a` modulo `b`, returning positive value
49 +* `a.iushln(13)` - shift bits of `a` left by 13
50 +
51 +## Instructions
52 +
53 +Prefixes/postfixes are put in parens at the of the line. `endian` - could be
54 +either `le` (little-endian) or `be` (big-endian).
55 +
56 +### Utilities
57 +
58 +* `a.clone()` - clone number
59 +* `a.toString(base, length)` - convert to base-string and pad with zeroes
60 +* `a.toNumber()` - convert to Javascript Number (limited to 53 bits)
61 +* `a.toJSON()` - convert to JSON compatible hex string (alias of `toString(16)`)
62 +* `a.toArray(endian, length)` - convert to byte `Array`, and optionally zero
63 + pad to length, throwing if already exceeding
64 +* `a.toArrayLike(type, endian, length)` - convert to an instance of `type`,
65 + which must behave like an `Array`
66 +* `a.toBuffer(endian, length)` - convert to Node.js Buffer (if available). For
67 + compatibility with browserify and similar tools, use this instead:
68 + `a.toArrayLike(Buffer, endian, length)`
69 +* `a.bitLength()` - get number of bits occupied
70 +* `a.zeroBits()` - return number of less-significant consequent zero bits
71 + (example: `1010000` has 4 zero bits)
72 +* `a.byteLength()` - return number of bytes occupied
73 +* `a.isNeg()` - true if the number is negative
74 +* `a.isEven()` - no comments
75 +* `a.isOdd()` - no comments
76 +* `a.isZero()` - no comments
77 +* `a.cmp(b)` - compare numbers and return `-1` (a `<` b), `0` (a `==` b), or `1` (a `>` b)
78 + depending on the comparison result (`ucmp`, `cmpn`)
79 +* `a.lt(b)` - `a` less than `b` (`n`)
80 +* `a.lte(b)` - `a` less than or equals `b` (`n`)
81 +* `a.gt(b)` - `a` greater than `b` (`n`)
82 +* `a.gte(b)` - `a` greater than or equals `b` (`n`)
83 +* `a.eq(b)` - `a` equals `b` (`n`)
84 +* `a.toTwos(width)` - convert to two's complement representation, where `width` is bit width
85 +* `a.fromTwos(width)` - convert from two's complement representation, where `width` is the bit width
86 +* `BN.isBN(object)` - returns true if the supplied `object` is a BN.js instance
87 +
88 +### Arithmetics
89 +
90 +* `a.neg()` - negate sign (`i`)
91 +* `a.abs()` - absolute value (`i`)
92 +* `a.add(b)` - addition (`i`, `n`, `in`)
93 +* `a.sub(b)` - subtraction (`i`, `n`, `in`)
94 +* `a.mul(b)` - multiply (`i`, `n`, `in`)
95 +* `a.sqr()` - square (`i`)
96 +* `a.pow(b)` - raise `a` to the power of `b`
97 +* `a.div(b)` - divide (`divn`, `idivn`)
98 +* `a.mod(b)` - reduct (`u`, `n`) (but no `umodn`)
99 +* `a.divRound(b)` - rounded division
100 +
101 +### Bit operations
102 +
103 +* `a.or(b)` - or (`i`, `u`, `iu`)
104 +* `a.and(b)` - and (`i`, `u`, `iu`, `andln`) (NOTE: `andln` is going to be replaced
105 + with `andn` in future)
106 +* `a.xor(b)` - xor (`i`, `u`, `iu`)
107 +* `a.setn(b)` - set specified bit to `1`
108 +* `a.shln(b)` - shift left (`i`, `u`, `iu`)
109 +* `a.shrn(b)` - shift right (`i`, `u`, `iu`)
110 +* `a.testn(b)` - test if specified bit is set
111 +* `a.maskn(b)` - clear bits with indexes higher or equal to `b` (`i`)
112 +* `a.bincn(b)` - add `1 << b` to the number
113 +* `a.notn(w)` - not (for the width specified by `w`) (`i`)
114 +
115 +### Reduction
116 +
117 +* `a.gcd(b)` - GCD
118 +* `a.egcd(b)` - Extended GCD results (`{ a: ..., b: ..., gcd: ... }`)
119 +* `a.invm(b)` - inverse `a` modulo `b`
120 +
121 +## Fast reduction
122 +
123 +When doing lots of reductions using the same modulo, it might be beneficial to
124 +use some tricks: like [Montgomery multiplication][0], or using special algorithm
125 +for [Mersenne Prime][1].
126 +
127 +### Reduction context
128 +
129 +To enable this tricks one should create a reduction context:
130 +
131 +```js
132 +var red = BN.red(num);
133 +```
134 +where `num` is just a BN instance.
135 +
136 +Or:
137 +
138 +```js
139 +var red = BN.red(primeName);
140 +```
141 +
142 +Where `primeName` is either of these [Mersenne Primes][1]:
143 +
144 +* `'k256'`
145 +* `'p224'`
146 +* `'p192'`
147 +* `'p25519'`
148 +
149 +Or:
150 +
151 +```js
152 +var red = BN.mont(num);
153 +```
154 +
155 +To reduce numbers with [Montgomery trick][0]. `.mont()` is generally faster than
156 +`.red(num)`, but slower than `BN.red(primeName)`.
157 +
158 +### Converting numbers
159 +
160 +Before performing anything in reduction context - numbers should be converted
161 +to it. Usually, this means that one should:
162 +
163 +* Convert inputs to reducted ones
164 +* Operate on them in reduction context
165 +* Convert outputs back from the reduction context
166 +
167 +Here is how one may convert numbers to `red`:
168 +
169 +```js
170 +var redA = a.toRed(red);
171 +```
172 +Where `red` is a reduction context created using instructions above
173 +
174 +Here is how to convert them back:
175 +
176 +```js
177 +var a = redA.fromRed();
178 +```
179 +
180 +### Red instructions
181 +
182 +Most of the instructions from the very start of this readme have their
183 +counterparts in red context:
184 +
185 +* `a.redAdd(b)`, `a.redIAdd(b)`
186 +* `a.redSub(b)`, `a.redISub(b)`
187 +* `a.redShl(num)`
188 +* `a.redMul(b)`, `a.redIMul(b)`
189 +* `a.redSqr()`, `a.redISqr()`
190 +* `a.redSqrt()` - square root modulo reduction context's prime
191 +* `a.redInvm()` - modular inverse of the number
192 +* `a.redNeg()`
193 +* `a.redPow(b)` - modular exponentiation
194 +
195 +## LICENSE
196 +
197 +This software is licensed under the MIT License.
198 +
199 +[0]: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
200 +[1]: https://en.wikipedia.org/wiki/Mersenne_prime
This diff is collapsed. Click to expand it.
1 +{
2 + "name": "bn.js",
3 + "version": "4.12.0",
4 + "description": "Big number implementation in pure javascript",
5 + "main": "lib/bn.js",
6 + "scripts": {
7 + "lint": "semistandard",
8 + "unit": "mocha --reporter=spec test/*-test.js",
9 + "test": "npm run lint && npm run unit"
10 + },
11 + "repository": {
12 + "type": "git",
13 + "url": "git@github.com:indutny/bn.js"
14 + },
15 + "keywords": [
16 + "BN",
17 + "BigNum",
18 + "Big number",
19 + "Modulo",
20 + "Montgomery"
21 + ],
22 + "author": "Fedor Indutny <fedor@indutny.com>",
23 + "license": "MIT",
24 + "bugs": {
25 + "url": "https://github.com/indutny/bn.js/issues"
26 + },
27 + "homepage": "https://github.com/indutny/bn.js",
28 + "browser": {
29 + "buffer": false
30 + },
31 + "devDependencies": {
32 + "istanbul": "^0.3.5",
33 + "mocha": "^2.1.0",
34 + "semistandard": "^7.0.4"
35 + }
36 +}
This diff is collapsed. Click to expand it.
1 +(The MIT License)
2 +
3 +Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
4 +Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
5 +
6 +Permission is hereby granted, free of charge, to any person obtaining
7 +a copy of this software and associated documentation files (the
8 +'Software'), to deal in the Software without restriction, including
9 +without limitation the rights to use, copy, modify, merge, publish,
10 +distribute, sublicense, and/or sell copies of the Software, and to
11 +permit persons to whom the Software is furnished to do so, subject to
12 +the following conditions:
13 +
14 +The above copyright notice and this permission notice shall be
15 +included in all copies or substantial portions of the Software.
16 +
17 +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This diff is collapsed. Click to expand it.
1 +# Security Policies and Procedures
2 +
3 +## Reporting a Bug
4 +
5 +The Express team and community take all security bugs seriously. Thank you
6 +for improving the security of Express. We appreciate your efforts and
7 +responsible disclosure and will make every effort to acknowledge your
8 +contributions.
9 +
10 +Report security bugs by emailing the current owner(s) of `body-parser`. This
11 +information can be found in the npm registry using the command
12 +`npm owner ls body-parser`.
13 +If unsure or unable to get the information from the above, open an issue
14 +in the [project issue tracker](https://github.com/expressjs/body-parser/issues)
15 +asking for the current contact information.
16 +
17 +To ensure the timely response to your report, please ensure that the entirety
18 +of the report is contained within the email body and not solely behind a web
19 +link or an attachment.
20 +
21 +At least one owner will acknowledge your email within 48 hours, and will send a
22 +more detailed response within 48 hours indicating the next steps in handling
23 +your report. After the initial reply to your report, the owners will
24 +endeavor to keep you informed of the progress towards a fix and full
25 +announcement, and may ask for additional information or guidance.
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
4 + * MIT Licensed
5 + */
6 +
7 +'use strict'
8 +
9 +/**
10 + * Module dependencies.
11 + * @private
12 + */
13 +
14 +var deprecate = require('depd')('body-parser')
15 +
16 +/**
17 + * Cache of loaded parsers.
18 + * @private
19 + */
20 +
21 +var parsers = Object.create(null)
22 +
23 +/**
24 + * @typedef Parsers
25 + * @type {function}
26 + * @property {function} json
27 + * @property {function} raw
28 + * @property {function} text
29 + * @property {function} urlencoded
30 + */
31 +
32 +/**
33 + * Module exports.
34 + * @type {Parsers}
35 + */
36 +
37 +exports = module.exports = deprecate.function(bodyParser,
38 + 'bodyParser: use individual json/urlencoded middlewares')
39 +
40 +/**
41 + * JSON parser.
42 + * @public
43 + */
44 +
45 +Object.defineProperty(exports, 'json', {
46 + configurable: true,
47 + enumerable: true,
48 + get: createParserGetter('json')
49 +})
50 +
51 +/**
52 + * Raw parser.
53 + * @public
54 + */
55 +
56 +Object.defineProperty(exports, 'raw', {
57 + configurable: true,
58 + enumerable: true,
59 + get: createParserGetter('raw')
60 +})
61 +
62 +/**
63 + * Text parser.
64 + * @public
65 + */
66 +
67 +Object.defineProperty(exports, 'text', {
68 + configurable: true,
69 + enumerable: true,
70 + get: createParserGetter('text')
71 +})
72 +
73 +/**
74 + * URL-encoded parser.
75 + * @public
76 + */
77 +
78 +Object.defineProperty(exports, 'urlencoded', {
79 + configurable: true,
80 + enumerable: true,
81 + get: createParserGetter('urlencoded')
82 +})
83 +
84 +/**
85 + * Create a middleware to parse json and urlencoded bodies.
86 + *
87 + * @param {object} [options]
88 + * @return {function}
89 + * @deprecated
90 + * @public
91 + */
92 +
93 +function bodyParser (options) {
94 + var opts = {}
95 +
96 + // exclude type option
97 + if (options) {
98 + for (var prop in options) {
99 + if (prop !== 'type') {
100 + opts[prop] = options[prop]
101 + }
102 + }
103 + }
104 +
105 + var _urlencoded = exports.urlencoded(opts)
106 + var _json = exports.json(opts)
107 +
108 + return function bodyParser (req, res, next) {
109 + _json(req, res, function (err) {
110 + if (err) return next(err)
111 + _urlencoded(req, res, next)
112 + })
113 + }
114 +}
115 +
116 +/**
117 + * Create a getter for loading a parser.
118 + * @private
119 + */
120 +
121 +function createParserGetter (name) {
122 + return function get () {
123 + return loadParser(name)
124 + }
125 +}
126 +
127 +/**
128 + * Load a parser module.
129 + * @private
130 + */
131 +
132 +function loadParser (parserName) {
133 + var parser = parsers[parserName]
134 +
135 + if (parser !== undefined) {
136 + return parser
137 + }
138 +
139 + // this uses a switch for static require analysis
140 + switch (parserName) {
141 + case 'json':
142 + parser = require('./lib/types/json')
143 + break
144 + case 'raw':
145 + parser = require('./lib/types/raw')
146 + break
147 + case 'text':
148 + parser = require('./lib/types/text')
149 + break
150 + case 'urlencoded':
151 + parser = require('./lib/types/urlencoded')
152 + break
153 + }
154 +
155 + // store to prevent invoking require()
156 + return (parsers[parserName] = parser)
157 +}
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
4 + * MIT Licensed
5 + */
6 +
7 +'use strict'
8 +
9 +/**
10 + * Module dependencies.
11 + * @private
12 + */
13 +
14 +var createError = require('http-errors')
15 +var destroy = require('destroy')
16 +var getBody = require('raw-body')
17 +var iconv = require('iconv-lite')
18 +var onFinished = require('on-finished')
19 +var unpipe = require('unpipe')
20 +var zlib = require('zlib')
21 +
22 +/**
23 + * Module exports.
24 + */
25 +
26 +module.exports = read
27 +
28 +/**
29 + * Read a request into a buffer and parse.
30 + *
31 + * @param {object} req
32 + * @param {object} res
33 + * @param {function} next
34 + * @param {function} parse
35 + * @param {function} debug
36 + * @param {object} options
37 + * @private
38 + */
39 +
40 +function read (req, res, next, parse, debug, options) {
41 + var length
42 + var opts = options
43 + var stream
44 +
45 + // flag as parsed
46 + req._body = true
47 +
48 + // read options
49 + var encoding = opts.encoding !== null
50 + ? opts.encoding
51 + : null
52 + var verify = opts.verify
53 +
54 + try {
55 + // get the content stream
56 + stream = contentstream(req, debug, opts.inflate)
57 + length = stream.length
58 + stream.length = undefined
59 + } catch (err) {
60 + return next(err)
61 + }
62 +
63 + // set raw-body options
64 + opts.length = length
65 + opts.encoding = verify
66 + ? null
67 + : encoding
68 +
69 + // assert charset is supported
70 + if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
71 + return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
72 + charset: encoding.toLowerCase(),
73 + type: 'charset.unsupported'
74 + }))
75 + }
76 +
77 + // read body
78 + debug('read body')
79 + getBody(stream, opts, function (error, body) {
80 + if (error) {
81 + var _error
82 +
83 + if (error.type === 'encoding.unsupported') {
84 + // echo back charset
85 + _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
86 + charset: encoding.toLowerCase(),
87 + type: 'charset.unsupported'
88 + })
89 + } else {
90 + // set status code on error
91 + _error = createError(400, error)
92 + }
93 +
94 + // unpipe from stream and destroy
95 + if (stream !== req) {
96 + unpipe(req)
97 + destroy(stream, true)
98 + }
99 +
100 + // read off entire request
101 + dump(req, function onfinished () {
102 + next(createError(400, _error))
103 + })
104 + return
105 + }
106 +
107 + // verify
108 + if (verify) {
109 + try {
110 + debug('verify body')
111 + verify(req, res, body, encoding)
112 + } catch (err) {
113 + next(createError(403, err, {
114 + body: body,
115 + type: err.type || 'entity.verify.failed'
116 + }))
117 + return
118 + }
119 + }
120 +
121 + // parse
122 + var str = body
123 + try {
124 + debug('parse body')
125 + str = typeof body !== 'string' && encoding !== null
126 + ? iconv.decode(body, encoding)
127 + : body
128 + req.body = parse(str)
129 + } catch (err) {
130 + next(createError(400, err, {
131 + body: str,
132 + type: err.type || 'entity.parse.failed'
133 + }))
134 + return
135 + }
136 +
137 + next()
138 + })
139 +}
140 +
141 +/**
142 + * Get the content stream of the request.
143 + *
144 + * @param {object} req
145 + * @param {function} debug
146 + * @param {boolean} [inflate=true]
147 + * @return {object}
148 + * @api private
149 + */
150 +
151 +function contentstream (req, debug, inflate) {
152 + var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
153 + var length = req.headers['content-length']
154 + var stream
155 +
156 + debug('content-encoding "%s"', encoding)
157 +
158 + if (inflate === false && encoding !== 'identity') {
159 + throw createError(415, 'content encoding unsupported', {
160 + encoding: encoding,
161 + type: 'encoding.unsupported'
162 + })
163 + }
164 +
165 + switch (encoding) {
166 + case 'deflate':
167 + stream = zlib.createInflate()
168 + debug('inflate body')
169 + req.pipe(stream)
170 + break
171 + case 'gzip':
172 + stream = zlib.createGunzip()
173 + debug('gunzip body')
174 + req.pipe(stream)
175 + break
176 + case 'identity':
177 + stream = req
178 + stream.length = length
179 + break
180 + default:
181 + throw createError(415, 'unsupported content encoding "' + encoding + '"', {
182 + encoding: encoding,
183 + type: 'encoding.unsupported'
184 + })
185 + }
186 +
187 + return stream
188 +}
189 +
190 +/**
191 + * Dump the contents of a request.
192 + *
193 + * @param {object} req
194 + * @param {function} callback
195 + * @api private
196 + */
197 +
198 +function dump (req, callback) {
199 + if (onFinished.isFinished(req)) {
200 + callback(null)
201 + } else {
202 + onFinished(req, callback)
203 + req.resume()
204 + }
205 +}
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014 Jonathan Ong
4 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
5 + * MIT Licensed
6 + */
7 +
8 +'use strict'
9 +
10 +/**
11 + * Module dependencies.
12 + * @private
13 + */
14 +
15 +var bytes = require('bytes')
16 +var contentType = require('content-type')
17 +var createError = require('http-errors')
18 +var debug = require('debug')('body-parser:json')
19 +var read = require('../read')
20 +var typeis = require('type-is')
21 +
22 +/**
23 + * Module exports.
24 + */
25 +
26 +module.exports = json
27 +
28 +/**
29 + * RegExp to match the first non-space in a string.
30 + *
31 + * Allowed whitespace is defined in RFC 7159:
32 + *
33 + * ws = *(
34 + * %x20 / ; Space
35 + * %x09 / ; Horizontal tab
36 + * %x0A / ; Line feed or New line
37 + * %x0D ) ; Carriage return
38 + */
39 +
40 +var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*([^\x20\x09\x0a\x0d])/ // eslint-disable-line no-control-regex
41 +
42 +/**
43 + * Create a middleware to parse JSON bodies.
44 + *
45 + * @param {object} [options]
46 + * @return {function}
47 + * @public
48 + */
49 +
50 +function json (options) {
51 + var opts = options || {}
52 +
53 + var limit = typeof opts.limit !== 'number'
54 + ? bytes.parse(opts.limit || '100kb')
55 + : opts.limit
56 + var inflate = opts.inflate !== false
57 + var reviver = opts.reviver
58 + var strict = opts.strict !== false
59 + var type = opts.type || 'application/json'
60 + var verify = opts.verify || false
61 +
62 + if (verify !== false && typeof verify !== 'function') {
63 + throw new TypeError('option verify must be function')
64 + }
65 +
66 + // create the appropriate type checking function
67 + var shouldParse = typeof type !== 'function'
68 + ? typeChecker(type)
69 + : type
70 +
71 + function parse (body) {
72 + if (body.length === 0) {
73 + // special-case empty json body, as it's a common client-side mistake
74 + // TODO: maybe make this configurable or part of "strict" option
75 + return {}
76 + }
77 +
78 + if (strict) {
79 + var first = firstchar(body)
80 +
81 + if (first !== '{' && first !== '[') {
82 + debug('strict violation')
83 + throw createStrictSyntaxError(body, first)
84 + }
85 + }
86 +
87 + try {
88 + debug('parse json')
89 + return JSON.parse(body, reviver)
90 + } catch (e) {
91 + throw normalizeJsonSyntaxError(e, {
92 + message: e.message,
93 + stack: e.stack
94 + })
95 + }
96 + }
97 +
98 + return function jsonParser (req, res, next) {
99 + if (req._body) {
100 + debug('body already parsed')
101 + next()
102 + return
103 + }
104 +
105 + req.body = req.body || {}
106 +
107 + // skip requests without bodies
108 + if (!typeis.hasBody(req)) {
109 + debug('skip empty body')
110 + next()
111 + return
112 + }
113 +
114 + debug('content-type %j', req.headers['content-type'])
115 +
116 + // determine if request should be parsed
117 + if (!shouldParse(req)) {
118 + debug('skip parsing')
119 + next()
120 + return
121 + }
122 +
123 + // assert charset per RFC 7159 sec 8.1
124 + var charset = getCharset(req) || 'utf-8'
125 + if (charset.slice(0, 4) !== 'utf-') {
126 + debug('invalid charset')
127 + next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
128 + charset: charset,
129 + type: 'charset.unsupported'
130 + }))
131 + return
132 + }
133 +
134 + // read
135 + read(req, res, next, parse, debug, {
136 + encoding: charset,
137 + inflate: inflate,
138 + limit: limit,
139 + verify: verify
140 + })
141 + }
142 +}
143 +
144 +/**
145 + * Create strict violation syntax error matching native error.
146 + *
147 + * @param {string} str
148 + * @param {string} char
149 + * @return {Error}
150 + * @private
151 + */
152 +
153 +function createStrictSyntaxError (str, char) {
154 + var index = str.indexOf(char)
155 + var partial = index !== -1
156 + ? str.substring(0, index) + '#'
157 + : ''
158 +
159 + try {
160 + JSON.parse(partial); /* istanbul ignore next */ throw new SyntaxError('strict violation')
161 + } catch (e) {
162 + return normalizeJsonSyntaxError(e, {
163 + message: e.message.replace('#', char),
164 + stack: e.stack
165 + })
166 + }
167 +}
168 +
169 +/**
170 + * Get the first non-whitespace character in a string.
171 + *
172 + * @param {string} str
173 + * @return {function}
174 + * @private
175 + */
176 +
177 +function firstchar (str) {
178 + var match = FIRST_CHAR_REGEXP.exec(str)
179 +
180 + return match
181 + ? match[1]
182 + : undefined
183 +}
184 +
185 +/**
186 + * Get the charset of a request.
187 + *
188 + * @param {object} req
189 + * @api private
190 + */
191 +
192 +function getCharset (req) {
193 + try {
194 + return (contentType.parse(req).parameters.charset || '').toLowerCase()
195 + } catch (e) {
196 + return undefined
197 + }
198 +}
199 +
200 +/**
201 + * Normalize a SyntaxError for JSON.parse.
202 + *
203 + * @param {SyntaxError} error
204 + * @param {object} obj
205 + * @return {SyntaxError}
206 + */
207 +
208 +function normalizeJsonSyntaxError (error, obj) {
209 + var keys = Object.getOwnPropertyNames(error)
210 +
211 + for (var i = 0; i < keys.length; i++) {
212 + var key = keys[i]
213 + if (key !== 'stack' && key !== 'message') {
214 + delete error[key]
215 + }
216 + }
217 +
218 + // replace stack before message for Node.js 0.10 and below
219 + error.stack = obj.stack.replace(error.message, obj.message)
220 + error.message = obj.message
221 +
222 + return error
223 +}
224 +
225 +/**
226 + * Get the simple type checker.
227 + *
228 + * @param {string} type
229 + * @return {function}
230 + */
231 +
232 +function typeChecker (type) {
233 + return function checkType (req) {
234 + return Boolean(typeis(req, type))
235 + }
236 +}
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
4 + * MIT Licensed
5 + */
6 +
7 +'use strict'
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var bytes = require('bytes')
14 +var debug = require('debug')('body-parser:raw')
15 +var read = require('../read')
16 +var typeis = require('type-is')
17 +
18 +/**
19 + * Module exports.
20 + */
21 +
22 +module.exports = raw
23 +
24 +/**
25 + * Create a middleware to parse raw bodies.
26 + *
27 + * @param {object} [options]
28 + * @return {function}
29 + * @api public
30 + */
31 +
32 +function raw (options) {
33 + var opts = options || {}
34 +
35 + var inflate = opts.inflate !== false
36 + var limit = typeof opts.limit !== 'number'
37 + ? bytes.parse(opts.limit || '100kb')
38 + : opts.limit
39 + var type = opts.type || 'application/octet-stream'
40 + var verify = opts.verify || false
41 +
42 + if (verify !== false && typeof verify !== 'function') {
43 + throw new TypeError('option verify must be function')
44 + }
45 +
46 + // create the appropriate type checking function
47 + var shouldParse = typeof type !== 'function'
48 + ? typeChecker(type)
49 + : type
50 +
51 + function parse (buf) {
52 + return buf
53 + }
54 +
55 + return function rawParser (req, res, next) {
56 + if (req._body) {
57 + debug('body already parsed')
58 + next()
59 + return
60 + }
61 +
62 + req.body = req.body || {}
63 +
64 + // skip requests without bodies
65 + if (!typeis.hasBody(req)) {
66 + debug('skip empty body')
67 + next()
68 + return
69 + }
70 +
71 + debug('content-type %j', req.headers['content-type'])
72 +
73 + // determine if request should be parsed
74 + if (!shouldParse(req)) {
75 + debug('skip parsing')
76 + next()
77 + return
78 + }
79 +
80 + // read
81 + read(req, res, next, parse, debug, {
82 + encoding: null,
83 + inflate: inflate,
84 + limit: limit,
85 + verify: verify
86 + })
87 + }
88 +}
89 +
90 +/**
91 + * Get the simple type checker.
92 + *
93 + * @param {string} type
94 + * @return {function}
95 + */
96 +
97 +function typeChecker (type) {
98 + return function checkType (req) {
99 + return Boolean(typeis(req, type))
100 + }
101 +}
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
4 + * MIT Licensed
5 + */
6 +
7 +'use strict'
8 +
9 +/**
10 + * Module dependencies.
11 + */
12 +
13 +var bytes = require('bytes')
14 +var contentType = require('content-type')
15 +var debug = require('debug')('body-parser:text')
16 +var read = require('../read')
17 +var typeis = require('type-is')
18 +
19 +/**
20 + * Module exports.
21 + */
22 +
23 +module.exports = text
24 +
25 +/**
26 + * Create a middleware to parse text bodies.
27 + *
28 + * @param {object} [options]
29 + * @return {function}
30 + * @api public
31 + */
32 +
33 +function text (options) {
34 + var opts = options || {}
35 +
36 + var defaultCharset = opts.defaultCharset || 'utf-8'
37 + var inflate = opts.inflate !== false
38 + var limit = typeof opts.limit !== 'number'
39 + ? bytes.parse(opts.limit || '100kb')
40 + : opts.limit
41 + var type = opts.type || 'text/plain'
42 + var verify = opts.verify || false
43 +
44 + if (verify !== false && typeof verify !== 'function') {
45 + throw new TypeError('option verify must be function')
46 + }
47 +
48 + // create the appropriate type checking function
49 + var shouldParse = typeof type !== 'function'
50 + ? typeChecker(type)
51 + : type
52 +
53 + function parse (buf) {
54 + return buf
55 + }
56 +
57 + return function textParser (req, res, next) {
58 + if (req._body) {
59 + debug('body already parsed')
60 + next()
61 + return
62 + }
63 +
64 + req.body = req.body || {}
65 +
66 + // skip requests without bodies
67 + if (!typeis.hasBody(req)) {
68 + debug('skip empty body')
69 + next()
70 + return
71 + }
72 +
73 + debug('content-type %j', req.headers['content-type'])
74 +
75 + // determine if request should be parsed
76 + if (!shouldParse(req)) {
77 + debug('skip parsing')
78 + next()
79 + return
80 + }
81 +
82 + // get charset
83 + var charset = getCharset(req) || defaultCharset
84 +
85 + // read
86 + read(req, res, next, parse, debug, {
87 + encoding: charset,
88 + inflate: inflate,
89 + limit: limit,
90 + verify: verify
91 + })
92 + }
93 +}
94 +
95 +/**
96 + * Get the charset of a request.
97 + *
98 + * @param {object} req
99 + * @api private
100 + */
101 +
102 +function getCharset (req) {
103 + try {
104 + return (contentType.parse(req).parameters.charset || '').toLowerCase()
105 + } catch (e) {
106 + return undefined
107 + }
108 +}
109 +
110 +/**
111 + * Get the simple type checker.
112 + *
113 + * @param {string} type
114 + * @return {function}
115 + */
116 +
117 +function typeChecker (type) {
118 + return function checkType (req) {
119 + return Boolean(typeis(req, type))
120 + }
121 +}
1 +/*!
2 + * body-parser
3 + * Copyright(c) 2014 Jonathan Ong
4 + * Copyright(c) 2014-2015 Douglas Christopher Wilson
5 + * MIT Licensed
6 + */
7 +
8 +'use strict'
9 +
10 +/**
11 + * Module dependencies.
12 + * @private
13 + */
14 +
15 +var bytes = require('bytes')
16 +var contentType = require('content-type')
17 +var createError = require('http-errors')
18 +var debug = require('debug')('body-parser:urlencoded')
19 +var deprecate = require('depd')('body-parser')
20 +var read = require('../read')
21 +var typeis = require('type-is')
22 +
23 +/**
24 + * Module exports.
25 + */
26 +
27 +module.exports = urlencoded
28 +
29 +/**
30 + * Cache of parser modules.
31 + */
32 +
33 +var parsers = Object.create(null)
34 +
35 +/**
36 + * Create a middleware to parse urlencoded bodies.
37 + *
38 + * @param {object} [options]
39 + * @return {function}
40 + * @public
41 + */
42 +
43 +function urlencoded (options) {
44 + var opts = options || {}
45 +
46 + // notice because option default will flip in next major
47 + if (opts.extended === undefined) {
48 + deprecate('undefined extended: provide extended option')
49 + }
50 +
51 + var extended = opts.extended !== false
52 + var inflate = opts.inflate !== false
53 + var limit = typeof opts.limit !== 'number'
54 + ? bytes.parse(opts.limit || '100kb')
55 + : opts.limit
56 + var type = opts.type || 'application/x-www-form-urlencoded'
57 + var verify = opts.verify || false
58 +
59 + if (verify !== false && typeof verify !== 'function') {
60 + throw new TypeError('option verify must be function')
61 + }
62 +
63 + // create the appropriate query parser
64 + var queryparse = extended
65 + ? extendedparser(opts)
66 + : simpleparser(opts)
67 +
68 + // create the appropriate type checking function
69 + var shouldParse = typeof type !== 'function'
70 + ? typeChecker(type)
71 + : type
72 +
73 + function parse (body) {
74 + return body.length
75 + ? queryparse(body)
76 + : {}
77 + }
78 +
79 + return function urlencodedParser (req, res, next) {
80 + if (req._body) {
81 + debug('body already parsed')
82 + next()
83 + return
84 + }
85 +
86 + req.body = req.body || {}
87 +
88 + // skip requests without bodies
89 + if (!typeis.hasBody(req)) {
90 + debug('skip empty body')
91 + next()
92 + return
93 + }
94 +
95 + debug('content-type %j', req.headers['content-type'])
96 +
97 + // determine if request should be parsed
98 + if (!shouldParse(req)) {
99 + debug('skip parsing')
100 + next()
101 + return
102 + }
103 +
104 + // assert charset
105 + var charset = getCharset(req) || 'utf-8'
106 + if (charset !== 'utf-8') {
107 + debug('invalid charset')
108 + next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
109 + charset: charset,
110 + type: 'charset.unsupported'
111 + }))
112 + return
113 + }
114 +
115 + // read
116 + read(req, res, next, parse, debug, {
117 + debug: debug,
118 + encoding: charset,
119 + inflate: inflate,
120 + limit: limit,
121 + verify: verify
122 + })
123 + }
124 +}
125 +
126 +/**
127 + * Get the extended query parser.
128 + *
129 + * @param {object} options
130 + */
131 +
132 +function extendedparser (options) {
133 + var parameterLimit = options.parameterLimit !== undefined
134 + ? options.parameterLimit
135 + : 1000
136 + var parse = parser('qs')
137 +
138 + if (isNaN(parameterLimit) || parameterLimit < 1) {
139 + throw new TypeError('option parameterLimit must be a positive number')
140 + }
141 +
142 + if (isFinite(parameterLimit)) {
143 + parameterLimit = parameterLimit | 0
144 + }
145 +
146 + return function queryparse (body) {
147 + var paramCount = parameterCount(body, parameterLimit)
148 +
149 + if (paramCount === undefined) {
150 + debug('too many parameters')
151 + throw createError(413, 'too many parameters', {
152 + type: 'parameters.too.many'
153 + })
154 + }
155 +
156 + var arrayLimit = Math.max(100, paramCount)
157 +
158 + debug('parse extended urlencoding')
159 + return parse(body, {
160 + allowPrototypes: true,
161 + arrayLimit: arrayLimit,
162 + depth: Infinity,
163 + parameterLimit: parameterLimit
164 + })
165 + }
166 +}
167 +
168 +/**
169 + * Get the charset of a request.
170 + *
171 + * @param {object} req
172 + * @api private
173 + */
174 +
175 +function getCharset (req) {
176 + try {
177 + return (contentType.parse(req).parameters.charset || '').toLowerCase()
178 + } catch (e) {
179 + return undefined
180 + }
181 +}
182 +
183 +/**
184 + * Count the number of parameters, stopping once limit reached
185 + *
186 + * @param {string} body
187 + * @param {number} limit
188 + * @api private
189 + */
190 +
191 +function parameterCount (body, limit) {
192 + var count = 0
193 + var index = 0
194 +
195 + while ((index = body.indexOf('&', index)) !== -1) {
196 + count++
197 + index++
198 +
199 + if (count === limit) {
200 + return undefined
201 + }
202 + }
203 +
204 + return count
205 +}
206 +
207 +/**
208 + * Get parser for module name dynamically.
209 + *
210 + * @param {string} name
211 + * @return {function}
212 + * @api private
213 + */
214 +
215 +function parser (name) {
216 + var mod = parsers[name]
217 +
218 + if (mod !== undefined) {
219 + return mod.parse
220 + }
221 +
222 + // this uses a switch for static require analysis
223 + switch (name) {
224 + case 'qs':
225 + mod = require('qs')
226 + break
227 + case 'querystring':
228 + mod = require('querystring')
229 + break
230 + }
231 +
232 + // store to prevent invoking require()
233 + parsers[name] = mod
234 +
235 + return mod.parse
236 +}
237 +
238 +/**
239 + * Get the simple query parser.
240 + *
241 + * @param {object} options
242 + */
243 +
244 +function simpleparser (options) {
245 + var parameterLimit = options.parameterLimit !== undefined
246 + ? options.parameterLimit
247 + : 1000
248 + var parse = parser('querystring')
249 +
250 + if (isNaN(parameterLimit) || parameterLimit < 1) {
251 + throw new TypeError('option parameterLimit must be a positive number')
252 + }
253 +
254 + if (isFinite(parameterLimit)) {
255 + parameterLimit = parameterLimit | 0
256 + }
257 +
258 + return function queryparse (body) {
259 + var paramCount = parameterCount(body, parameterLimit)
260 +
261 + if (paramCount === undefined) {
262 + debug('too many parameters')
263 + throw createError(413, 'too many parameters', {
264 + type: 'parameters.too.many'
265 + })
266 + }
267 +
268 + debug('parse urlencoding')
269 + return parse(body, undefined, undefined, { maxKeys: parameterLimit })
270 + }
271 +}
272 +
273 +/**
274 + * Get the simple type checker.
275 + *
276 + * @param {string} type
277 + * @return {function}
278 + */
279 +
280 +function typeChecker (type) {
281 + return function checkType (req) {
282 + return Boolean(typeis(req, type))
283 + }
284 +}
1 +root = true
2 +
3 +[*]
4 +indent_style = space
5 +indent_size = 4
6 +end_of_line = lf
7 +charset = utf-8
8 +trim_trailing_whitespace = true
9 +insert_final_newline = true
10 +max_line_length = 160
11 +quote_type = single
12 +
13 +[test/*]
14 +max_line_length = off
15 +
16 +[LICENSE.md]
17 +indent_size = off
18 +
19 +[*.md]
20 +max_line_length = off
21 +
22 +[*.json]
23 +max_line_length = off
24 +
25 +[Makefile]
26 +max_line_length = off
27 +
28 +[CHANGELOG.md]
29 +indent_style = space
30 +indent_size = 2
31 +
32 +[LICENSE]
33 +indent_size = 2
34 +max_line_length = off
35 +
36 +[coverage/**/*]
37 +indent_size = off
38 +indent_style = off
39 +indent = off
40 +max_line_length = off
1 +{
2 + "root": true,
3 +
4 + "extends": "@ljharb",
5 +
6 + "ignorePatterns": [
7 + "dist/",
8 + ],
9 +
10 + "rules": {
11 + "complexity": 0,
12 + "consistent-return": 1,
13 + "func-name-matching": 0,
14 + "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
15 + "indent": [2, 4],
16 + "max-lines-per-function": [2, { "max": 150 }],
17 + "max-params": [2, 15],
18 + "max-statements": [2, 52],
19 + "multiline-comment-style": 0,
20 + "no-continue": 1,
21 + "no-magic-numbers": 0,
22 + "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
23 + },
24 +
25 + "overrides": [
26 + {
27 + "files": "test/**",
28 + "rules": {
29 + "function-paren-newline": 0,
30 + "max-lines-per-function": 0,
31 + "max-statements": 0,
32 + "no-buffer-constructor": 0,
33 + "no-extend-native": 0,
34 + "no-throw-literal": 0,
35 + }
36 + }
37 + ]
38 +}
1 +# These are supported funding model platforms
2 +
3 +github: [ljharb]
4 +patreon: # Replace with a single Patreon username
5 +open_collective: # Replace with a single Open Collective username
6 +ko_fi: # Replace with a single Ko-fi username
7 +tidelift: npm/qs
8 +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 +liberapay: # Replace with a single Liberapay username
10 +issuehunt: # Replace with a single IssueHunt username
11 +otechie: # Replace with a single Otechie username
12 +custom: # Replace with a single custom sponsorship URL
1 +{
2 + "all": true,
3 + "check-coverage": false,
4 + "reporter": ["text-summary", "text", "html", "json"],
5 + "lines": 86,
6 + "statements": 85.93,
7 + "functions": 82.43,
8 + "branches": 76.06,
9 + "exclude": [
10 + "coverage",
11 + "dist"
12 + ]
13 +}
This diff is collapsed. Click to expand it.
1 +BSD 3-Clause License
2 +
3 +Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors)
4 +All rights reserved.
5 +
6 +Redistribution and use in source and binary forms, with or without
7 +modification, are permitted provided that the following conditions are met:
8 +
9 +1. Redistributions of source code must retain the above copyright notice, this
10 + list of conditions and the following disclaimer.
11 +
12 +2. Redistributions in binary form must reproduce the above copyright notice,
13 + this list of conditions and the following disclaimer in the documentation
14 + and/or other materials provided with the distribution.
15 +
16 +3. Neither the name of the copyright holder nor the names of its
17 + contributors may be used to endorse or promote products derived from
18 + this software without specific prior written permission.
19 +
20 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 +'use strict';
2 +
3 +var replace = String.prototype.replace;
4 +var percentTwenties = /%20/g;
5 +
6 +var Format = {
7 + RFC1738: 'RFC1738',
8 + RFC3986: 'RFC3986'
9 +};
10 +
11 +module.exports = {
12 + 'default': Format.RFC3986,
13 + formatters: {
14 + RFC1738: function (value) {
15 + return replace.call(value, percentTwenties, '+');
16 + },
17 + RFC3986: function (value) {
18 + return String(value);
19 + }
20 + },
21 + RFC1738: Format.RFC1738,
22 + RFC3986: Format.RFC3986
23 +};
1 +'use strict';
2 +
3 +var stringify = require('./stringify');
4 +var parse = require('./parse');
5 +var formats = require('./formats');
6 +
7 +module.exports = {
8 + formats: formats,
9 + parse: parse,
10 + stringify: stringify
11 +};
1 +'use strict';
2 +
3 +var utils = require('./utils');
4 +
5 +var has = Object.prototype.hasOwnProperty;
6 +var isArray = Array.isArray;
7 +
8 +var defaults = {
9 + allowDots: false,
10 + allowPrototypes: false,
11 + allowSparse: false,
12 + arrayLimit: 20,
13 + charset: 'utf-8',
14 + charsetSentinel: false,
15 + comma: false,
16 + decoder: utils.decode,
17 + delimiter: '&',
18 + depth: 5,
19 + ignoreQueryPrefix: false,
20 + interpretNumericEntities: false,
21 + parameterLimit: 1000,
22 + parseArrays: true,
23 + plainObjects: false,
24 + strictNullHandling: false
25 +};
26 +
27 +var interpretNumericEntities = function (str) {
28 + return str.replace(/&#(\d+);/g, function ($0, numberStr) {
29 + return String.fromCharCode(parseInt(numberStr, 10));
30 + });
31 +};
32 +
33 +var parseArrayValue = function (val, options) {
34 + if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
35 + return val.split(',');
36 + }
37 +
38 + return val;
39 +};
40 +
41 +// This is what browsers will submit when the ✓ character occurs in an
42 +// application/x-www-form-urlencoded body and the encoding of the page containing
43 +// the form is iso-8859-1, or when the submitted form has an accept-charset
44 +// attribute of iso-8859-1. Presumably also with other charsets that do not contain
45 +// the ✓ character, such as us-ascii.
46 +var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('&#10003;')
47 +
48 +// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
49 +var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
50 +
51 +var parseValues = function parseQueryStringValues(str, options) {
52 + var obj = {};
53 + var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
54 + var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
55 + var parts = cleanStr.split(options.delimiter, limit);
56 + var skipIndex = -1; // Keep track of where the utf8 sentinel was found
57 + var i;
58 +
59 + var charset = options.charset;
60 + if (options.charsetSentinel) {
61 + for (i = 0; i < parts.length; ++i) {
62 + if (parts[i].indexOf('utf8=') === 0) {
63 + if (parts[i] === charsetSentinel) {
64 + charset = 'utf-8';
65 + } else if (parts[i] === isoSentinel) {
66 + charset = 'iso-8859-1';
67 + }
68 + skipIndex = i;
69 + i = parts.length; // The eslint settings do not allow break;
70 + }
71 + }
72 + }
73 +
74 + for (i = 0; i < parts.length; ++i) {
75 + if (i === skipIndex) {
76 + continue;
77 + }
78 + var part = parts[i];
79 +
80 + var bracketEqualsPos = part.indexOf(']=');
81 + var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
82 +
83 + var key, val;
84 + if (pos === -1) {
85 + key = options.decoder(part, defaults.decoder, charset, 'key');
86 + val = options.strictNullHandling ? null : '';
87 + } else {
88 + key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
89 + val = utils.maybeMap(
90 + parseArrayValue(part.slice(pos + 1), options),
91 + function (encodedVal) {
92 + return options.decoder(encodedVal, defaults.decoder, charset, 'value');
93 + }
94 + );
95 + }
96 +
97 + if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
98 + val = interpretNumericEntities(val);
99 + }
100 +
101 + if (part.indexOf('[]=') > -1) {
102 + val = isArray(val) ? [val] : val;
103 + }
104 +
105 + if (has.call(obj, key)) {
106 + obj[key] = utils.combine(obj[key], val);
107 + } else {
108 + obj[key] = val;
109 + }
110 + }
111 +
112 + return obj;
113 +};
114 +
115 +var parseObject = function (chain, val, options, valuesParsed) {
116 + var leaf = valuesParsed ? val : parseArrayValue(val, options);
117 +
118 + for (var i = chain.length - 1; i >= 0; --i) {
119 + var obj;
120 + var root = chain[i];
121 +
122 + if (root === '[]' && options.parseArrays) {
123 + obj = [].concat(leaf);
124 + } else {
125 + obj = options.plainObjects ? Object.create(null) : {};
126 + var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
127 + var index = parseInt(cleanRoot, 10);
128 + if (!options.parseArrays && cleanRoot === '') {
129 + obj = { 0: leaf };
130 + } else if (
131 + !isNaN(index)
132 + && root !== cleanRoot
133 + && String(index) === cleanRoot
134 + && index >= 0
135 + && (options.parseArrays && index <= options.arrayLimit)
136 + ) {
137 + obj = [];
138 + obj[index] = leaf;
139 + } else if (cleanRoot !== '__proto__') {
140 + obj[cleanRoot] = leaf;
141 + }
142 + }
143 +
144 + leaf = obj;
145 + }
146 +
147 + return leaf;
148 +};
149 +
150 +var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
151 + if (!givenKey) {
152 + return;
153 + }
154 +
155 + // Transform dot notation to bracket notation
156 + var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey;
157 +
158 + // The regex chunks
159 +
160 + var brackets = /(\[[^[\]]*])/;
161 + var child = /(\[[^[\]]*])/g;
162 +
163 + // Get the parent
164 +
165 + var segment = options.depth > 0 && brackets.exec(key);
166 + var parent = segment ? key.slice(0, segment.index) : key;
167 +
168 + // Stash the parent if it exists
169 +
170 + var keys = [];
171 + if (parent) {
172 + // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
173 + if (!options.plainObjects && has.call(Object.prototype, parent)) {
174 + if (!options.allowPrototypes) {
175 + return;
176 + }
177 + }
178 +
179 + keys.push(parent);
180 + }
181 +
182 + // Loop through children appending to the array until we hit depth
183 +
184 + var i = 0;
185 + while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
186 + i += 1;
187 + if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
188 + if (!options.allowPrototypes) {
189 + return;
190 + }
191 + }
192 + keys.push(segment[1]);
193 + }
194 +
195 + // If there's a remainder, just add whatever is left
196 +
197 + if (segment) {
198 + keys.push('[' + key.slice(segment.index) + ']');
199 + }
200 +
201 + return parseObject(keys, val, options, valuesParsed);
202 +};
203 +
204 +var normalizeParseOptions = function normalizeParseOptions(opts) {
205 + if (!opts) {
206 + return defaults;
207 + }
208 +
209 + if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') {
210 + throw new TypeError('Decoder has to be a function.');
211 + }
212 +
213 + if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
214 + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
215 + }
216 + var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
217 +
218 + return {
219 + allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
220 + allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
221 + allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse,
222 + arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
223 + charset: charset,
224 + charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
225 + comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
226 + decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
227 + delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
228 + // eslint-disable-next-line no-implicit-coercion, no-extra-parens
229 + depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
230 + ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
231 + interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
232 + parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
233 + parseArrays: opts.parseArrays !== false,
234 + plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
235 + strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
236 + };
237 +};
238 +
239 +module.exports = function (str, opts) {
240 + var options = normalizeParseOptions(opts);
241 +
242 + if (str === '' || str === null || typeof str === 'undefined') {
243 + return options.plainObjects ? Object.create(null) : {};
244 + }
245 +
246 + var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
247 + var obj = options.plainObjects ? Object.create(null) : {};
248 +
249 + // Iterate over the keys and setup the new object
250 +
251 + var keys = Object.keys(tempObj);
252 + for (var i = 0; i < keys.length; ++i) {
253 + var key = keys[i];
254 + var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
255 + obj = utils.merge(obj, newObj, options);
256 + }
257 +
258 + if (options.allowSparse === true) {
259 + return obj;
260 + }
261 +
262 + return utils.compact(obj);
263 +};
1 +'use strict';
2 +
3 +var getSideChannel = require('side-channel');
4 +var utils = require('./utils');
5 +var formats = require('./formats');
6 +var has = Object.prototype.hasOwnProperty;
7 +
8 +var arrayPrefixGenerators = {
9 + brackets: function brackets(prefix) {
10 + return prefix + '[]';
11 + },
12 + comma: 'comma',
13 + indices: function indices(prefix, key) {
14 + return prefix + '[' + key + ']';
15 + },
16 + repeat: function repeat(prefix) {
17 + return prefix;
18 + }
19 +};
20 +
21 +var isArray = Array.isArray;
22 +var split = String.prototype.split;
23 +var push = Array.prototype.push;
24 +var pushToArray = function (arr, valueOrArray) {
25 + push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
26 +};
27 +
28 +var toISO = Date.prototype.toISOString;
29 +
30 +var defaultFormat = formats['default'];
31 +var defaults = {
32 + addQueryPrefix: false,
33 + allowDots: false,
34 + charset: 'utf-8',
35 + charsetSentinel: false,
36 + delimiter: '&',
37 + encode: true,
38 + encoder: utils.encode,
39 + encodeValuesOnly: false,
40 + format: defaultFormat,
41 + formatter: formats.formatters[defaultFormat],
42 + // deprecated
43 + indices: false,
44 + serializeDate: function serializeDate(date) {
45 + return toISO.call(date);
46 + },
47 + skipNulls: false,
48 + strictNullHandling: false
49 +};
50 +
51 +var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
52 + return typeof v === 'string'
53 + || typeof v === 'number'
54 + || typeof v === 'boolean'
55 + || typeof v === 'symbol'
56 + || typeof v === 'bigint';
57 +};
58 +
59 +var sentinel = {};
60 +
61 +var stringify = function stringify(
62 + object,
63 + prefix,
64 + generateArrayPrefix,
65 + strictNullHandling,
66 + skipNulls,
67 + encoder,
68 + filter,
69 + sort,
70 + allowDots,
71 + serializeDate,
72 + format,
73 + formatter,
74 + encodeValuesOnly,
75 + charset,
76 + sideChannel
77 +) {
78 + var obj = object;
79 +
80 + var tmpSc = sideChannel;
81 + var step = 0;
82 + var findFlag = false;
83 + while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) {
84 + // Where object last appeared in the ref tree
85 + var pos = tmpSc.get(object);
86 + step += 1;
87 + if (typeof pos !== 'undefined') {
88 + if (pos === step) {
89 + throw new RangeError('Cyclic object value');
90 + } else {
91 + findFlag = true; // Break while
92 + }
93 + }
94 + if (typeof tmpSc.get(sentinel) === 'undefined') {
95 + step = 0;
96 + }
97 + }
98 +
99 + if (typeof filter === 'function') {
100 + obj = filter(prefix, obj);
101 + } else if (obj instanceof Date) {
102 + obj = serializeDate(obj);
103 + } else if (generateArrayPrefix === 'comma' && isArray(obj)) {
104 + obj = utils.maybeMap(obj, function (value) {
105 + if (value instanceof Date) {
106 + return serializeDate(value);
107 + }
108 + return value;
109 + });
110 + }
111 +
112 + if (obj === null) {
113 + if (strictNullHandling) {
114 + return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key', format) : prefix;
115 + }
116 +
117 + obj = '';
118 + }
119 +
120 + if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
121 + if (encoder) {
122 + var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
123 + if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
124 + var valuesArray = split.call(String(obj), ',');
125 + var valuesJoined = '';
126 + for (var i = 0; i < valuesArray.length; ++i) {
127 + valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
128 + }
129 + return [formatter(keyValue) + '=' + valuesJoined];
130 + }
131 + return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
132 + }
133 + return [formatter(prefix) + '=' + formatter(String(obj))];
134 + }
135 +
136 + var values = [];
137 +
138 + if (typeof obj === 'undefined') {
139 + return values;
140 + }
141 +
142 + var objKeys;
143 + if (generateArrayPrefix === 'comma' && isArray(obj)) {
144 + // we need to join elements in
145 + objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
146 + } else if (isArray(filter)) {
147 + objKeys = filter;
148 + } else {
149 + var keys = Object.keys(obj);
150 + objKeys = sort ? keys.sort(sort) : keys;
151 + }
152 +
153 + for (var j = 0; j < objKeys.length; ++j) {
154 + var key = objKeys[j];
155 + var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
156 +
157 + if (skipNulls && value === null) {
158 + continue;
159 + }
160 +
161 + var keyPrefix = isArray(obj)
162 + ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
163 + : prefix + (allowDots ? '.' + key : '[' + key + ']');
164 +
165 + sideChannel.set(object, step);
166 + var valueSideChannel = getSideChannel();
167 + valueSideChannel.set(sentinel, sideChannel);
168 + pushToArray(values, stringify(
169 + value,
170 + keyPrefix,
171 + generateArrayPrefix,
172 + strictNullHandling,
173 + skipNulls,
174 + encoder,
175 + filter,
176 + sort,
177 + allowDots,
178 + serializeDate,
179 + format,
180 + formatter,
181 + encodeValuesOnly,
182 + charset,
183 + valueSideChannel
184 + ));
185 + }
186 +
187 + return values;
188 +};
189 +
190 +var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
191 + if (!opts) {
192 + return defaults;
193 + }
194 +
195 + if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
196 + throw new TypeError('Encoder has to be a function.');
197 + }
198 +
199 + var charset = opts.charset || defaults.charset;
200 + if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
201 + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
202 + }
203 +
204 + var format = formats['default'];
205 + if (typeof opts.format !== 'undefined') {
206 + if (!has.call(formats.formatters, opts.format)) {
207 + throw new TypeError('Unknown format option provided.');
208 + }
209 + format = opts.format;
210 + }
211 + var formatter = formats.formatters[format];
212 +
213 + var filter = defaults.filter;
214 + if (typeof opts.filter === 'function' || isArray(opts.filter)) {
215 + filter = opts.filter;
216 + }
217 +
218 + return {
219 + addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
220 + allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
221 + charset: charset,
222 + charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
223 + delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
224 + encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
225 + encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
226 + encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
227 + filter: filter,
228 + format: format,
229 + formatter: formatter,
230 + serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,
231 + skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,
232 + sort: typeof opts.sort === 'function' ? opts.sort : null,
233 + strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
234 + };
235 +};
236 +
237 +module.exports = function (object, opts) {
238 + var obj = object;
239 + var options = normalizeStringifyOptions(opts);
240 +
241 + var objKeys;
242 + var filter;
243 +
244 + if (typeof options.filter === 'function') {
245 + filter = options.filter;
246 + obj = filter('', obj);
247 + } else if (isArray(options.filter)) {
248 + filter = options.filter;
249 + objKeys = filter;
250 + }
251 +
252 + var keys = [];
253 +
254 + if (typeof obj !== 'object' || obj === null) {
255 + return '';
256 + }
257 +
258 + var arrayFormat;
259 + if (opts && opts.arrayFormat in arrayPrefixGenerators) {
260 + arrayFormat = opts.arrayFormat;
261 + } else if (opts && 'indices' in opts) {
262 + arrayFormat = opts.indices ? 'indices' : 'repeat';
263 + } else {
264 + arrayFormat = 'indices';
265 + }
266 +
267 + var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
268 +
269 + if (!objKeys) {
270 + objKeys = Object.keys(obj);
271 + }
272 +
273 + if (options.sort) {
274 + objKeys.sort(options.sort);
275 + }
276 +
277 + var sideChannel = getSideChannel();
278 + for (var i = 0; i < objKeys.length; ++i) {
279 + var key = objKeys[i];
280 +
281 + if (options.skipNulls && obj[key] === null) {
282 + continue;
283 + }
284 + pushToArray(keys, stringify(
285 + obj[key],
286 + key,
287 + generateArrayPrefix,
288 + options.strictNullHandling,
289 + options.skipNulls,
290 + options.encode ? options.encoder : null,
291 + options.filter,
292 + options.sort,
293 + options.allowDots,
294 + options.serializeDate,
295 + options.format,
296 + options.formatter,
297 + options.encodeValuesOnly,
298 + options.charset,
299 + sideChannel
300 + ));
301 + }
302 +
303 + var joined = keys.join(options.delimiter);
304 + var prefix = options.addQueryPrefix === true ? '?' : '';
305 +
306 + if (options.charsetSentinel) {
307 + if (options.charset === 'iso-8859-1') {
308 + // encodeURIComponent('&#10003;'), the "numeric entity" representation of a checkmark
309 + prefix += 'utf8=%26%2310003%3B&';
310 + } else {
311 + // encodeURIComponent('✓')
312 + prefix += 'utf8=%E2%9C%93&';
313 + }
314 + }
315 +
316 + return joined.length > 0 ? prefix + joined : '';
317 +};
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.